Don't argue with me

Aperi'CTF 2019 - Reverse (150 pts).

Aperi’CTF 2019 - Don’t argue with me

Challenge details

Event Challenge Category Points Solves
Aperi’CTF 2019 Don’t argue with me Reverse 150 11

We’re given an ELF chall file.

Task description:

One of your fellow players has designed a binary protection system based on a technique he claims to be very powerful.

Prove him wrong.

Let’s analyze this binary using Ghidra!

Reverse engineering

First, create a new non-shared project and import the ELF chall file. If the tool association is correctly configured, double clicking on the chall file should open it in the CodeBrowser.

We’re invited to start the binary analysis, the default settings are quite sufficient, let’s just run it and wait for a few seconds.

Searching for the entry point of our program using the Functions panel ([Windows] > Functions), we quickly identify the main function which is quite difficult to understand, but essentially contains comparisons on a table of bytes that we can assume is the flag:

ghidra

Exploitation

Using the decompiled code, we can retrieve all the comparisons and pass them to a solver that will list all the possible values for these tests.

z3 is an equation solver developed by Microsoft that outputs possible inputs that meets certain constraints.

The exploitation can be automated, but requires some time to implement C code analysis and constraint extraction. We’re not going through all the steps of the implementation of the extraction part here.

After retrieving all the equations, we can add them in z3 and specify some additional constraints.

To make the z3 output as effective as possible, we can add strict comparison to the known digits:

solver.add(flag[0] == ord('A'))
solver.add(flag[1] == ord('P'))
solver.add(flag[2] == ord('R'))
solver.add(flag[3] == ord('K'))
solver.add(flag[4] == ord('{'))
solver.add(flag[-1] == ord('}'))

Then we can run the z3 solver!

Output:

APRK{Did_u_thought_that_it_would_be_easy_without_scripting?}

Additionally, after some analysis, we find that the flag is picked up from the argv[0], which corresponds to the name of our binary file.

To change this value, we can either rename the program or use a wrapper to change this value when calling:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char ** argv) {
    char *args[] = {"APRK{Did_u_thought_that_it_would_be_easy_without_scripting?}", (char*) NULL};

    execv("./chall", args);

    return EXIT_SUCCESS;
}

Output:

Well done ! You validated this challenge !

The final flag is APRK{Did_u_thought_that_it_would_be_easy_without_scripting?}

Happy Hacking!

Creased & Areizen