Friday, 20 October 2017

CTF Writeup - Flare-On 2017 - 03: greek_to_me.exe


  • Name - greek_to_me.exe
  • Category - Reverse Engineering
  • Points - 1
  • Binary - Download here


Launching the binary greek_to_me.exe, we don't get any output nor the option to supply any input. It gets stuck waiting for us to do something or maybe it's doing something computationally intensive. Let's look at the first part of the main function sub_401008():



The function first calls sub_401121(), in the blue basic block above, which contains the following code:

SOCKET __cdecl sub_401121(char *buf)
{
    SOCKET v2; // esi
    SOCKET v3; // eax
    SOCKET v4; // edi
    struct WSAData WSAData; // [esp+0h] [ebp-1A0h]
    struct sockaddr name; // [esp+190h] [ebp-10h]
    
    if ( WSAStartup(0x202u, &WSAData) )
        return 0;
    v2 = socket(2, 1, 6);
    if ( v2 != -1 )
    {
        name.sa_family = 2;
        *(_DWORD *)&name.sa_data[2] = inet_addr("127.0.0.1");
        *(_WORD *)name.sa_data = htons(0x2222u);
        if ( bind(v2, &name, 16) != -1 && listen(v2, 0x7FFFFFFF) != -1 )
        {
            v3 = accept(v2, 0, 0);
            v4 = v3;
            if ( v3 != -1 )
            {
                if ( recv(v3, buf, 4, 0) > 0 )
                    return v4;
                closesocket(v4);
            }
        }
        closesocket(v2);
    }
    WSACleanup();
    return 0;
}


The function opens a local socket on port 2222 and accepts a buffer of 4 bytes. Going back to the image of sub_401121(), the green basic block shows that ECX is loaded with 0x40107C + 0x79, EAX is loaded with 0x40107C and DL takes the first byte of the buffer. The yellow basic block then loops from memory position EAX to memory position ECX, each time computing a simple decryption routine (XOR memory byte with first byte of input and add 0x22) and overwriting the previous values. As location 0x40107C points to code in the binary, the loop modifies the binary whilst running. This is how location 0x40107C looks before it has been modified:


The trick to this challenge is that the decryption algorithm is dependent on a single byte ONLY. As this search space is tiny we create a python script that runs the binary, connects to it, sends it a single character and writes the response:

import socket
import subprocess

for x in range(128,255):
    subprocess.Popen(['greek_to_me.exe'], close_fds=True, creationflags=0x00000008)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("127.0.0.1", 2222))
    s.send(chr(x)) 
    data = s.recv(1024).decode()
    print x, data
    s.close ()

Running the script:

Command Prompt
C:\>python brute_force.py 128 Nope, that's not it. 129 Nope, that's not it. 130 Nope, that's not it. [... snip ...] 160 Nope, that's not it. 161 Nope, that's not it. 162 Congratulations! But wait, where's my flag? 163 Nope, that's not it. 164 Nope, that's not it. [... snip ...] C:\>

We now know that the right key is 0xA2, but were is the flag? If we send the right key straight away and go through the decryption algorithm, we notice that the bottom part of sub_401121(), specifically at location 0x40107C, has been modified:


Collecting the bytes above the congratulations message we get: et_tu_brute_force@flare-on.com

No comments:

Post a Comment