UMDCTF 2018 - JarJar

This past weekend the Cyber Dawgs competed in UMDCTF and took first place :). This a writeup of one of the challenges from the CTF.

This year the reverse engineering challenges were a lot more challenging. This writeup is about the challenge "JarJar libs" (only had two solves at the end of the competition).
JarJar-solves
Challenge Binary

We are given a 64bit stripped ELF binary that is depended on a shared library named "libgcj.so.17". Without this shared library the challenge will not run.
file-details-2

With some googling we can see that the library is a "Java Runtime Library for gcc". After downloading the shared library we can use LD_PRELOAD to load the shared library.
LD_PRELOAD=./libgcj.so.17

Now we can run the program:
run-1

Ok so now we know we must figure out what input will take us down the win path. Loading the binary into IDA we can reverse engineer what the program does. What made this challenge slightly more challenging was the fact that it was a linux binary that was using Java runtime functions so it was similar to reversing a C++ binary. It uses Java functions to do basic functionality and it was a pain to set breakpoints on name mangled functions.
functions_example-1


Using gdb and IDA we can see that the program is going character by character from our input and checking them against either a hard coded value or doing math on our input and then checking to see if it matches a value.

test1
In the above block it is calling a function to get a character from our input and then checking to see if it equals "a".

test2-1
And in this block it is getting a character at another index, adds a value to it and checks to see if it is equal to 0xDB.

Reversing the first couple blocks we can figure out that the beginning of our input should equal IHazDePass-

After the program checks that your input begins with IHazDePass- it then takes everything after the - and passes it into a function that I labeled hash_function

call-hash-1

The hash_function was pretty big so I wanted to avoid reversing it as much as possible. What also made this challenge harder was the fact that the binary was using Java's String class to handle its strings. While dynamically debugging the program it would be confusing to see what strings are being used.
strings

At this point I wasn't too sure what this hashing function was doing so I decided to see what the hash that was generated was being compared to at the end. Using gdb I knew that inside the string_equal function it has to extract the hashed strings at some point.(so I do not have to reverse where the Java string object stores the string)
string_check-2
arg(1) = 1b0028845913cc1e4fc298f455d92862
arg(2) = hash dependent on input
Running it a few times I could see that arg1 is a hard coded hash and arg(2) is the result of passing your input after IHazDePass- to the hash_function mentioned above. The result of the hash function must equal 1b0028845913cc1e4fc298f455d92862.

This hash looked like a MD5 hash so my first instinct was to pass the hard coded hash into a hash cracking website.
no_luck
It could not find the hard coded hash in its database.

The next part took me longer then it should have, but it was a good learning experience.

Stepping through the hash_function I could see that it was taking the MD5 of the your input after the - and manipulating it.
blocks-1
Looking at the graph overview of this function was overwhelming as I didn't want to reverse most of the blocks for a 30 point problem. (should have been more points IMO ;) ). After desperately trying to finish this problem it finally struck me that I control what is being MD5 hashed so I can pass in my controlled data, take the true MD5 hash of that data manually and then compare what the hash_function returns. This will show me how the hash_function manipulates the hash after it has been MD5'd. After running it a few times with different inputs and then seeing the resulting hash I quickly noticed the hash_function was

  1. Taking the MD5 of the substring after -
  2. Then simply reversing that hash

Example :

  • Input: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  • True MD5: 4f1c2efbe48a8c356719ba8d650eb59a
  • hash_function:a95be056d8ab917653c8a84ebfe2c1f4

Which means we can take the reverse of the hard coded hash and that would be the valid Md5 hash of what our input should be.
Reversed hard coded hash : 26829d554f892cf4e1cc3195488200b1
Passing this into the hash cracker:
final_hash

Now appending hereitis to IHazDePass- and passing that into our program we get the flag.
win