babyreeee
4 minutes to read
We are given a binary called chall
:
$ file chall
chall: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=151528987cd274999ec93665ef2d6a7678c5107b, for GNU/Linux 3.2.0, stripped
When we execute, it asks for the flag:
$ ./chall
Hello! Welcome to SEETF. Please enter the flag.
SEE{asdf}
Flag wrong. Try again.
Let’s open the binary in Ghidra to analyze the decompiled C code. This is the main
function. It is a bit overwhelming because there are a lot of assignments:
undefined8 main() {
char *pcVar1;
undefined4 *puVar2;
size_t length;
ulong i;
ulong i_copy;
char flag_input[128];
undefined4 local_d8[4];
undefined4 local_c8;
undefined4 uStack196;
undefined4 uStack192;
undefined4 uStack188;
undefined4 local_b8;
undefined4 uStack180;
undefined4 uStack176;
undefined4 uStack172;
undefined4 local_a8;
undefined4 uStack164;
undefined4 uStack160;
undefined4 uStack156;
undefined4 local_98;
undefined4 uStack148;
undefined4 uStack144;
undefined4 uStack140;
undefined4 local_88;
undefined4 uStack132;
undefined4 uStack128;
undefined4 uStack124;
undefined4 local_78;
undefined4 uStack116;
undefined4 uStack112;
undefined4 uStack108;
undefined4 local_68;
undefined4 uStack100;
undefined4 uStack96;
undefined4 uStack92;
undefined4 local_58;
undefined4 uStack84;
undefined4 uStack80;
undefined4 uStack76;
undefined4 local_48;
undefined4 uStack68;
undefined4 uStack64;
undefined4 uStack60;
undefined4 local_38;
undefined4 uStack52;
undefined4 uStack48;
undefined4 uStack44;
undefined4 local_28;
undefined4 uStack36;
undefined4 uStack32;
undefined4 uStack28;
undefined4 local_18;
undefined4 uStack20;
undefined4 uStack16;
undefined4 uStack12;
byte i_byte;
puts("Hello! Welcome to SEETF. Please enter the flag.");
local_d8[0] = 0x98;
local_d8[1] = 0x8b;
local_d8[2] = 0x88;
local_d8[3] = 0xc3;
local_c8 = 0x71;
uStack196 = 0xb6;
uStack192 = 0x7e;
uStack188 = 0xa3;
local_b8 = 0x72;
uStack180 = 0xbb;
uStack176 = 0x73;
uStack172 = 0x7d;
local_a8 = 0x7a;
uStack164 = 0xa9;
uStack160 = 0x74;
uStack156 = 0x73;
local_98 = 0x68;
uStack148 = 0xa4;
uStack144 = 0xb6;
uStack140 = 0x6e;
local_88 = 0x62;
uStack132 = 0xbc;
uStack128 = 0x61;
uStack124 = 0x61;
local_78 = 0x62;
uStack116 = 0xb3;
uStack112 = 0x67;
uStack108 = 0xbc;
local_68 = 0x61;
uStack100 = 0x6b;
uStack96 = 0xb8;
uStack92 = 0xb5;
local_58 = 0x56;
uStack84 = 0x54;
uStack80 = 0x89;
uStack76 = 0x55;
local_48 = 0x8c;
uStack68 = 0x50;
uStack64 = 0x5b;
uStack60 = 0x51;
local_38 = 0x53;
uStack52 = 0x54;
uStack48 = 0x5d;
uStack44 = 0x5e;
local_28 = 0x50;
uStack36 = 0x86;
uStack32 = 0x89;
uStack28 = 0x89;
local_18 = 0x48;
uStack20 = 0x4f;
uStack16 = 0x49;
uStack12 = 0xf1;
fgets(flag_input, 0x80, stdin);
length = strlen(flag_input);
if (length == 53) {
puts("Good work! Your flag is the correct size.");
puts("On to the flag check itself...");
length = strlen(flag_input);
i = 0;
do {
i_copy = i & 0xffffffff;
if (length - 1 == i) {
puts("Success! Go get your points, champ.");
return 0;
}
pcVar1 = flag_input + i;
puVar2 = local_d8 + i;
i_byte = (byte) i;
i = i + 1;
} while ((byte) *puVar2 == (byte) (*pcVar1 + 0x45U ^ i_byte));
printf("Flag check failed at index: %d", i_copy);
} else {
printf("Flag wrong. Try again.");
}
return 1;
}
Notice that the flag must have 53 bytes (actually 52 because the last one is a new line character):
$ python3 -c 'print("A" * 47)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$ ./chall
Hello! Welcome to SEETF. Please enter the flag.
SEE{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA}
Good work! Your flag is the correct size.
On to the flag check itself...
Flag check failed at index: 4
Here we have two ways to solve the challenge. One is to test every character (let’s say index 4) of the flag until we get a message "Flag check failed at index: 5"
. Then we can construct the flag one character at a time.
However, I found it nicer to reverse the algorithm to encrypt the flag (that uses XOR), since we know how our input is being encrypted and compared to the real encrypted flag.
This is the solution script:
#!/usr/bin/env python3
flag_enc = [
0x98,
0x8b,
0x88,
0xc3,
0x71,
0xb6,
0x7e,
0xa3,
0x72,
0xbb,
0x73,
0x7d,
0x7a,
0xa9,
0x74,
0x73,
0x68,
0xa4,
0xb6,
0x6e,
0x62,
0xbc,
0x61,
0x61,
0x62,
0xb3,
0x67,
0xbc,
0x61,
0x6b,
0xb8,
0xb5,
0x56,
0x54,
0x89,
0x55,
0x8c,
0x50,
0x5b,
0x51,
0x53,
0x54,
0x5d,
0x5e,
0x50,
0x86,
0x89,
0x89,
0x48,
0x4f,
0x49,
0xf1
]
for i, c in enumerate(flag_enc):
print(chr(((c ^ i) - 0x45)), end='')
$ python3 solve.py
SEE{0n3_5m411_573p_81d215e8b81ae10f1c08168207fba396}
The full script can be found in here: solve.py
.