Flare-On 6 CTF WriteUp (Part 10)

. 9 min read

This is the tenth part of the Flare-On 6 CTF WriteUp Series.

10 - Mugatu

The challenge reads

Hello,
I’m working an incident response case for Derek Zoolander. He clicked a link and was infected with MugatuWare! As a result, his new headshot compilation GIF was encrypted. To secure an upcoming runway show, Derek needs this GIF decrypted; however, he refuses to pay the ransom. We received an additional encrypted GIF from an anonymous informant. The informant told us the GIF should help in our decryption efforts, but we were unable to figure it out. We’re reaching out to you, our best malware analyst, in hopes that you can reverse engineer this malware and decrypt Derek’s GIF.

I've included a directory full of files containing:
MugatuWare malware
Ransom note (GIFtToDerek.txt)
Encrypted headshot GIF (best.gif.Mugatu)
Encrypted informant GIF (the_key_to_success_0000.gif.Mugatu)

Thanks, Roy

The challenge is a reference to the movie Zoolander 2. The main objective is to decrypt a GIF file which has been encrypted by the ransomware. In addition to these two files we have an additional encrypted GIF which has been provided for our help. Since we are dealing with a ransomware it's best to use a Virtual Machine. Doing so will also enable us to run the sample and observe its behavior.

Dynamic Analysis

For dynamic analysis I'll be using API Monitor. This free tool allows us to trace all the API calls made by an program while its running. Using the tool we notice the following:

Figure 1: Twitrss.me
Figure 1: Twitrss.me
  • A POST request to mugatu.flare-on.com. Interestingly, querying with nslookup from the terminal returns NXDOMAIN which implies it's a non existent domain.
Figure 2: POST request to mugatu.flare-on.com
Figure 2: POST request to mugatu.flare-on.com
Figure 3: NXDOMAIN
Figure 3: NXDOMAIN

Let's add the following entry to our host file (C:\Windows\System32\drivers\etc\host) for redirecting traffic to mugatu.flare-on.com to localhost.

127.0.0.1 mugatu.flare-on.com

We need to set up a HTTP server for receiving the POST request. We can code one in Python (like below) or use a tool like Packet Sender. Once the server is setup let's run the binary.

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        body = self.rfile.read(content_length)
        print body
        self.send_response(200)
        self.end_headers()

httpd = HTTPServer(('localhost', 80), SimpleHTTPRequestHandler)
httpd.serve_forever()

The malware sends out POST requests which looks like Base64 encoded data.

λ python post_server.py
7u6sH0UAAAAIQk4RXEsKXQ5UQVxLHX8dVUIfDX4WV14IYQVNGRwGAAATFRFPBhQmGi8+EwtEABFTHRBRQF1VVlZVRhcDHllUVhRbEVg=
127.0.0.1 - - [30/Sep/2019 13:54:11] "POST / HTTP/1.1" 200 -
7u6sH0UAAABBZG1pbnwxMC4wLjIuMTV8Ni0xLTc2MDF8QWRtaW5pc3RyYXRvcnxDOlxXaW5kb3dzfDA5LzMwLzIwMTktMDg6MjQ6MTA=
127.0.0.1 - - [30/Sep/2019 13:54:17] "POST / HTTP/1.1" 200 -
7u6sH0UAAAAIQk4RXEsKXQ5UQVxLHX8dVUIfDX4WV14IYQVNGRwGAAATFRFPBhQmGi8+EwtEABFTHRBRQF1VVlZVRhcDHllUVhRbEVg=
127.0.0.1 - - [30/Sep/2019 13:54:22] "POST / HTTP/1.1" 200 -

If we look at the POST request in a debugger we can find expects a response to the POST request which apparently should also be Base64 encoded as shown in Figure 4.

Figure 4: The response should be base64 encoded
Figure 4: The response should be base64 encoded

