Will find Flags for Food: Reversing with Ghidra: Part II

I am an experienced Vulnerability Researcher and Security Architect with 16+ years of experience in various verticals and horizontals, be it consumer electronics, semiconductors, automotive or other. Having started in software engineer in low-level embedded devices from writing applications to kernel drivers on various operating systems and then moving to my real calling i.e. hacking. Love to stick to the older golden days of game hacking, BBS, shareware, phreaking, phrack, virus era, metal music, cheats and many more such cool stuff from the underground. I wear many hats from time to time as necessary - but I also love to help people and organizations to deal with the core cybersecurity issues and not provide them a checklist with a presentation. Opinions and posts on my site are purely my own and do not reflect my work.
This one was special after my previous binary challenge for another company as I had some idea into how binary challenges work for potential employers. For this particular company there were 4 challenges – Out of which the first one was a binary reversing to find hidden flag that was supposed to be used for the next challenge.
I will not be releasing this binary although this was 5-6 years ago – This company is doing crazy work in Side Channel Attacks and Tools and is very successfull. Unfortunately, I could not complete the entire challenge for this company.
To Identify a Secret-Flag that would be uncovered if we:
Either Find the Key and then run the binary with that Key on an ARM board
Use the found Key to further go ahead and uncover the Secret Flag just by reversing the encryption, xor algorithm from the binary
Approaches used:
Static Analysis
GDB and IDA Pro
GHIDRA (Released 5th March)
Static Analysis: – Initially I tried some simple static analysis like strings

The first order or business from this output is to make a rough picture of what possibly the code is doing.
These suggest the strings printed from functions like printf, stderr etc.

Code exits abruptly from somewhere
Puts probably puts something to stdout
Putchar probably puts some character somewhere
Abort like aborts the program
Printf prints something
Strlen calculates string length, maybe for inputted string.
Stderr writes error to console
Fwrite write something to some stream
Combining this with dynamic analysis would get us to conclude on a few more things:

program accepts argument from command line, prints usage.
Exits is key length or input is less than or greater than 9, which probably would be the key length. (Concluded after editing code from GHIDRA)
After this I tried to follow assembly and dynamic analysis in GDB, but it was moving slow. As I am a regular follower of NSA, I was eyeing for their GHIDRA release, which happened at the right time the challenge was shared with me around 25th March, and I could start working on it only on 31st March. So I shifted to GHIDRA as it has an inbuilt decompiler, which other reverse engineering tools din’t have or are too expensive for me. Took me a few hours to start on with the GHIDRA journey, saw a few videos by LiveOverflow and John Hammond to get started, and viola. Below is the first screenshot from GHIDRA

I edited some of the code like function signatures, variable types etc. to make the code look more C, which it was already and exported the code to a bin100.c file.


It is clear from this the code expects a Key length that is equal to 9 or it exits with wrong length. I recompiled the code saved from GHIDRA on X86 go get this out and speed up the process.
Now it is clear that we need to bypass all the conditions correctly for the given if conditions mentioned above for the challenge to go inside the while loop and generate the secret flag or something.
I tried to comment out rest of the code and enabled only specific code for the current condition being tested for validity.
Logic:
The array for Key is used as a vector sent in from command line for comparing with important conditions for password generation.
For example: if we enter “ABCDEFGHI” as the key then it is represented as below.

