This challenge was part of the NorthSec 2020 CTF. In this challenge, a zip file was provided. In this zip file, we found three files. A jar file, a .so file and a .sh file. The .sh file was only to run the jar file without any additional argument.
The first step for me, was to load the jar file inside the famous Java Decompiler JD-Gui. We can see that the jar file contains 4 classes.
We can immediately see a FLAG in the Main class
FLAG-81ffbd94e51df117e74f unsurprisingly this flag is only worth 1 pt. However, we see that there is a secret place we need to access. There is probably another flag there.
In the Bootstrap class, we see that it will attempt to load the Validator.class. It will do so by removing the “I” from the IValidator class. This way, the class will not be loaded directly in memory at runtime by the JVM. It will go through the .so file before being loaded. This file uses the JNI feature of Java which allows binaries to be executed instead of Java byte code. No password is provided to the JNI function, this means that the file Validator.class will be loaded every time in memory even if an incorrect flag is entered. I have attempted to decompile the Validator class. However this file was not a valid class file. We can check this using the first 4 bytes of the file. Any valid .class file must start with the magic number
CAFE BABE. The file did not start with the magic number. We can assume that the
Validator.class is encrypted and contains the flag or the logic to compute the correct flag.
Every time I had to deal with encrypted .class, I usually use the same approach. Instead of trying to reverse engineer the decryption, I let the computer do the work for me. Once the classes are decrypted, they are stored in memory. I can now do a memory dump of the java process and extract the classes from memory. In order to dump the memory at the correct time, I have recompiled the main and added a ReadLine to wait for user input just after the
IValidator validator = Bootstrap.<IValidator>get(IValidator.class); line.
Once the program enters this state, I can be sure that the class is loaded in memory and is no longer encrypted. I can now extract the memory using the command
gcore PID -o dump.bin
The classes can be extracted using a small C++ program that I made a while back. I have used C++ because memory dumps can be quite large and C++ have the speed advantage over an interpreted language like Python.
We end up with a lot of classes in the
out/ folder. These classes can be decrypted using FernFlower. Once they are decrypted a simple
grep can help us locate the file in question using the name of the class. This method has a drawback that a lot of classes will be decrypted including the ones from the standard library. This can take quite some time if the program is fairly large. In this case, it took less than two minutes. The source code of the Validator.class is available below.
The remaining step is to compute a valid flag. In the code, we can clearly see that the flag needs to be 25 characters long including the “FLAG-” part. We can also see that the flag is validated using substrings of two characters. It is validated using its hash code. Since we know that the flag is composed of letters between “a” and “f” and numbers between 0 and 9, we can compute every possibility in a list and slowly rebuild the flag. The code bellow was used to compute this list.
With the help of the list, the hash code could be matched with the corresponding string. Those strings were appended to get the
FLAG-96267a509dbfe7e113bc. This flag was worth 3 pt.