After Base64 decoding the response, it's xored with 0x4D and it must match the string orange mocha frappuccino\0. Appended with this string we need to send another 4 byte value which will later be used as a key to encrypt files as we will soon see. In the code below, we are sending the key \x01\x02\x03\x04.

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
import base64

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        body = self.rfile.read(content_length)
        print body
        self.send_response(200)
        self.end_headers()
        start = str(bytearray(map(lambda x: x^0x4d, bytearray('orange mocha frappuccino\0'))))
        key = '\x01\x02\x03\x04'
        to_send = start + key + '\xff'*34
        self.wfile.write(base64.b64encode(to_send))
        
httpd = HTTPServer(('localhost', 80), SimpleHTTPRequestHandler)
httpd.serve_forever()

Let's go back to API Monitor. We spot a series of the following function calls

  • GetLogicalStringsA
  • GetDriveTypeA
  • FindFirstFileA

Typically, in a ransomware these functions are generally used to enumerate all the files in a directory.

Figure 5: Call to FindFirstFileA
Figure 5: Call to FindFirstFileA

Let's set a breakpoint on the functions and try to know what it's really doing. To thwart analysis, all the API calls have been obfuscated. Shown in Figure 6 are the stubs which ultimately lead to the real API.

Figure 6: Obfuscated API calls stub
Figure 6: Obfuscated API calls stub

For example in Figure 7, it is actually a call to FindFirstFileA. Instead of a direct call, it calls the corresponding stub which ultimately lands on the real function.

Figure 7: Obfuscated call to FindFirstFileA
Figure 7: Obfuscated call to FindFirstFileA

Deobfuscating API calls

Figure 8: Addresses of the stubs
Figure 8: Addresses of the stubs

The addresses of the stubs are stored in a pointer table as shown in Figure 8. To deobfuscate, we can simply write the address of the final function in the pointer table bypassing the stub. The following x64dbg script does that

addr = dump.sel()
i = 0

loop_1:
mov api_jump, [addr]
api = dis.imm(api_jump)
not api
mov [addr], api
add addr, 4

inc i
cmp i, 0x50
jl loop_1

After running the script, the pointer table look like Figure 9.

Figure 9: Updated pointer table
Figure 9: Updated pointer table

Correspondingly, the disassembly is now readable as we have removed all the indirect calls.

Figure 10: Call indirection removed
Figure 10: Call indirection removed

The malware recursively iterates over all directories starting from C:\ drive. As we can see in Figure 11, it compares the directory name with the string "really, really, really, ridiculously good looking gifs".

Figure 11: The malware it searching for a special directory
Figure 11: The malware it searching for a special directory

Which means its searching for a directory with that specific name. Lets create one such directory like C:\$\really, really, really, ridiculously good looking gifs. We have created the directory under a directory named $ so that it will be found first. Within the directory we keep a GIF file since we know it encrypts them. Instead of a real GIF we can use a dummy file filled with the a bunch of A's such that it will be easier to spot in the debugger If at this point we let the malware run freely, we'll see that it goes on to encrypt the dummy GIF with .Mugatu extension appended.

Finding the encryption algorithm

We need to locate the encryption code by which it encrypts the files. A quick way is to set breakpoint on File Handling APIs like CreateFileA, ReadFile, WriteFile etc. Using this approach we can quickly zero in on the relevant code as shown in Figure 12.

Figure 12: Code related to encryption
Figure 12: Code related to encryption

The malware loads the file in memory using CreatFileA, CreateFileMappingA and MapViewOfFile. A few lines below we notice an indirect call to a function which does the encryption.

Figure 13: Call to encrypt function
Figure 13: Call to encrypt function

This function takes in three parameters:

  • A pointer to the buffer containing the file contents to encrypt
  • Length of the above buffer
  • Pointer to the 4 byte key (which in our case was \x01\x02\x03\x04)
push ebp
mov ebp,esp
push ebx
push esi
mov esi,dword ptr ss:[ebp+C]
push edi
--------------snip--------------

add edx,esi
xor ecx,eax
sub esi,61C88647
add ecx,ebx

--------------snip--------------
pop esi
pop ebx
pop ebp
ret

