Friday, 4 November 2016

CTF Writeup - Flare-On 2016 - 04: flareon2016challenge


  • Name - flareon2016challenge
  • Category - Reverse Engineering
  • Points - 4
  • Description - n/a
  • Binary - Download here

The binary for this challenge is a dll and hence we have to do some static analysis before we decide what to do next. The library exports functions flareon2016challenge_1() all the way up to flareon2016challenge_51(). Most of them perform actions on byte_10007014 buffer and return a value. For example flareon2016challenge_7() looks like this:

signed int flareon2016challenge_7()
{
    byte_10007014[dword_10007010-- % 0x10u] -= 79;
    return 16;
}

And flareon2016challenge_47() looks like this:


signed int flareon2016challenge_47()
{
    char v0; // cl@1

    v0 = __ROL1__(byte_10007014[dword_10007010 % 0x10u], 4);
    byte_10007014[dword_10007010-- % 0x10u] = v0;
    return 20;
}


If we chain the return values we get the following: 30 -> 15 -> 42 -> 18 -> ... -> 35 -> 1 -> 51. The only 2 exported functions which are not part of this chain are flareon2016challenge_49() and flareon2016challenge50(). These will come into play later. Lets see what happens when we call the functions in the chain using the C program below:

int main(int argc, char* argv[])
{
    FARPROC func;

    HINSTANCE dllHandle = LoadLibraryA("flareon2016challenge.dll");
 
    if (dllHandle == NULL)
        return 0;
 
    // Start from function 30
    int next_func = 30;

    // Go through chain of functions
    while (1)
    {
        printf("Calling function %d\r\n", next_func);
        func = GetProcAddress(dllHandle, next_func);
        next_func = func();
        if (next_func == 51)
        {
            printf("Calling function %d\r\n", next_func);
            func = GetProcAddress(dllHandle, next_func);
            func();
            break;
        }

    printf("Press Any Key to Continue\n");
    getchar();
    return 0;
}


The first thing we notice is the following:


The most important thing though happens in the function which is called at the end, namely flareon2016challenge_51():

int flareon2016challenge_51()
{
    char v1; // [sp+0h] [bp-90h]@1

    sub_10001530(16);
    sub_10001000((int)&v1, (int)&unk_10007060, (int)&unk_10007060, 6672);
    return printf(aPlayMeASongHav);
}

Each of the functions listed above operate on a buffer which, after our program ends, looks like this in memory:


Copy the bytes into a hex editor, construct the PE file locally and open it in IDA. The main function only has the following:


int __cdecl main(int argc, const char **argv, const char **envp)
{
    Beep(0x1B8u, 0x1F4u);
    Beep(0x1B8u, 0x1F4u);
    Beep(0x1B8u, 0x1F4u);
    Beep(0x15Du, 0x15Eu);
    Beep(0x20Bu, 0x96u);
    Beep(0x1B8u, 0x1F4u);
    Beep(0x15Du, 0x15Eu);
    Beep(0x20Bu, 0x96u);
    Beep(0x1B8u, 0x3E8u);
    Beep(0x293u, 0x1F4u);
    Beep(0x293u, 0x1F4u);
    Beep(0x293u, 0x1F4u);
    Beep(0x2BAu, 0x15Eu);
    Beep(0x20Bu, 0x96u);
    Beep(0x19Fu, 0x1F4u);
    Beep(0x15Du, 0x15Eu);
    Beep(0x20Bu, 0x96u);
    Beep(0x1B8u, 0x3E8u);
    return 0;
}


Running the binary plays Darth Vader's theme. Interesting!

Let's look at flareon2016challenge_50():

int __cdecl flareon2016challenge_50(DWORD dwFreq, DWORD dwDuration)
{
    int result; // eax@1

    Beep(dwFreq, dwDuration);
    byte_10007028[dword_10008DD4] -= dwFreq;
    byte_10007028[dword_10008DD4] ^= dwDuration;
    result = dword_10008DD4++ + 1;
    if ( dword_10008DD4 == 18 )
        result = flareon2016challenge_49();
    return result;
}

The function accepts 2 variables: dwFreq and dwDuration, just like the Beep() function in the extracted PE. Let's feed these into this function using the following program:

int main(int argc, char* argv[])
{
    FARPROC func;

    HINSTANCE dllHandle = LoadLibraryA("flareon2016challenge.dll");
 
    if (dllHandle == NULL)
        return 0;

    // call flareon2016challenge_50 18 times for Darth Vader song
    func = GetProcAddress(dllHandle, 50);
 
    func(440, 500);
    func(440, 500);
    func(440, 500);
    func(349, 350);
    func(523, 150);
    func(440, 500);
    func(349, 350);
    func(523, 150);
    func(440, 1000);
    func(659, 500);
    func(659, 500);
    func(659, 500);
    func(698, 350);
    func(523, 150);
    func(415, 500);
    func(349, 350);
    func(523, 150);
    func(440, 1000);

    printf("Press Any Key to Continue\n");
    getchar();
    return 0;
}

After Darth Vader's theme we get:

Command Prompt
C:\>solver.exe f0ll0w_t3h_3xp0rts@flare-on.com Press Any Key to Continue _

No comments:

Post a Comment