Post

BASEic (SunshineCTF 2025)

BASEic (SunshineCTF 2025)

Steps:

  1. Read the binary in Ghidra and locate the flag check in FUN_001014d1.
  2. Notice it base64 encodes your input with a custom routine and compares against a hardcoded prefix plus a trailing chunk stored in .rodata.
  3. Concatenate the two base64 strings to get the full target base64 of the correct input.
  4. Base64 decode that target to recover the flag.
  5. Optionally verify by re-encoding the recovered flag and comparing.

Detailed Explanation

We are given an x86_64 ELF. The interesting function is the programs entry’s target, which Ghidra names FUN_001014d1. Here is some relevant logic:

Seeds a buffer with a literal from .rodata

1
builtin_strncpy(local_56, "yX0I0NTM1fQ==", 0x0e);

It asks for input and appends it after those 14 bytes:

1
2
printf("What is the flag> ");
scanf("%s", local_56 + 0xe);

It requires raw input to be 0x16 bytes:

1
if (strlen(local_56 + 0xe) == 0x16){...}

it then base64 encodes only the input using the function at FUN_001012c6:

1
2
size_t n = strlen(local_56 + 0xe);
char *b64 = FUN_001012c6(local_56 + 0xe, n); 

Then the result is checked in two parts:

1
2
3
4
5
6
if (strncmp(b64, "c3Vue2MwdjNyMW5nX3V", 0x13) == 0) {
    size_t m = strlen(local_56);               
    if (strncmp(b64 + 0x13, local_56, m) == 0) {
        puts("You got it, submit the flag!");
    }
}

From these two checks we learn that the correct input must be:

1
"c3Vue2MwdjNyMW5nX3V" + "yX0I0NTM1fQ==" = c3Vue2MwdjNyMW5nX3VyX0I0NTM1fQ==

When we base64 decode the string we get the plaintext flag:
flag: sun{c0v3r1ng_ur_B4535}

This post is licensed under CC BY 4.0 by the author.