RE Series #1: HTB Impossible Password

In my earlier post, I said was going to focus deeply into one subject each quarter of this year, so that at the end of the year, I would have 4 more above average skillsets to add to my arsenal (not mastery within such a short period of time). This quarter, I decided to work deeply into RE and patching of binaries. This would include both static and dynamic analysis, and I would anticipate myself to learn tools like IDA, Ghidra, Radare2 and Ollydbg.

In this first post, we’ll start with a relatively easy one from HTB called Impossible Password. Lets begin!

First Stage: ltrace

We run the binary using ltrace to see what sort of functions the binary is calling behind the scenes

The answer is reveal immediately!

Keying in a random string “aaaaa”, we see that it compares itself to “SuperSeKretKey”, so we try to key that instead. Pretty straight forward!

Second Stage: Static Analysis and Patching

In the second stage, we are prompted for another input again, and entering random inputs, we see that it does a string compare against a random looking string

Absolute gibberish string comparison

We can confirm the string is random by running it again, and observing an absolutely random string

Another random string at the bottom

We further analyze the binary by opening it In Ghidra. We search for the strings, and find that “SuperSeKretKey” is declared and referenced. By navigating to the function the referenced it, we see the control flow of the program.

SuperSeKretKey in Strings Definitions within the binary
Finding address that reference the string leads us to the control flow

Address 00400919 (JZ LAB_00400925) is executed when we entered the correct “SuperSeKretKey” in the first phase, and jumps to the specified address 00400925

Function at 0x00400925

The function at address 00400925 accepts out input (_isoc99_scanf), moves 0x14 to EDI, and calls FUN_0040078d

Function at 0x0040078d

This function calls “time” at 004007b3, and subsequently calls “srand” at 004007d9. We can roughly infer that it takes the current time value, and calls srand to generate the bunch of random strings we saw earlier in Phase 2. This tells us that we likely can’t find the correct string by brute forcing or guessing, as the probability of getting the correct string would be incredibly low.

The next best option, and smarter way around brute forcing, is to patch the binary.

We circle back to the function at 0x00400925, and see that it calls strcmp, and jumps to 0x00400976 if the strings are not equal (strcmp returns 0 if strings are equal, and non-zero is they are different). Knowing that our guesses are very likely to be different from the randomly generated string, we can patch the binary to JZ instead of JNZ

JNZ jumps if the strings are not the same, which is highly likely
JZ jumps if the strings are the same, which is very unlikely.

Changing it to JZ allows the program to flow down the other control path. We save the binary by running this script, as Ghidra has some issues with saving patched binaries:

https://github.com/schlafwandler/ghidra_SavePatch

Simply follow the instructions there to create the SaveFile.py script, and highlight the patched code to save the binary.

Now we try running the binary again, and we should easily get the flag.

We entered the string “blah” and got the flag, which is censored in blue at the bottom

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: