Hacking Series Part 13
Challenge: OTP Implementation
Category: reverse engineering
We are given a binary called “otp” and a text file called “flag.txt”. If you execute otp, you will notice that you need to pass a key as an argument in order for the program to run. When I opened otp in IDA, I saw that this key is scrambled with unknown logic, then compared to another string. If these strings match, the program prints “You got the key, congrats! Now xor it with the flag!”
This indicates that flag.txt does not contain any part of the actual flag, and finding the key is likely the only way to get the flag. If you look at how the key is scrambled, you see that there is a function named
jumble that is responsible for this, as well as multiple
sub instructions afterward.
This means that trying to reverse
jumble would probably take too much time, and there is likely an easier way of finding the original key. Before jumble is called, there is a function called
valid_char, which makes sure each character in the passed key is between a range of characters or numbers. Figuring out this range is important, since all other characters immediately invalidate the key, which makes the program exit.
In order for a character to be “valid” the function must return 1. If you look into
valid_char, you see that there are two cases where the function returns 1, and one where it returns 0.
This is where the range of the characters allowed is determined. One case where the function returns 1 is if the character is greater than “/” and less than or equal to “9”. Another case where the function returns 1 is if the character is greater than “`" and less than or equal to “f”. In other words, the characters need to be in the range of 0–9 or a-f. This indicates that the key is a hex value.
It is also important to note that the key needs to be exactly 100 characters, or the program will immediately exit as well, as shown in the following
If you continue to look through the assembly, you will see that after the key is scrambled, it must equal the following string starting with “bajbg…”, which is being passed to
Now that we know these important pieces of information, we can try to automate the task of figuring the key out letter by letter. Since the key is only 100 characters long, this is an effective method and shouldn’t take too long. We can do this by using a Python script with gdb.
We first have to place a breakpoint in a place where we can access the scrambled key, or
rbp+string_compared in the above image. The easiest place to do this would be at the
strncmp call, then access the memory location in
rax, since that is where the scrambled key would be stored. We would then need to compare every valid character from our defined range to the string shown in the assembly.
If the first character in our scrambled key matches the first character in the string shown in the assembly, we add the value we used to the key. This should be a loop that repeats 100 times.
I made the following Python script to demonstrate this process, it can be run with gdb using the command
gdb -q -x script.py .
At the end, it prints a 100 character key. In order to make sure I got the right key, I ran it with otp.
It prints the correct message, which means I got the correct key. It then says to xor it with the flag, which I assume means the string found in flag.txt. The xor operation would use the following values:
The correct flag would be the result.