Ransom
2 minutos de lectura
Tenemos un Windows PE llamado windows_update.exe
:
$ file windows_update.exe
windows_update.exe: PE32+ executable (console) x86-64, for MS Windows
Además, hay otro archivo que parece cifrado desde login.xlsx
:
$ file login.xlsx.enc
login.xlsx.enc: data
Descompilación
Si abrimos el Windows PE en Ghidra, veremos esta función main
:
int __cdecl main(int _Argc, char **_Argv, char **_Env) {
char *filename;
__main();
if (_Argc == 1) {
filename = "C:\\Users";
} else if (_Argc == 2) {
filename = _Argv[1];
} else {
printf("Usage: %s <filename>\n", *_Argv);
}
ftw(filename, (_func_int_char_ptr_stat_ptr_int *) &list, 1);
return 0;
}
Está llamando a ftw
:
int ftw(char *path, _func_int_char_ptr_stat_ptr_int *fcb, int descriptors) {
int ret;
undefined4 in_register_00000084;
int in_stack_00000028;
ret = do_it(path, (int) fcb, (void *) CONCAT44(in_register_00000084, descriptors), 0, in_stack_00000028);
return ret;
}
Y esta llama a do_it
. Esta función es mucho más grande, por lo que no la mostraré aquí. Lo que hace básicamente es recorrer el sistema de archivos y buscar archivos.
Intuición
Dado que el reto se llama “Ransom” y hay un archivo cifrado, podríamos pensar que este Windows PE es en realidad un ransomware. De hecho, si buscamos funciones en Ghidra, veremos encryptFile
:
void encryptFile(char *filename) {
bool bVar1;
undefined7 extraout_var;
bVar1 = readfile(filename);
if ((int) CONCAT71(extraout_var,bVar1) != 1) {
encrypt(file, DAT_00409978);
writefile(filename, file, DAT_00409978);
free(file);
}
}
Este lee un archivo con readfile
, llama a encrypt
y escribe el resultado en writefile
. Esta es la función encrypt
:
void encrypt(char *content, ulonglong length) {
char secret[11];
int i;
secret._0_8_ = 0x4345535245505553;
secret._8_2_ = 0x5255;
secret[10] = 'E';
for (i = 0; (ulonglong)(longlong)i < length; i++) {
content[i] = secret[(ulonglong) (longlong) i % 11] + content[i];
}
}
Básicamente, toma cada byte del archivo y suma un byte de la clave (SUPERSECURE
, en formato little-endian):
$ python3 -q
>>> from pwn import p64, p16
>>> p64(0x4345535245505553) + p16(0x5255) + b'E'
b'SUPERSECURE'
Descifrada
Entonces, para descifrar el archivo, solo necesitamos restar el carácter de la clave (y aplicar el módulo 256 para evitar valores negativos). Vamos a hacerlo:
>>> with open('login.xlsx.enc', 'rb') as f:
... enc = f.read()
...
>>> key = b'SUPERSECURE'
>>> data = bytes((e - key[i % 11]) % 256 for i, e in enumerate(enc))
>>> data[:20]
b'PK\x03\x04\x14\x00\x08\x08\x08\x00\xf4\xa3\\Q\x00\x00\x00\x00\x00\x00'
Echando un vistazo a los primeros bytes (bytes mágicos), parece que el archivo es un archivo ZIP (en realidad, los archivos de Microsoft Office son archivos ZIP a pesar de tener una extensión .xlsx
). Entonces, escribamos la información descifrada:
>>> with open('login.xlsx', 'wb') as f:
... f.write(data)
...
4877
>>> exit()
Flag
Si abrimos el archivo, veremos la flag:
HTB{M4lW4R3_4n4LY5I5_IN73r357iN9_57uFF}