-
Let's load binary into Ghidra and navigate to
main
funaction at0x101208
.Decompiled view of this function, after fixing some data types and renaming couple of variables looks like this:
int FUN_00101208(void) { char cVar1; int iVar2; char *pcVar3; size_t sVar4; long lVar5; long in_FS_OFFSET; char input_buf [64]; long local_20; local_20 = *(long *)(in_FS_OFFSET + 0x28); __printf_chk(1,"What\'s the flag? "); input_buf._0_8_ = 0; input_buf._8_8_ = 0; input_buf._16_8_ = 0; input_buf._24_8_ = 0; input_buf._32_8_ = 0; input_buf._40_8_ = 0; input_buf._48_8_ = 0; input_buf._56_8_ = 0; pcVar3 = fgets(input_buf,0x40,stdin); if (pcVar3 == (char *)0x0) { puts("no!!"); iVar2 = 1; } else { sVar4 = strcspn(input_buf,"\n"); input_buf[sVar4] = '\0'; lVar5 = 0; do { cVar1 = FUN_001011e9(); input_buf[lVar5] = input_buf[lVar5] ^ cVar1 + (char)lVar5; lVar5 = lVar5 + 1; } while (lVar5 != 0x40); iVar2 = memcmp(input_buf,PTR_ARRAY_00104010,0x40); if (iVar2 == 0) { puts("You got it!"); } else { puts("That\'s not it..."); iVar2 = 1; } } if (local_20 == *(long *)(in_FS_OFFSET + 0x28)) { return iVar2; } }
As we can see here:
pcVar3 = fgets(input_buf,0x40,stdin);
64
bytes are read from the input and stored into a aninput_buf
. -
After that each byte in
input_buf
is XORed with value returned fromFUN_001011e9
+ current itteratorIt's better viewed from the disassembly:
LAB_001012ae XREF[1]: 001012c6(j) 001012ae b8 00 00 MOV EAX,0x0 00 00 001012b3 e8 31 ff CALL FUN_001011e9 undefined FUN_001011e9() ff ff 001012b8 01 d8 ADD EAX,EBX 001012ba 30 44 1d 00 XOR byte ptr [RBP + RBX*0x1]=>input_buf,AL 001012be 48 83 c3 01 ADD RBX,0x1 001012c2 48 83 fb 40 CMP RBX,0x40 001012c6 75 e6 JNZ LAB_001012ae
-
And a decompilation of
FUN_001011e9
is next:void FUN_001011e9(void) { DAT_0010402c = DAT_0010402c * 0x41c64e6d + 0x3039 & 0x7fffffff; return; }
Here, some value from gloval variable stored at
0x10402c
(wich is initialized with0
as shown below) is multipied by0x41c64e6d
, summed up with another constant0x3039
and bitwise added with0x7fffffff
:DAT_0010402c XREF[2]: FUN_001011e9:001011ed(R), FUN_001011e9:00101201(W) 0010402c 00 00 00 00 undefined4 00000000h
-
After all of this is done the
memcpy
is called:iVar2 = memcmp(input_buf,PTR_ARRAY_00104010,0x40); if (iVar2 == 0) { puts("You got it!"); }
-
We can reverse all of this with a simple python script and capture the flag:
#!/usr/bin/env python3 enc_bytes = [ 0x74, 0x1A, 0x95, 0x4E, 0xBA, 0xDB, 0x47, 0x64, 0x09, 0x2D, 0xD1, 0xBF, 0x8A, 0x9D, 0xDE, 0x5A, 0xD7, 0x5C, 0x93, 0x16, 0x09, 0x3B, 0x30, 0x6F, 0x97, 0x40, 0xD0, 0x7C, 0x57, 0xDB, 0xDE, 0x0C, 0x09, 0xA0, 0x84, 0x9B, 0x8A, 0x76, 0x2F, 0xB1, 0x57, 0xA2, 0xE1, 0x4F, 0xB9, 0x6F, 0x81, 0xBF, 0xB9, 0xBF, 0xE1, 0xEF, 0x79, 0xCF, 0x01, 0xDF, 0xF9, 0x9F, 0xE1, 0x8F, 0x39, 0x2F, 0x81, 0xFF ] x = 0 res = [] for i in range(0, 64): x = ((x * 0x41c64e6d) + 0x3039) & 0x7fffffff r = ((x + i) & 0x000000ff) ^ enc_bytes[i] res.append(r) print(bytearray(res).decode())
MetaCTF{pr0p3r_encrypt10n_1snt_s0_e4sy...}
That's it.