Level4, time for some crypto and reverse engineering.. Level 4 is a binary which decrypts encrypted files with a password, and of course an example binary and password are given. Putting some random data in a file and trying to decrypt that results in a message that the file is invalid or corrupt. This suggests that the binary has some kind of checksum algorithm to detect if the file is valid. Let’s take a closer look at the binary..
Above is the decompiled, cleaned up fuction that is responsible for reading and decrypting the file and printing the decrypted contents. The function does the following:
- Read the file and store a pointer to filedata and size in a struct
- Do initial checksum over file data
- Decrypt file with password (Xcrypt, symmetric encryption)
- Do checksum over decrypted data
- Print decrypted data
Ok, now we have a better understanding what the binary exactly does.. And now? Well.. The above function has a buffer overflow vulnerability. It decrypts the file data and than copies the decrypted contents to a static buffer(4096 bytes). To exploit this vulnerability we have to write the “encrypter” that writes an encrypted file bigger than 4096 bytes.. We have to match the format that the decrypter application expects. The format can be identified by looking at what the decrypt function exactly does. But for the lazy, here is a picture:
Time to start coding! Because the binary uses a symmetric encryption algorithm we can just copy the decompiled xcrypt function to our encryption program. Also the crc32 checksum function can be “borrowed” from the decrypter. I started rebuilding the decrypter application, making sure everything was working correctly by comparing output of the decrypted data. Once that was in place it was pretty easy to build the encryption program. I eventually ended up with this program:
Now we got our encryption program, time to exploit that buffer overflow! I started inputting MSF patterns to determine which registers we control and where the exact location in the buffer is where we overwrite the return address. I determined that we control the following registers:
- EBP: buffer
- ESP: points to buffer
- EIP: buffer
As the binary is statically compiled with NX(Non executable stack) a ROP chain is again the solution. I started up ropeme as usual and noticed all the ROP gadgets I used in level 3 to do my syscall were also present in this binary (on a different address though). I than copied most of my payload for level 3, corrected the ROP gadget addresses and wham! We got a shell!
Nice! Really enjoyed this one! This is my python script for generating the malicious data to encrypt: