본문 바로가기

PWN

Bypass CRC check for fuzzing with pintools

tcp, zip, tar, png등 다양한 데이터 형식에서는 crc 체크를 통해서 파일의 무결성을 검증한다. 만약 crc 체크가 실패하면 프로그램이 그냥 종료된다. 퍼저에 의해 무작위로 변이된 데이터가 crc를 맞출 수 있을 확률이 지극히 낮다. 이러한 문제를 해결하기 위해서 2가지 방법을 쓸 수 있다.

  1. Post mutator에 crc 체크를 맞춰주는 코드를 넣어준다.
    1. 장점1 : Crash reproduce가 쉽다.
    2. 장점2 : crc뿐만 아니라, 다른 형식에 대해서도 적용할 수 있기 때문에 더 범용적이다.
    3. 단점1 : 하나의 포맷이 아니라, 다수의 포맷을 처리하는 프로그램의 경우, 프로그램에서 어떠한 방식으로 파일의 포맷을 결정하는지 리버싱해야 한다.
    4. switch(format(data)){//have to reversing format function case ZIP: unzip(data) case TAR: untar(data) case TCP: handle_tcp(data) }
    5. 단점2: 데이터 포맷에 대한 이해가 필요하다.

2. Fuzzing할 바이너리에서 crc 체크 코드를 삭제해준다.

  1. 장점1 : 쉽다.
  2. 장점2 : 자동화를 할 여지가 많다.
  3. 단점1 : 바이너리를 임의로 패치했기 때문에, 실제로는 reproduce되지 않는 크래시일 수 있다.
  4. 단점2 : 다수의 데이터 포맷을 처리하는 경우, 가장 처음 체크하는 포맷 외에는 제대로 검증되지 않을 수 있다.
  5. if is_zip(data): #==> No format error, so always True. unzip(data) elif is_tar(data):#==> unfuzzable untar(data)

소스코드가 있다면, crc코드를 간단하게 삭제할 수 있지만, strip된 바이너리에서는 crc 체크 구문을 찾기 힘들 수 있다. Fuzzing할 바이너리에서 crc 체크 코드를 삭제하기 위해서는 바이너리를 리버싱한 후, 어디에서 crc 체크가 이루어지는지 찾아야 한다. 하지만, 데이터의 crc값이 무엇인지 알고 있다면, pintools를 이용해서 crc 체크가 이루어지는 위치를 자동으로 찾을 수 있다.

아래는 cmptrace.cpp를 약간 수정한 코드이다. 프로그램이 돌아가면서 실행되는 모든 cmp 명령어를 로깅한다.

 

// cmptrace.cpp
//https://github.com/inaz2/pintools/blob/master/cmptrace.cpp
#include <cstdio>
#include "pin.H"
#include <iostream>
#include<fstream>
using namespace std;
std::ostream* out = &std::cerr;
VOID log_f(){
    string fileName = "trace";
    out = new std::ofstream(fileName.c_str());
}

VOID print_cmp_mem(VOID *ip, UINT64 * addr, ADDRINT value) {
    PIN_LockClient();
    IMG img = IMG_FindByAddress((unsigned long )ip);
    unsigned long base = IMG_LowAddress(img);
    string name = IMG_Name(img);
    *out <<name << " + 0x"<<hex<< (unsigned long )ip -base << " : cmp 0x" <<*addr<<" , 0x"<<value<< endl ;
    PIN_UnlockClient();
}

VOID print_cmp_reg(VOID *ip, ADDRINT lvalue, ADDRINT rvalue) {
    PIN_LockClient();
    IMG img = IMG_FindByAddress((unsigned long )ip);
    if(!IMG_Valid(img)){
        return;
    }
    unsigned long base = IMG_LowAddress(img);
    string name = IMG_Name(img);
    
    *out <<name << " + 0x"<<hex<< (unsigned long )ip -base << " : cmp 0x" <<lvalue<<" , 0x"<<rvalue<< endl ;
    PIN_UnlockClient();
}

VOID Instruction(INS ins, VOID *v)
{
    if (INS_Opcode(ins) == XED_ICLASS_CMP) {
        if (INS_MemoryOperandCount(ins) == 1) {
            if (INS_OperandIsImmediate(ins, 1)) {
                INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)print_cmp_mem, IARG_INST_PTR, IARG_MEMORYOP_EA, 0, IARG_ADDRINT, INS_OperandImmediate(ins, 1), IARG_END);
            } else if (INS_OperandIsReg(ins, 0)) {
                INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)print_cmp_mem, IARG_INST_PTR, IARG_MEMORYOP_EA, 0, IARG_REG_VALUE, INS_OperandReg(ins, 0), IARG_END);
            } else {
                INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)print_cmp_mem, IARG_INST_PTR, IARG_MEMORYOP_EA, 0, IARG_REG_VALUE, INS_OperandReg(ins, 1), IARG_END);
            }
        } else {
            if (INS_OperandIsImmediate(ins, 1)) {
                INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)print_cmp_reg, IARG_INST_PTR, IARG_REG_VALUE, INS_OperandReg(ins, 0), IARG_ADDRINT, INS_OperandImmediate(ins, 1), IARG_END);
            } else {
                INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)print_cmp_reg, IARG_INST_PTR, IARG_REG_VALUE, INS_OperandReg(ins, 0), IARG_REG_VALUE, INS_OperandReg(ins, 1), IARG_END);
            }
        }
    }
}

int main(int argc, char *argv[])
{
    log_f();
    PIN_Init(argc, argv);
    INS_AddInstrumentFunction(Instruction, 0);
    PIN_StartProgram();
    return 0;
}

 

 

pintools로 모든 cmp 명령어를 덤프하고, 그중에서 crc 값이 사용되는 주소를 찾은 후 패치하면 된다.

 

➜  cmp git:(main) ✗ ../../../pin -t ./obj-intel64/cmp.so -- ./target지워짐 passwd.gz 
➜  cmp git:(main) ✗ gzip -lv passwd.gz
method  crc     date  time           compressed        uncompressed  ratio uncompressed_name
defla 29a74433 Nov 19 15:52                1035                2801  63.9% passwd
➜  cmp git:(main) ✗ cat ./trace|grep 29a74433
/home/jjy/inturn/pin/source/tools/cmp/target__지워짐.so : cmp 0x29a74433 , 0x29a74433
/home/jjy/inturn/pin/source/tools/cmp/target__지워짐.so : cmp 0x29a74433 , 0x29a74433

 

참조

https://github.com/CAFA1/CAFA

https://github.com/inaz2/pintools/blob/master/cmptrace.cpp

 

'PWN' 카테고리의 다른 글

AFLPlusplus qemu, Persistence mode 속도 느려질 때  (0) 2022.01.04
AFLPlusplus - qemu mode - High map density  (0) 2021.10.22
Linux 버그 보는 곳  (1) 2021.06.06
Ida python for bug hunting  (0) 2021.03.11
Assaultcube Fuzzing  (0) 2021.02.04