Baby Crypt
2 minutos de lectura
Se nos proporciona un binario llamado 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
Si lo abrimos en Ghidra, veremos esta función main
:
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;
}
Básicamente, pregunta por una clave de 3 bytes y realiza un cifrado XOR. Como la salida esperada es la flag y conocemos su formato (HTB{...}
), podemos invertir el cifrado XOR y obtener la clave esperada.
Sean $m$ el byte en texto claro, $k$ el byte the la clave y $c$ el byte cifrado. El cifrado XOR tiene la siguiente propiedad:
$$ c = m \oplus k \iff k = c \oplus m $$
Por tanto, podemos tomar los primeros tres bytes del texto cifrado (variable llamada local_38
, en formato little-endian) y aplicar XOR con los bytes en texto claro:
$ python3 -q
>>> chr(ord('H') ^ 0x3f)
'w'
>>> chr(ord('T') ^ 0x64)
'0'
>>> chr(ord('B') ^ 0x35)
'w'
Y así conseguimos la clave (w0w
). Vamos a capturar la flag:
$ ./baby_crypt
Give me the key and I'll give you the flag: w0w
HTB{x0r_1s_us3d_by_h4x0r!}