HTB Auth-or-not:一个自实现堆管理的pwn练习
字数 1410 2025-08-29 08:30:24
HTB Auth-or-not PWN题解:自定义堆管理漏洞分析与利用
题目概述
这是一个来自Hack The Box的PWN挑战,名为"Auth-or-not",主要考察对自定义堆管理器的漏洞分析和利用能力。题目实现了一个自定义的内存管理机制,通过分析其内存布局和操作逻辑,我们可以发现并利用其中的漏洞。
逆向分析
主要结构体
题目保留了符号信息,关键结构体定义如下:
struct Author {
char Name[16];
char Surname[16];
char *Note; // 通过ta_alloc分配
size_t NoteSize; // 用户可控
void (*Print)(char*); // 函数指针,可用于RCE
};
功能函数
-
add_author:
- 使用
ta_alloc自定义分配器申请内存 NoteSize完全由用户控制- 当输入
-1时,会返回无符号的-1,实际上分配0字节内存但仍可写入数据,导致堆溢出
- 使用
-
get_from_user:
- 读取用户输入时没有NULL终止符
- 结合
%s打印操作可泄露后续内存内容
-
print_author:
- 通过结构体调用
Print函数指针 - 关键利用点,可用于RCE
- 通过结构体调用
-
delete_author:
- 只清空结构体指针,不清理
Note指针 - 存在UAF(Use After Free)隐患
- 只清空结构体指针,不清理
漏洞分析
主要漏洞点
-
整数溢出导致堆溢出:
- 当
NoteSize输入为-1时,NoteSize+1变为0 - 但仍能写入数据,造成堆溢出
- 当
-
信息泄露:
get_from_user不添加NULL终止符- 通过精心构造可泄露栈地址、PIE地址和libc地址
-
UAF问题:
delete_author不清理Note指针- 结合堆布局可实现内存重用
堆布局观察
申请两个author后的栈上模拟堆布局:
第一次申请:
- 大小: -1 (实际0)
- 地址: 0x7fff30589f18 (可控)
- 内容被第二次申请覆盖
这种布局意味着:
- 释放第一次申请
- 重新申请并覆盖第二次申请的部分内容
- 通过精心构造可泄露地址信息
利用策略
利用步骤
-
泄露栈和PIE地址:
- 完全覆盖
Name和Surname字段 - 相邻的
Note指针会被Print打印出来 - 调整指针指向可泄露
PrintNote函数地址,计算PIE基址
- 完全覆盖
-
泄露libc地址:
- 题目未提供libc文件
- 需要泄露libc符号地址并通过libc database查询
- 实验确定具体libc版本
-
实现RCE:
- 覆盖
Print函数指针为system Print调用时传入Note指针作为参数- 将
Note内容设置为/bin/sh即可获取shell
- 覆盖
关键技巧
-
堆风水(Heap Feng Shui):
- 通过控制分配和释放顺序操纵内存布局
- 实现内存重用和覆盖
-
地址计算:
- 通过泄露的地址计算关键函数地址
- 包括PIE基址、libc基址等
-
函数指针劫持:
- 利用自定义堆管理器的缺陷覆盖函数指针
- 将控制流导向
system等危险函数
EXP编写要点
辅助函数
-
泄露地址函数:
def leak_address(): # 构造特定布局 # 触发信息泄露 # 解析返回数据获取地址 return address -
计算偏移:
def calculate_offsets(leaked_addr): pie_base = leaked_addr - 0x1234 # 根据实际偏移调整 libc_base = leaked_libc_addr - 0x5678 return pie_base, libc_base
完整利用流程
- 泄露PIE地址
- 泄露libc地址并确定版本
- 计算
system地址 - 构造内存布局覆盖
Print指针 - 设置
Note内容为/bin/sh - 触发
Print调用获取shell
总结
这道题目展示了自定义堆管理器的常见漏洞模式:
- 整数处理不当导致的溢出
- 内存管理不严谨导致的UAF
- 函数指针缺乏保护
通过分析内存布局而非深入堆管理细节,可以更高效地发现和利用漏洞。关键点在于:
- 观察内存实际布局而非陷入实现细节
- 利用信息泄露构建完整的内存图景
- 通过堆操作控制关键数据结构的覆盖
这种思路适用于大多数自定义内存管理的PWN题目。