Inspecting the code we notice the constant 61C88647. Searching for this value on Google points us to Tiny Encryption Algorithm (TEA). Note that the actual constant used in TEA source code is 9E3779B9 (which is the same as -61C88647when treated as an unsigned 32-bit integer). Apart from TEA, the XTEA cipher also uses the same constant and have a similar structure.

Let's try to decompile the encryption code. We can do this by copying the assembly to a new file and assemble it using fasm.

; enc-algo.asm

format PE

encrypt:
    push ebp
    mov ebp, esp
    push ebx
    push esi
    mov esi, dword [ebp+0xC]
    push edi
    mov edi, dword [esi]
    mov ebx, dword [esi+0x4]
    xor esi, esi

  here:
    mov ecx, dword [ebp+0x10]
    mov eax, esi
    and eax, 0x3
    movzx edx, byte [eax+ecx*1]
    mov ecx, ebx
    shl ecx, 0x4
    mov eax, ebx
    shr eax, 0x5
    add edx, esi
    xor ecx, eax
    sub esi, 0x61C88647
    add ecx, ebx
    xor ecx, edx
    mov edx, dword [ebp+0x10]
    add edi, ecx
    mov ecx, edi
    mov eax, edi
    shr eax, 0x5
    shl ecx, 0x4
    xor ecx, eax
    mov eax, esi
    shr eax, 0xB
    add ecx, edi
    and eax, 0x3
    movzx eax, byte [eax+edx]
    add eax, esi
    xor ecx, eax
    add ebx, ecx
    dec dword [ebp+0x8]
    jne short here
    mov esi, dword [ebp+0xC]
    mov dword [esi], edi
    pop edi
    mov dword [esi+0x4], ebx
    pop esi
    pop ebx
    pop ebp
    ret

After renaming the variables appropriately, our decompiled code looks like Figure 14.

Figure 14: Decompiled encryption function
Figure 14: Decompiled encryption function

The TEA cipher uses a fixed number (32) of rounds which is not the case with here. This encryption algorithm here is actually a modified version of the XTEA cipher using a 32 bit key instead of the standard 64 bit.

Decrypting the informant GIF

The informant GIF has the filename the_key_to_success_0000.gif.Mugatu. The name hints that the key used to encrypt this file is \x00\x00\x00\x00. Using the following code we can decrypt the informant GIF.

#include <stdio.h>

typedef unsigned int uint32_t;
typedef unsigned char uint8_t;

