Reversing/ctf

[write-up] 2018 SCTF - dingjmax

Ryuuu 2018. 7. 14. 10:09

dj 리듬게임을 할 수 있는 바이너리였다. max인 100000 점수로 맞추면 플래그가 나오는 것 같아서 무조건 perfect가 되게 패치하였다.


하지만 플래그가 나오지 않았다….

 


따라서 디버깅 해본 결과 플래그를 연산하는 부분은 한 루틴밖에 없었다.

 


시간과 어떤 것을 누르는지 가지고 플래그를 연산하는데 반복문이 한번 돌때마다 ++time 해주어 1씩 증가된다. 또한 dj 게임이 시작될 때는 400부터 시작된다. 따라서 perfect가 뜨는 시간을 알면 플래그를 복호화 할 수 있을것이라고 생각했다.

 


계속 디버깅 해 본 결과 dword_607600[0] = _(DWORD )zero_offset[(unsigned int64)(0xCCCCCCCCCCCCCCCDLL * (unsigned int128)time >> 64) >> 4]; 이 라인에서 dj 노드를 가지고 오는 것 같았다. 


실제로 zero_offset이란 data 영역을 본 결과 노드들이 존재하는 것을 확인할 수 있었다.



또한 위의 if문을 python으로 실행시켜 본 결과 time이 20배수일 때 if문을 만족시키는 것을 확인할 수 있었다.

 
#usr/bin/env python
# ryuuu

for time in range(10000):
        if(time == 20 * ((0xCCCCCCCCCCCCCCCD * time >> 64) >> 4)):
                print time



저 if 문이 실행될때마다 dj 노드를 가지고 온다. 20초마다 노드를 한칸씩 가지고 오는 것이다. 따라서 처음 시작시간 400 + o가 있는 offset *20 해주면 노드를 누르면 perfect가 나오는 시간을 구할 수 있다. 그래서 위에서 본 offset이 들어있는 데이터영역을 파싱해주는 파이썬 코드를 작성하였다.

 
# usr/bin/env python
# ryuuu

from pwn import *

f = open("data.txt",'r')

time = []
for i in range(2130):
        str = f.readline()
        if "aO" in str:
                time.append(i*20+400)

print time


따라서 이제 시간을 모두 알았으니 플래그를 연산하는 부분을 그대로 가지고와 연산해 출력해주는 코드를 짤 수 있다. 어떤것을 눌러야 하는지는 직접 박혀있는 것을 손으로 써주었다.

int time[299] = { 780, 940, 1100, 1260, 1420, 1580, 1740, 1900, 2060, 2220, 2380, 2540, 2700, 2860, 3020, 3180, 3340, 3500, 3660, 3820, 3980, 4140, 4300, 4460, 4620, 4780, 4940, 5100, 5260, 5420, 5580, 5740, 5900, 6060, 6220, 6380, 6540, 6700, 6860, 7020, 7180, 7340, 7500, 7660, 7820, 7980, 8140, 8300, 8460, 8620, 8780, 8940, 9100, 9260, 9420, 9580, 9740, 9900, 10060, 10220, 10380, 10540, 10620, 10700, 10780, 10860, 10940, 11020, 11100, 11180, 11260, 11340, 11420, 11500, 11540, 11580, 11620, 11660, 11700, 11740, 11780, 11820, 11860, 11900, 11940, 11980, 12000, 12020, 12040, 12060, 12080, 12100, 12120, 12140, 12160, 12180, 12200, 12220, 12240, 12260, 12300, 12460, 12620, 12780, 12940, 13100, 13260, 13420, 13580, 13740, 13900, 14140, 14400, 14540, 14680, 14940, 14960, 15000, 15020, 15080, 15200, 15240, 15300, 15400, 15520, 15540, 15660, 15880, 15920, 15980, 16080, 16140, 16220, 16840, 17000, 17260, 17520, 17740, 17780, 18300, 18440, 18840, 18860, 19020, 19160, 19360, 19880, 20100, 20120, 20600, 20620, 20640, 20680, 20780, 20880, 20920, 20980, 21240, 21300, 21320, 21340, 21420, 21440, 21600, 21740, 21780, 21880, 22260, 22320, 22840, 23220, 23280, 23620, 23860, 24000, 24020, 24100, 24140, 24260, 24400, 24780, 25180, 25220, 25320, 25360, 25520, 25680, 26040, 26080, 26180, 26200, 26240, 26360, 26480, 26640, 26760, 27440, 27560, 27600, 27620, 27680, 27720, 27800, 27820, 27920, 28120, 28140, 28300, 28440, 28460, 28480, 28600, 29200, 29260, 29420, 29480, 29760, 29780, 30100, 30180, 30300, 30380, 30500, 30520, 30920, 31060, 31300, 31420, 31660, 31900, 32360, 32460, 32660, 32700, 32860, 32920, 33000, 33020, 33080, 33240, 33300, 33560, 33700, 33780, 33980, 34000, 34160, 34260, 34280, 34320, 34340, 34500, 34800, 34820, 35180, 35240, 35300, 35340, 35540, 35620, 35920, 36420, 36460, 36540, 36700, 36860, 36980, 37040, 37060, 37200, 38220, 38500, 38940, 39060, 39160, 39280, 39520, 39540, 39560, 39600, 39700, 40040, 40100, 40160, 40180, 40320, 40360, 40520, 40660, 40880, 40980, 41100, 41340, 41520, 41620, 41640, 41740, 42100, 42200 };

