Baby Crypt
2 minutes to read
We have a binary called baby_crypt
:
$ file baby_crypt
baby_crypt: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=24af7e68eab982022ea63c1828813c3bfa671b51, for GNU/Linux 3.2.0, not stripped
If we open it in Ghidra, we will see this main
function:
int main() {
char *key;
long in_FS_OFFSET;
int i;
undefined8 local_38;
undefined8 local_30;
undefined8 local_28;
undefined2 local_20;
long canary;
canary = *(long *) (in_FS_OFFSET + 0x28);
printf("Give me the key and I\'ll give you the flag: ");
key = (char *) malloc(4);
fgets(key, 4, stdin);
local_38 = 0x6f0547480c35643f;
local_30 = 0x28130304026f0446;
local_28 = 0x5000f4358280e52;
local_20 = 0x4d56;
for (i = 0; i < 0x1a; i = i + 1) {
*(byte *) ((long) &local_38 + (long) i) = *(byte *) ((long) &local_38 + (long) i) ^ key[i % 3];
}
printf("%.26s\n", &local_38);
if (canary != *(long *) (in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
Basically, it asks for a 3-byte key and then performs a XOR cipher. Since the expected output is the flag and we know the format (HTB{...}
), we can reverse the XOR cipher and get the expected key.
Let $m$ be the plaintext byte, $k$ the key byte and $c$ be the ciphertext byte. XOR cipher has this property:
$$ c = m \oplus k \iff k = c \oplus m $$
Hence, we can take the first three bytes of the ciphertext (variable called local_38
, in little-endian format) and XOR them with the plaintext bytes:
$ python3 -q
>>> chr(ord('H') ^ 0x3f)
'w'
>>> chr(ord('T') ^ 0x64)
'0'
>>> chr(ord('B') ^ 0x35)
'w'
And we found the key (w0w
). Let’s get the flag:
$ ./baby_crypt
Give me the key and I'll give you the flag: w0w
HTB{x0r_1s_us3d_by_h4x0r!}