TAMUctf 19 Obfuscaxor

CTF/Writeup 2019. 3. 22. 15:55

바이너리를 보면 간단한 키젠미 문제인데, 문제 이름에서도 느껴지듯이 바이너리가 난독화 되어있다. 


플래그가 출력되려면 verify_key 함수의 리턴 값이 1이어야 되는데 헥스레이로 코드를 보면 무조건 0이 리턴되길래 인풋이 들어가는 enc함수에서 동적으로 코드영역을 패치해 리턴값을 세팅하는 부분이 있는 건가 하고 해당 함수를 보니 코드가 요상하게 난독화 되어 있었다.


__int64 __fastcall verify_key(char *a1)

{

  if ( strlen(a1) > 9 && strlen(a1) <= 0x40 )

    enc(a1);

  return 0LL;

}



void __fastcall __noreturn enc(const char *a1)

{

  __int64 v1; // rdx

  __int64 v2; // rcx

  __int64 v3; // r8

  obf::for_wrapper *v4; // rax

  __int64 v5; // rbx

  __int64 v6; // rbx

  char *s; // [rsp+18h] [rbp-D8h]

  int v8; // [rsp+2Ch] [rbp-C4h]

  int v9; // [rsp+30h] [rbp-C0h]

  char v10; // [rsp+34h] [rbp-BCh]

  void *v11; // [rsp+38h] [rbp-B8h]

  _BYTE *v12; // [rsp+40h] [rbp-B0h]

  __int64 v13; // [rsp+50h] [rbp-A0h]

  __int64 v14; // [rsp+58h] [rbp-98h]

  __int64 v15; // [rsp+60h] [rbp-90h]

  __int64 v16; // [rsp+68h] [rbp-88h]

  char v17; // [rsp+70h] [rbp-80h]

  void **v18; // [rsp+90h] [rbp-60h]

  char *v19; // [rsp+98h] [rbp-58h]

  char **v20; // [rsp+A0h] [rbp-50h]

  _BYTE **v21; // [rsp+A8h] [rbp-48h]

  int *v22; // [rsp+B0h] [rbp-40h]

  unsigned __int64 v23; // [rsp+B8h] [rbp-38h]


  s = (char *)a1;

  v23 = __readfsqword(0x28u);

  v8 = 3;

  v13 = 0LL;

  v14 = 0LL;

  v11 = malloc(0x40uLL);

  v9 = strlen(a1);

  v12 = malloc(5uLL);

  obf::Num<int,3858>::Num(&v18);

  *v12 = (unsigned __int64)obf::Num<int,3858>::get(&v18) ^ 0xCC;

  obf::Num<int,2568>::Num(&v18);

  v12[1] = (unsigned __int64)obf::Num<int,2568>::get(&v18) ^ 0xA5;

  obf::Num<int,1868>::Num(&v18);

  v12[2] = (unsigned __int64)obf::Num<int,1868>::get(&v18) ^ 0xF2;

  obf::Num<int,749>::Num(&v18);

  v12[3] = (unsigned __int64)obf::Num<int,749>::get(&v18) ^ 2;

  obf::Num<int,1056>::Num(&v18);

  v12[4] = (unsigned __int64)obf::Num<int,1056>::get(&v18) ^ 0x20;

  v15 = 0LL;

  v16 = 0LL;

  obf::for_wrapper::for_wrapper<enc(char const*)::{lambda(void)#1},enc(char const*)::{lambda(void)#2},enc(char const*)::{lambda(void)#3}>(

    (__int64)&v17,

    (__int64)&v10);

  v18 = &v11;

  v19 = &v10;

  v20 = &s;

  v21 = &v12;

  v22 = &v8;

  v4 = (obf::for_wrapper *)obf::for_wrapper::set_body<enc(char const*)::{lambda(void)#4}>(

                             (__int64)&v17,

                             (__int64)&v10,

                             v1,

                             v2,

                             v3);

  obf::for_wrapper::run(v4);

  obf::for_wrapper::~for_wrapper((obf::for_wrapper *)&v17);

  std::shared_ptr<obf::base_rvholder>::~shared_ptr(&v15);

  v5 = operator new(0x18uLL);

  obf::rvholder<char *>::rvholder(v5, v11, v11);

  std::__shared_ptr<obf::base_rvholder,(__gnu_cxx::_Lock_policy)2>::reset<obf::rvholder<char *>>(&v13, v5);

  v6 = __cxa_allocate_exception(16LL);

  std::shared_ptr<obf::base_rvholder>::shared_ptr(v6, &v13);

  __cxa_throw(v6, &`typeinfo for'std::shared_ptr<obf::base_rvholder>, std::shared_ptr<obf::base_rvholder>::~shared_ptr);

}


뭔가 이상하다 싶어 verify_key 함수의 어셈코드를 보니 아래와 같이 코드 영역 중간부분을 ida가 데이터로 해석하고 있었다.



해당 부분을 convert해서 보면 아래와 같이 strcmp를 통해 어떤 값들을 비교하는걸 볼 수 있었다.



두 값을 디버깅을 통해 확인해보면 인풋을 enc함수 내에서 암호화 해 아래의 값과 비교하는걸 볼 수 있었다.


[0xAE,0x9E,0xFF,0x9C,0xAB,0xC7,0xD3,0x81,0xE7,0xEE,0xFB,0x8A,0x9D,0xEF,0x8D,0xAE]


input이 위의 값이 되도록 하면되는데 중요한건 enc 함수가 난독화되어 있어서 분석이 매우 어려웠다. 그래서 해당 함수를 분석하지 않고 일단 input이 해당 함수를 거친 후 어떻게 return되는지를 통해 해당 함수 동작을 추측해봤다.


input으로 1111111111111111 값을 주고 암호화된 값을 확인해 보면 4바이트씩 값이 반복되는걸 볼 수 있었다. 단순하게 4바이트 키 값으로 xor한다고 생각해 key를 추출해서 위의 비교 대상인 값을 xor해보면 아래와 같은 값이 나온다.


getFlag.py


table_key = [0xAE,0x9E,0xFF,0x9C,0xAB,0xC7,0xD3,0x81,0xE7,0xEE,0xFB,0x8A,0x9D,0xEF,0x8D,0xAE]

key = [222,173,190,239]

flag = ""

for i in xrange(len(table_key)):

    flag += chr(table_key[i]^key[i%4])

print flag


result = p3Asujmn9CEeCB3A


해당 값을 바이너리 실행 후 입력해보면 플래그가 나온다.












'CTF > Writeup' 카테고리의 다른 글

Securinets CTF Quals 2019 AutomateMe  (0) 2019.03.26
Securinets CTF Quals 2019 Web Writeup  (0) 2019.03.25
Pico CTF 2018 keygen-me-2  (0) 2019.03.22
Tokyo-Westerns-3rd-2017 CTF Rev Rev Rev  (0) 2019.03.15
0CTF 2016 Quals : boomshakalaka  (0) 2019.03.14
블로그 이미지

JeonYoungSin

메모 기록용 공간

,