247CTF - Easy Reversing Challenge Writeups

The More The Merrier

One byte is great. But what if you need more? Can you find the flag hidden in this binary?

Given the binary "the_more_the_merrier".

We can disassemble the main() function into:

38: int main (int argc, char **argv, char **envp);
; var char *var_8h @ rbp-0x8
0x0000063a      push rbp
0x0000063b      mov rbp, rsp
0x0000063e      sub rsp, 0x10
0x00000642      lea rax, str.247CTF_6df2[redacted]b36c ; 0x6e8
0x00000649      mov qword [var_8h], rax
0x0000064d      lea rdi, str.Nothing_to_see_here.. ; 0x78c ; const char *s
0x00000654      call puts          ; sym.imp.puts ; int puts(const char *s)
0x00000659      mov eax, 0
0x0000065e      leave
0x0000065f      ret

This translates into:

#include <stdint.h>
 
int32_t main (void) {
    char * var_8h;
    rax = "247CTF{6df2[redacted]b36c}";
    var_8h = rax;
    puts ("Nothing to see here..");
    eax = 0;
    return rax;
}

Before the puts instruction, we can see the address 0x000006e8 being stored in the rax register:

0x00000642      lea rax, str.247CTF_6df2[redacted]b36c ; 0x6e8 -> rax = "247CTF{6df2[redacted]b36c}";

If we inspect that address with, for example, a hex editor, we can see the flag is stored byte by byte there:


The Encrypted Password

You won't find the admin's secret password in this binary. We even encrypted it with a secure one-time-pad. Can you still recover the password?

Given the binary "encrypted_password"

We can disassembly the main() function into:

int32_t main (void) {
    int64_t var_a8h;
    int64_t var_a4h;
    char * s;
    int64_t var_98h;
    int64_t var_90h;
    int64_t var_88h;
    int64_t var_80h;
    char * s2;
    int64_t var_68h;
    int64_t var_60h;
    int64_t var_58h;
    int64_t var_50h;
    char * s1;
    int64_t canary;
    rax = *(fs:0x28);
    canary = *(fs:0x28);
    eax = 0;
    rax = 0x3930343965353738;
    rdx = 0x3861623131383966;
    s = rax;
    var_98h = rdx;
    rax = 0x3665656562303635;
    rdx = 0x3264373763306266;
    var_90h = rax;
    var_88h = rdx;
    var_80h = 0;
    rax = *(0x00000a88);
    rdx = *(0x00000a90);
    s2 = rax;
    var_68h = rdx;
    rax = *(0x00000a98);
    rdx = *(0x00000aa0);
    var_60h = rax;
    var_58h = rdx;
    eax = *(0x00000aa8);
    var_50h = al;
    var_a8h = 0;
    while (rbx < rax) {
        eax = var_a8h;
        rax = (int64_t) eax;
        edx = *((rbp + rax - 0x70));
        eax = var_a8h;
        rax = (int64_t) eax;
        eax = *((rbp + rax - 0xa0));
        edx ^= eax;
        eax = var_a8h;
        rax = (int64_t) eax;
        *((rbp + rax - 0x70)) = dl;
        var_a8h++;
        eax = var_a8h;
        rbx = (int64_t) eax;
        rax = &s;
        rdi = rax;
        rax = strlen ();
    }
    puts ("Enter the secret password:");
    rax = &s1;
    fgets (rax, 0x21, *(stdin));
    rdx = &s2;
    rax = &s1;
    eax = strcmp (rax, rdx);
    if (eax == 0) {
        rax = &s2;
        rsi = rax;
        eax = 0;
        printf ("You found the flag!\n247CTF{%s}\n");
    }
    var_a4h = 0;
    while (rbx < rax) {
        eax = var_a4h;
        rax = (int64_t) eax;
        *((rbp + rax - 0x70)) = 0;
        var_a4h++;
        eax = var_a4h;
        rbx = (int64_t) eax;
        rax = &s;
        rdi = rax;
        rax = strlen ();
    }
    eax = 0;
    rcx = canary;
    rcx ^= *(fs:0x28);
    if (rbx != rax) {
        stack_chk_fail ();
    }
    return rax;
}

This seems harder than it really is, basically, we have to focus on the following lines:

[... snip ...]

    puts ("Enter the secret password:");
    rax = &s1;
    fgets (rax, 0x21, *(stdin));
    rdx = &s2;
    rax = &s1;
    eax = strcmp (rax, rdx);
    if (eax == 0) {
        rax = &s2;
        rsi = rax;
        eax = 0;
        printf ("You found the flag!\n247CTF{%s}\n");
    }

[... snip ...]

The goal is to find a rax value submitted through the fgets stdin instruction that matches the rdx register, if so, the flag is returned to us; the comparison is being done with strcmp, which is being saved into the eax register, and we know the strings are equal if the returned value is 0.

Running ltrace against the binary and submitting a random value as test, shows us our string is being compared with an MD5-like hash:

If we run the "encrypted_password" binary with that hash, the flag is returned to us.