Ransom
3 minutes to read
We have a Windows PE called windows_update.exe
:
$ file windows_update.exe
windows_update.exe: PE32+ executable (console) x86-64, for MS Windows
Moreover, there is another file that looks encrypted from login.xlsx
:
$ file login.xlsx.enc
login.xlsx.enc: data
Decompilation
If we open the Windows PE in Ghidra, we will see this main
function:
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;
}
It is calling 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;
}
And it calls do_it
. This function is much more bigger, so I won’t show it here. What it does basically is traverse the file system and look for files.
Intuition
Since the challenge is called “Ransom” and there is an encrypted file, we might think that this Windows PE is actually a ransomware. In fact, if we search for functions in Ghidra, we will see 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);
}
}
This one reads a file with readfile
, calls encrypt
and writes the output using writefile
. This is 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];
}
}
Basically, it takes each byte of the file and adds a character from a key (SUPERSECURE
, in little-endian form):
$ python3 -q
>>> from pwn import p64, p16
>>> p64(0x4345535245505553) + p16(0x5255) + b'E'
b'SUPERSECURE'
Decryption
So, to decrypt the file, we only need to substract the character from the key (and apply modulo 256 to avoid negative values). Let’s do it:
>>> 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'
Taking a look at the first bytes (magic bytes), it looks like the file is a ZIP file (actually, Microsoft Office files are ZIP archives despite having .xlsx
extension). So, let’s write the decrypted information:
>>> with open('login.xlsx', 'wb') as f:
... f.write(data)
...
4877
>>> exit()
Flag
If we open the file, we will see the flag:
HTB{M4lW4R3_4n4LY5I5_IN73r357iN9_57uFF}