Skip to content

Instantly share code, notes, and snippets.

@davleop
Created May 13, 2024 00:09
Show Gist options
  • Save davleop/c1e29a9369126ac48632d0afa1228284 to your computer and use it in GitHub Desktop.
Save davleop/c1e29a9369126ac48632d0afa1228284 to your computer and use it in GitHub Desktop.
Write-up of TBTL CTF 2024 - RE: Flagcheck (100)

Here we are given a file chall which is a Linux executable; so we can throw it into Ghidra and checkout what it's doing.

image

Here in the main function, we see that the program expects a user input of length 63 and calculates some number to set as the random seed. Next we have this more interesting section where we are validating against a data field, target. The critical piece of code here is: ((int)cVar1 ^ iVar2 % 0x100) != *(uint *)(target + (long)local_6c * 4).

Here, we see cVar1 is a character of our user input and iVar2 is a random integer, denoted by rand(). We know that modulus (%) and exclusive or (^) are commutative, so we can use the given data in target to determine the random numbers, but first we need to extract out our data from Ghidra. I chose the simple approach of copy-pasting into my text editor and making it an integer array in my C program:

From this: (notice the length!) image

to this:

int target[] = {0x33,0x84,0x3D,0x3F,0x2A,0x93,0x7B,0x82,0x1A,0xAC,0x8E,0xF4,0xB1,0xCB,0x8D,0x21,0xE,0xB7,0x67,0x96,0x2C,0x81,0xD3,0xBC,0x29,0x6C,0x4B,0xD,0x0,0xED,0xFD,0xEE,0x56,0x40,0x52,0xD5,0x5,0x6D,0x90,0x3E,0x7A,0x1B,0x69,0x23,0x1F,0xB6,0x1D,0xBC,0x98,0xD1,0xA6,0x83,0xE9,0xEB,0x13,0x21,0x3D,0xF8,0x2B,0x79,0x53,0x4F,0xA1};

Then from there I wrote a C program to brute-force the seed, but it turned out to be fruitless effort because the seed was 0! I should've checked for this first, but I didn't want to assume that this was the case. So here's the program in its entirety anyways:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

void print_target_numbers(char *str, int *arr, int size) {
    printf("Outputting numbers for '%s'::", str);
    printf("[");
    for (int i = 0; i < size; i++) {
        if (i == size - 1)
            printf("%d", arr[i]);
        else
            printf("%d,", arr[i]);
    }
    puts("]\n");
}

int main() {
    int target_seed;
    int output_numbers[63];
    int target_first_numbers[5];

    int target[] = {0x33,0x84,0x3D,0x3F,0x2A,0x93,0x7B,0x82,0x1A,0xAC,0x8E,0xF4,0xB1,0xCB,0x8D,0x21,0xE,0xB7,0x67,0x96,0x2C,0x81,0xD3,0xBC,0x29,0x6C,0x4B,0xD,0x0,0xED,0xFD,0xEE,0x56,0x40,0x52,0xD5,0x5,0x6D,0x90,0x3E,0x7A,0x1B,0x69,0x23,0x1F,0xB6,0x1D,0xBC,0x98,0xD1,0xA6,0x83,0xE9,0xEB,0x13,0x21,0x3D,0xF8,0x2B,0x79,0x53,0x4F,0xA1};
    char user_input[] = "TBTL{"; // }

    for (int i = 0; i < 5; i++) {
        target_first_numbers[i] = target[i] % 0x100 ^ (int) user_input[i];
    }

    print_target_numbers(user_input, target_first_numbers, 5);

    for (int i = 0; i < 2147483647; i ++) {
        srand(i);

        int is_good = true;
        for (int x = 0; x < 5; x++) {
            int rn = rand() % 0x100;

            if (rn != target_first_numbers[x]) {
                is_good = false;
                break;
            }
        }

        if (is_good) {
            printf("Seed: %d\n\n", i);
            target_seed = i;
            break;
        }

    }

    srand(target_seed);
    for (int i = 0; i < 63; i++) {
        output_numbers[i] = rand() % 0x100;
    }
    
    print_target_numbers("Output Numbers", output_numbers, 63);

    return 0;

From there, I moved on to Python and just copy-pasted the output from the last print_target_numbers. And now that we have the random numbers, it's as simple as doing the math provided in the Ghidra output with our random numbers, 0x100, and target data fields.

Here's the quick script I wrote to solve that:

target = [0x33,0x84,0x3D,0x3F,0x2A,0x93,0x7B,0x82,0x1A,0xAC,0x8E,0xF4,0xB1,0xCB,0x8D,0x21,0xE,0xB7,0x67,0x96,0x2C,0x81,0xD3,0xBC,0x29,0x6C,0x4B,0xD,0x0,0xED,0xFD,0xEE,0x56,0x40,0x52,0xD5,0x5,0x6D,0x90,0x3E,0x7A,0x1B,0x69,0x23,0x1F,0xB6,0x1D,0xBC,0x98,0xD1,0xA6,0x83,0xE9,0xEB,0x13,0x21,0x3D,0xF8,0x2B,0x79,0x53,0x4F,0xA1]

random_numbers = [103,198,105,115,81,255,74,236,41,205,186,171,242,251,227,70,124,194,84,248,27,232,231,141,118,90,46,99,51,159,201,154,102,50,13,183,49,88,163,90,37,93,5,23,88,233,94,212,171,178,205,198,155,180,84,17,14,130,116,65,33,61,220]

output_string = ""

for i in range(len(random_numbers)):
    rn = random_numbers[i]
    tgt = target[i]
    output_string += chr(rn ^ tgt % 0x100)

print(output_string) # FLAG: TBTL{REDACTED}

And there you, the flag is printed in plain text!

@nabulator
Copy link

nice! a combination of C and python to get what you need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment