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
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
We can confirm the string is random by running it again, and observing an absolutely random string
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.
Address 00400919 (JZ LAB_00400925) is executed when we entered the correct “SuperSeKretKey” in the first phase, and jumps to the specified address 00400925
The function at address 00400925 accepts out input (_isoc99_scanf), moves 0x14 to EDI, and calls FUN_0040078d
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
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:
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.