Challenge Description

After struggling to secure our secret strings for a long time, we finally figured out the solution to our problem: Make decompilation harder. It should now be impossible to figure out how our programs work!

Provided Files

$ file anti_flag
anti_flag: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b8de97bc12c627606510140e43fc13e2efffcee5, for GNU/Linux 3.2.0, stripped

Solution

Executing behindthescenes, we find that we need a password to get to the next step:

$ ./behindthescenes     
./challenge <password>

Searching for the string challenge in Ghidra, we get here:

<SNIP>
0010201b 49              ??         49h    I
0010201c 74              ??         74h    t
0010201d 7a              ??         7Ah    z
0010201e 00              ??         00h
0010201f 5f              ??         5Fh    _
00102020 30              ??         30h    0
00102021 6e              ??         6Eh    n
00102022 00              ??         00h
00102023 4c              ??         4Ch    L
00102024 79              ??         79h    y
00102025 5f              ??         5Fh    _
00102026 00              ??         00h
00102027 55              ??         55h    U
00102028 44              ??         44h    D
00102029 32              ??         32h    2
0010202a 00              ??         00h
0010202b 3e              ??         3Eh    >
0010202c 20              ??         20h     
0010202d 48              ??         48h    H
0010202e 54              ??         54h    T
0010202f 42              ??         42h    B
00102030 7b              ??         7Bh    {
00102031 25              ??         25h    %
00102032 73              ??         73h    s
00102033 7d              ??         7Dh    }
00102034 0a              ??         0Ah
00102035 00              ??         00h
<SNIP>

We can read the string Itz_0nLy_UD2> HTB{%s}, which might indicate that the string preceding > HTB{%s} is what we need to get the flag.

Using Itz_0nLy_UD2 as the password, we get the flag:

$ ./behindthescenes Itz_0nLy_UD2    
> HTB{Itz******UD2}

Alternatively, if we take a look at the main function, we find an endless loop with the invalidInstructionException(); function at the end. The corresponding assembly instruction is:

001012e6 0f 0b           UD2

The UD2 instruction is provided for software testing to explicitly generate an invalid opcode. The opcode for this instruction is reserved for this purpose.

Other than raising the invalid opcode exception, this instruction is the same as the NOP instruction.

Ghidra stops disassembling the file after the first occurrence of UD2. We can select all the ?? instructions that follow and press D to manually disassemble them. We follow by patching all the occurrences of UD2 with NOP.

After doing so, we can see that there are 4 strcmps comparing the user input with string constants "Itz", "_0n", "Ly_", "UD2", and the flag seems to be a concatenation of these constants:

<SNIP>
      iVar1 = strncmp(*(char **)(param_2 + 8),"Itz",3);
      if (iVar1 == 0) {
        iVar1 = strncmp((char *)(*(long *)(param_2 + 8) + 3),"_0n",3);
        if (iVar1 == 0) {
          iVar1 = strncmp((char *)(*(long *)(param_2 + 8) + 6),"Ly_",3);
          if (iVar1 == 0) {
            iVar1 = strncmp((char *)(*(long *)(param_2 + 8) + 9),"UD2",3);
            if (iVar1 == 0) {
              printf("> HTB{%s}\n",*(undefined8 *)(param_2 + 8));
              uVar2 = 0;
            }
<SNIP>