Whali3n51's blog

  • 主页
  • 关于
  • 友链
  • 标签
  • 分类
pwn学习

Unsorted bin attack

Whali3n51 发布于 2019-06-02

首先用一个C语言的例子来说明Unsorted bin attack
这是一个CTFwiki的一个例子,我觉得讲解的很好,我就照搬过来了。

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
#include <stdio.h>
#include <stdlib.h>

int main() {
fprintf(stderr, "This file demonstrates unsorted bin attack by write a large "
"unsigned long value into stack\n");
fprintf(
stderr,
"In practice, unsorted bin attack is generally prepared for further "
"attacks, such as rewriting the "
"global variable global_max_fast in libc for further fastbin attack\n\n");

unsigned long target_var = 0;
fprintf(stderr,
"Let's first look at the target we want to rewrite on stack:\n");
fprintf(stderr, "%p: %ld\n\n", &target_var, target_var);

unsigned long *p = malloc(400);
fprintf(stderr, "Now, we allocate first normal chunk on the heap at: %p\n",
p);
fprintf(stderr, "And allocate another normal chunk in order to avoid "
"consolidating the top chunk with"
"the first one during the free()\n\n");
malloc(500);

free(p);
fprintf(stderr, "We free the first chunk now and it will be inserted in the "
"unsorted bin with its bk pointer "
"point to %p\n",
(void *)p[1]);

/*------------VULNERABILITY-----------*/

p[1] = (unsigned long)(&target_var - 2);
fprintf(stderr, "Now emulating a vulnerability that can overwrite the "
"victim->bk pointer\n");
fprintf(stderr, "And we write it with the target address-16 (in 32-bits "
"machine, it should be target address-8):%p\n\n",
(void *)p[1]);

//------------------------------------

malloc(400);
fprintf(stderr, "Let's malloc again to get the chunk we just free. During "
"this time, target should has already been "
"rewrite:\n");
fprintf(stderr, "%p: %p\n", &target_var, (void *)target_var);
}


上面的图片是用来解释代码的内容的。

代码的意思大致解释一下:
首先分配一个不属于fast bin范围大小的chunk。使一个指针指向这个地方。然后释放掉这个地方,但是不对该指针清空。
然后利用该指针控制刚释放chunk的bk。使得这个指针指向target_addr-0x10。也就是将这个指针指向我们伪装的chunk。我们target_addr刚好在伪装chunk的fd指针的这个地方。
然后再分配内存
这个时候的target_addr的值就被我们更改掉了,但是这个值不受我们控制,这个值为unsorted bin链表的链表头。
为什么这样就能更改掉我们的fd的值呢。
让我们看一看unsorted bin 分配内存的原理。
在分配内存的时候,将chunk从unsorted bin 移除的时候,会执行如下代码。

1
2
3
4
5
/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

这段代码就是我们控制了bk的值,我们就将unsorted_chunks的值放入任何地方。

在开篇的代码中,我们控制了刚刚释放chunk的bk值,让bk指向target_addr-0x10,,unsorted_chunk的值也就是放入了target_addr这个地方,因为改值是放入bk指向的fd指针所在的地方的。

这样也就解释了unsorted bin attack。这个漏洞的局限性很大,但是一般不单独使用这个漏洞,一般和fast bin attack连用。unsorted bin attack 可以改变 global_max_fast 来使得更大的chunk作为进入fast bin。

很简单的一个洞,所以没什么好讲的。
关于实例讲解,等我找到一个例子就可以了。
接下来用一个也是在CTFwiki里面找到的一个例子,我觉得这个例子很好的讲解了unsorted bin attack的实例应用

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
#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;
}

关于程序的源码,可以直接拷贝,然后到自己的linux系统中编译运行就可。
这一题就直接分析源码好了。
我们发现,这一题要读取flag,就必须让magic的值大于4869,但是这一题的magic的值全局变量定义的为0。所以我们需要改变这个值。但是这个程序没有其他的地方能修改这个值。
知道了大致方向,我们就开始分析程序。
首先是create_heap这个函数就是用来创建堆块的。而且程序的堆的大小自己决定,输入的值自己决定,但是会控制输入的长度,没有溢出点。
然后就是edit_heap这个函数,这个函数是在已有的堆块上面进行输入,而且长度自己决定,所以当自己输入的长度大于已有堆块的大小的时候,存在堆溢出。
再次就是delete_heap这个函数,就是free掉指针,然后再将指针清理,所以不存在UAF漏洞。

  • #Usnsorted bin attack
Newer

堆溢出的unlink漏洞利用

Older

强网杯:强网先锋_AP_Pwn writeup

© 2023 Whali3n51