char *answer = "jfdfddddfjkjfdfjkjfdfjkjfdfjkjfdkdjdfdfdjdkdfjkjfdkdjdfdfdjdkdkdjdfdfdjdkdkdjdfdddfdjdkdjdfdfdjdkjfdkdjdfdfdjdkfdfkddkjfdjfffkdfdfkdfkfjkfdfjjfkdjkkdddfjfkkfdjjdkjjfkdffdjjkfkfjfjfdjfdddkfdkdkjjkkkdkfjkkfjkddfkffdjfkffkkfjjfffjfjjfjdfddjdjfjfjkddkdkkdjkdjdkkdfkkkdkdkjdjfkdkkjdjkdkffkkdjkjjdfjddfkjk";
char byte_6075A0[100];
int dword_60756C = 0;

char byte_607568 = 0;
char byte_607588 = 0;
int make_flag(int a1);

char *s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_!";
__int64 intro();
__int64 __fastcall sub_400C5E(char *a1);
__int64 __fastcall sub_401DB8(unsigned __int8 a1, unsigned __int8 a2);
signed __int64 __fastcall sub_401C50(unsigned __int8 a1);

int main() {
   intro();
   char flag[46] = "qN7BuRx4rElDv84dgNaaNBanZf0HSHFjqOvbkFfgTRg3r";
   int i;
   for (i = 0; i < 299; i++) {
      make_flag(answer[i]*time[i]);
      sub_400C5E(flag);
   }
printf("SCTF{%s}", flag);
}
__int64 intro()
{
   __int64 result; // rax@3
   int i; // [sp+Ch] [bp-4h]@1

   byte_607568 = 0;
   byte_607588 = 0;
   s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_!";
   dword_60756C = strlen("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_!");
   for (i = 0;; ++i)
   {
      result = (unsigned int)dword_60756C;
      if (i >= dword_60756C)
         break;
      byte_6075A0[(signed __int64)i] = i;
   }
   return result;
}

int make_flag(int a1) {

   char v1; // ST13_1
   unsigned __int8 v3; // [rsp+Eh] [rbp-6h]
   int i; // [rsp+10h] [rbp-4h]

   for (i = 0; a1 > i; ++i)
   {
      byte_607588 = ((unsigned __int8)byte_607588 + 1) % dword_60756C;
      byte_607568 = ((unsigned __int8)byte_607568 + (unsigned __int8)byte_6075A0[(unsigned __int8)byte_607588])
         % dword_60756C;
      v1 = byte_6075A0[(unsigned __int8)byte_607588];
      byte_6075A0[(unsigned __int8)byte_607588] = byte_6075A0[(unsigned __int8)byte_607568];
      byte_6075A0[(unsigned __int8)byte_607568] = v1;
      v3 = byte_6075A0[((unsigned __int8)byte_6075A0[(unsigned __int8)byte_607588]
         + (unsigned __int8)byte_6075A0[(unsigned __int8)byte_607568])
         % dword_60756C];
   }
   return (unsigned __int8)s[v3];
}

signed __int64 __fastcall sub_401C50(unsigned __int8 a1)
{
   int i; // [rsp+10h] [rbp-4h]

   for (i = 0; i < dword_60756C; ++i)
   {
      if (a1 == s[i])
         return (unsigned int)i;
   }
   return 0xFFFFFFFF;
}

__int64 __fastcall sub_401DB8(unsigned __int8 a1, unsigned __int8 a2)
{
   unsigned int v2; // ST10_4

   v2 = sub_401C50(a1);
   return (unsigned __int8)s[((unsigned int)sub_401C50(a2) ^ (unsigned __int64)v2) % (unsigned int)dword_60756C];
}

__int64 __fastcall sub_400C5E(char *a1)
{
   unsigned __int8 flag_one_byte; // al
   __int64 result; // rax
   unsigned int i; // [rsp+18h] [rbp-18h]
   int flag_len; // [rsp+1Ch] [rbp-14h]

   flag_len = strlen(a1);                        // flag_len
   for (i = 0; ; ++i)
   {
      result = i;
      if ((signed int)i >= flag_len)
         break;
      flag_one_byte = make_flag(1);
      a1[i] = sub_401DB8(a1[i], flag_one_byte);
   }
   return result;



 

 Flag : SCTF{I_w0u1d_l1k3_70_d3v3l0p_GUI_v3rs10n_n3x7_t1m3}