void xtea_decipher(unsigned int num_rounds, uint32_t v[2], uint8_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
    for (i=0; i < num_rounds; i++) {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}

void main()
{
  FILE *inf = fopen("the_key_to_success_0000.gif.Mugatu", "rb");
  FILE *out = fopen("the_key_to_success_0000.gif", "wb");
  uint8_t key[] = {0, 0, 0, 0};
  
  fseek(inf, 0, SEEK_END);
  int file_size = ftell(inf);
  rewind(inf);
  int remaining = file_size;
  uint32_t ct[2];  

  while (remaining > 8)
  {
    fread(ct, sizeof(uint32_t), 2, inf);
    xtea_decipher(32, ct, key);
    fwrite(ct, sizeof(uint32_t), 2, out);
    remaining -= 8;
  }

  uint8_t buffer[8];

  if (remaining > 0)
  {
    fread(buffer, remaining, 1, inf);
    fwrite(buffer, remaining, 1, out);
  }
  fclose(inf);
  fclose(out);
}
Figure 15: the_key_to_success_0000.gif
Figure 15: the_key_to_success_0000.gif

The GIF hints that the first key byte used for encrypting best.gif is 0x31. Now all we need is to bruteforce the other 3 bytes of the key. We know that a GIF file starts with the bytes "GIF89". If we use the correct key the decrypted buffer must start with those bytes. Further, to speed up bruteforce we can try to decrypt just the first 8 bytes instead of the entire file.

int main()
{
  for (uint8_t k1 = 0; k1 < 0xff; k1++)
  {
    for (uint8_t k2 = 0; k2 < 0xff; k2++)
    {
      for (uint8_t k3 = 0; k3 < 0xff; k3++)
      {
        // First 8 bytes of best.gif.Mugatu
        uint32_t ct[] = {0x50B08E24, 0x6F68B2E8};

        uint8_t key[] = {0x31, k1, k2, k3};

        xtea_decipher(32, ct, key);
        if (ct[0] == 0x38464947) //GIF
        {
          printf("Key bytes 31 %x %x %x\n", k1, k2, k3);
          return 0;
        }
      }
    }
  }
  return -1;
}

Running our bruteforcer we get the full key in seconds as shown in Figure 16.

FIgure 16: Bruteforcing the key

Decrypting best.gif

Using the key we can XTEA decrypt best.gif.Mugatu to obtain the flag.

Figure 17: best.gif
Figure 17: best.gif

Flag: FL4rE-oN_5o_Ho7_R1gHt_NoW@flare-on.com



Barun

Reverse Engineer with an interest in low level stuff and anything about security.

Get IoT Security Training

IoT Pentesting Exploitation Training

Tags

Android android application security android hands on security and exploitation training android security Apktool application auditing application security auditing appsec usa appwatch attify attify badge attify training binwalk blackberry pentesting blackhat ble BLE hacking and exploitation BLE sniffing box brut Exception chroot cloud based mobile application security scanner consulting CTF Damn Vulnerable iOS App devops dumping memory embedded hacking exploitation exploiting smart devices Firmware hacking frida hackfest hacking smart devices how to secure iot device IDA internet of things Internet of Things Security ios application security ios security iot iot device IoT Exploitation iot hacking iot pentest iot pentesting iot security iot security training iotsecurity jtag jtag debugging mobile app mobile application security mobile application security testing mobile security ninja recon technique offensive iot exploitation ola cabs owasp owasp appsec penetration testing pentesting pentesting mobile apps powerofcommunity PrinterSecurity qemu quizup radio communication protocol radio coomunication Reversing sdr secure coding guidelines security security issue security services security training security vulnerability smart devices social networking spi threat modeling training uart vulnerability writeups xposed hooking zigbee zigbee exploitation zigbee security zwave firmware reverse engineering firmware emulation firmware analysis toolkit firmadyne getting started with firmware hacking iot penetration testing iot attacks recent iot attacks cyber attacks iot hacks biggest iot attacks of all time hacked smart devices iot bots, malwares latest iot attacks BtleJuice bleah retail iot challenges in iot retail security issues faced by e-retailers network security in retail DDoS attacks phishing attacks how retail can prevent cyber attacks security challenges in retail IoT Flare-on radio waves hacking arduino nano how to hack radio waves analog modulation digital modulation capture radio traffic bluetooth technology BLE vulnerabilities BLE attacks BLE dangers BLE security issues exploiting ble how to exploit ble tools to exploit ble privacy protection iot threats protect against iot threats dangers of iot smart user security how to protect iot devices monitor iot devices internet security safety measures to protect privacy healthcare iot iot threats to healthcare industry how can healthcare fight iot threats healthcare cyber security prevent cyber attacks on healthcare measures to prevent cyber attacks on healthcare organisations steps to prevent iot attacks on healthcare healthcare business protection against iot threats security in healthcare iot recent cyber attacks recent ARM attacks ARM course ARM Training ARM binaries Exploit ARM devices IoT hacks on ARM devices ARM gadgets learn ARM exploitation Mirai Botnet vulnerable ARM devices arm ARM exploitation book ARM exploitation video training guide to ARM exploitation cybersecurity why you should be a cybersecurity expert professional expert career in cybersecurity why choose career in cybersecurity growth potential penetration testers hackers profession What is a Mirai Botnet? virus How Mirai botnet infects your device Understanding Mirai Botnet How Mirai works setup mirai history IoT Devices What is mirai botnet? IP cameras security cameras CCTV cameras hacked security IP cameras surveillance cameras hijacked vulnerabilities in internet connected cameras recent security camera attacks vulnerabilities discovered in popular IoT IP cameras IoT security guidelines Mozilla NIST GSMA best security practices automotive security V2V V2I Car security ECU hacking GozNym Bank account hack customer privacy banking malware

Instagram