Q's blog

Home About me

Hackthebox - FlagCasino Writeup

This challenge mark the start of my effort on understanding exploit/malware development and uh... Honestly I don't know the name of what I want to learn specifically. A simple challenge with high rating and Very Easy difficulty. Since I'm new to this I read some walkthrough and try to understand as best of what's going on. First step you should download the challenge file.

challenge-file

So supposedly there are a lot of reversing/decompiler tools on the net. GCC and such, but I chose to use ghidra* since it seems the most script kiddy one to use.

decompile

Source code in text:

undefined8 main(void)

{
    int iVar1;
    char local_d;
    uint local_c;

    puts("[ ** WELCOME TO ROBO CASINO **]");
    puts(
        "     ,     ,\n    (\\____/)\n     (_oo_)\n       (O)\n     __||__    \\)\n  []/______\\[] /\n   / \\______/ \\/\n /    /__\\\n(\\   /____\\\n---------------------"
        );
    puts("[*** PLEASE PLACE YOUR BETS ***]");
    local_c = 0;
    while( true ) {
    if (0x1d < local_c) {
        puts("[ ** HOUSE BALANCE $0 - PLEASE COME BACK LATER ** ]");
        return 0;
    }
    printf("> ");
    iVar1 = __isoc99_scanf(&DAT_001020fc,&local_d);
    if (iVar1 != 1) break;
    srand((int)local_d);
    iVar1 = rand();
    if (iVar1 != *(int *)(check + (long)(int)local_c * 4)) {
        puts("[ * INCORRECT * ]");
        puts("[ *** ACTIVATING SECURITY SYSTEM - PLEASE VACATE *** ]");
                    /* WARNING: Subroutine does not return */
        exit(-2);
    }
    puts("[ * CORRECT *]");
    local_c = local_c + 1;
    }
                    /* WARNING: Subroutine does not return */
    exit(-1);
}
            

Let's break this down slowly and forget all the fluff code. Focus on the meat and bread of this code, we see

while( true ) {
        if (0x1d < local_c) {
This means that the application (read the flag length) will be 29 since 0x1d in decimal is 29.

Next we talk about the following snippet.

    iVar1 = __isoc99_scanf(&DAT_001020fc,&local_d);
    if (iVar1 != 1) break;
    srand((int)local_d);
    iVar1 = rand();
This snippet is about reading user input into local_d, set a random seed using our input (srand), then make a random value. Although this random value is not really random since we set the seed using srand*.

The biggest prize of this code is on this part.

    if (iVar1 != *(int *)(check + (long)(int)local_c * 4)) {
This part reads as if our input (rand-ed) is not the same as long(check + local_c * 4) {Let's dub this value as flag[index]} where check is an internal value and local_c is the counter. FlagCasino will stop running. In theory the "easiest" way to break this rev challenge and gain the flag is to brute-force the flag using alphanum + symbolic values.

Since I'm new to this kind challenge, and how the flagcasino is served to me. I thought I can only input numerical value. But when I tried to input standard HTB flag something clicked. The application actually going to continue char-by-char of the flag illustrated below.

input-test

With all of these observation known, I still don't know how to break this challenge. I don't want to brute force the answer either since it might take forever. After looking at a walkthrough though I understood that instead of trying to guess each instance of flag[index], we could practically instead map every char in uint8 range (because local_c is uint) as an srand seed and then randomize it. Now with this dictionary[random(seed=key)] = char[key] we could then use flagcasino check value to calculate the result of each index as val. We then can get dictionary[val] value which practically give us the flag.

Using python3 pwntools, we can make the following code to gain the flag.

from pwn import *
import ctypes

libc = ctypes.CDLL('libc.so.6')
dictionary = {}
flag = ""

for key in range(255):
    libc.srand(key)
    dictionary[libc.rand()] = chr(key)

casino = ELF("./rev_flagcasino/casino", checksec=False)
for local_c in range(30):
    val = casino.u32(casino.sym["check"] + local_c * 4)
    libc.srand(val)
    flag += dictionary[val]
print(flag)
  1. Ghidra
  2. Srand on C
  3. uint8
  4. uint8 to char
  5. pwntools