Now according to the code the important conditions are: ((argv[1][1] * (*argv[1]) != 0x1353)compare argv[1][1] multiplied by argv[1][0] with 0x1353 (Hex) So we need to look for 2 Characters whose multiplication is 0x1353(hex) or decimal **4947. **Now we form the equation for it (x * y = 4947), hence we need to find two factors of 4947 We use https://www.calculatorsoup.com/calculators/math/factors.php to do it faster.

We see that 4947 decimal has 4 factors out of which 51 and 97 fall under the printable ascii characters i.e 51 decimal is “3’ as char and 97 decimal is “a”, So these two must be the first two characters of our keygen.
Lets try to bypass the first condition with this. We comment out the rest of the code from the complete source and just keep the first conditions.

Now we are sure that first two characters of the keygen are either “3a” or “a3” Let us move on with other such conditions:
(argv[1][3] * argv[1][2] != 0x365b) compares argv[1][3] multiplied by argv[1][2] with 0x365b (Hex) So we need to look for 2 Characters whose multiplication is 0x365b(hex) or decimal **13915. **Now we form the equation for it (x * y = 13915), hence we need to find two factors of 13915

Only 115 and 121 have corresponding characters that are printable. 115 = “s” and 121 = “y” So the 3rd and 4th characters of our keygen are either “sy” or “ys”

Similarly we solve for other conditions from the code. (argv[1][5] * argv[1][4] != 0x1650) compares argv[1][4] multiplied by argv[1][5] with 0x1650 (Hex) Therefore, we need to look for two Characters whose multiplication is 0x1650(hex) or decimal **13915. **Now we form the equation for it (x * y = 5712), hence we need to find two factors of 5712
0x1650 (a[1][4] and a[1][5]) = 5712 48 × 119 = 5,712 = “0w” or “w0” 51 × 112 = 5,712 = 3p, 56 × 102 = 5,712 = 8f 68×84=5,712 =DT

Here we have multiple factors that have printable characters hence we cannot select one of the pair, so we check the next conditions. (argv[1][8] != ‘y’) – is straightforward.

And we are not sure about 1,4 and 1,5 as of yet. (argv[1][7] * argv[1][6] != 0x2b93) 0x2b93 (a[1][6] and a[1][7]) = 11155 97 × 115 = 11,155 = “as”

Now we need to solve other remaining conditions to finalize the key array.
((char)(argv[1][5] – argv[1][6]) != -0x2e) compares argv[1][5] subtracted by argv[1][6] resulting into negative 0x2e (Hex) which is -46
Therefore, we need to look for two Characters whose subtraction is negative 0x2e(hex) or decimal **-46. **Now we form the equation for it (x – y = -46), hence we need to find two numbers whose diff is -46. We already have y = either 115 or 97, so we form two equations X = 115 – 46 = 69 = E or X = 97 – 46 = 51 = 3
Hence argv[1][5] could be either 3 or E, but we have argv[1][4] and argv[1][5] as either “0w”, “w0” , “3p”, “8f”, “DT”, so by correlating these two, we can be sure that argv[1][5] will be “3p” or “p3”
One last condition remains now, ((char)(argv[1][3] – argv[1][4]) != ‘\t’) here we already have argv[1][3] but do not have argv[1][4] By applying similar logic to above, the hex for ‘\t’ escape sequence is TAB or decimal 9.
Hence the final array is

Alternatively, the Key is “3asyP3asy” – looks similar to “easypeasy”.
We would have brute forced this after decoding first few conditions, and then we would have acquired the key. I also tried this and arrived at the key before decoding all conditions.
Finding the Flag:
We must move ahead and must find the flag.

This code takes the argv array with length 9, and creates an MD5sum for “3asyp3asy” as 8c0821ad65f6dbfe2fb0e26915009975

From the while loop above, every character of the md5 hash is XOR’ed with a fixed string from the code in the data section, i.e fb3c52c311a9af964ec4bd5a7473e04a

As seen in this above diagram in .bss section putchar((uint)(local_buffer[local_c] ^ (&DAT_00010c34)[local_c]));
Once the while loop finishes, it according to the above condition inserts the XOR’ed value of the md5 hash with the .bss section value(let’s call it xorkey)
“xorkey” XOR “md5hash_of_3asyP3asy” = 8c0821ad65f6dbfe2fb0e26915009975 exor fb3c52c311a9af964ec4bd5a7473e04a = 7734736e745f746861745f336173793f

7734736e745f746861745f336173793f == Just by looking at this string, it appears to be in hex, so we convert it to ascii and acquire the flag that was requested for this challenge.

Secret Flag = w4snt_that_3asy?
The cool thing about this challenge was that it used a prime number factoring logic as the core logic for reversing the secret code. There are other simple ways also to solve this challenge but I found the prime factoring to be used quite interesting at the time – as this company strongly deals with cryptography and its application, it made sense for them to use something from that bucket here.




