NDH 2018 - Diablo, fighting Lazarus…
Event | Challenge | Category | Points | Solves |
---|---|---|---|---|
Nuit du hack 16 | Diablo, fighting Lazarus… | Reverse | 150 | 1 (Forever Alone) |
Description
This is the second part of the Diablo CrackMe series. This challenge is about reversing some Web Assembly to retrieve the correct value to be passed as an attack.
TL;DR
Dump the strings using the browser, decompile with WABT and search for the function that prints the correct win message. By single stepping through it I realised that it’s a simple XOR done in 3 rounds. Same as xoring with a 3 letter long key.
Run it
I started by renaming the given HTML file to index.html. Then I went inside the directory with all the challenge files and started my own server with python :
python -m SimpleHTTPServer
Now when going to localhost:8000 and opening the developer tools -> sources, I could see something like this after having refreshed :
All the WASM functions have successfully been loaded and can now be debugged with the builtin debugger :) I then tried a random password to see what answer I’ll get.
Dump the strings
Now I wanted to see if the flag was not simply stored as plaintext inside the memory, therefore I dumped the strings unsing the browser console :
for (i = 0; i < 2000; i++) {console.log(i, UTF8ToString(i))}
The flag wasn’t there unfortunately but I still got some useful results :
Now I know that the win message is located at 1597 and the one I got earlier is at 1508.
Decompile
I searched for references to those strings inside the decompiled source. For that I used WABT.
I found references of the strings from earlier in the _Attack function :
I must now identify this function inside the browser and this is a tedious task because there are no debugging symbols.
After a while, I could identify the 21st function as being the right one.
Breakpoints
I put a breakpoint at the beginning of this function so that I could do dynamic analysis. By single stepping through the function I realized that a first check is made on the length of the password. The password must be 27 chars long so I chose to input “ABCDEFGHIJKLMNOPQRSTUVWXYZa”
After that, the application does a bunch of work on memory but if I try to access it while debugging, it fails ! I can’t dump the memory while the application is working :(
I continued single stepping until I entered a loop.
In this loop, the first char of the password is xored with the constant 35.
Then this result is compared to 110.
Now I know that the first char of the password is 35^110 = 77 = “M”.
At the next iteration, surprinsingly, it’s not the second letter that is xored but the fourth one (“D”). It skips 2 letter each time and loops 9 times.
By repeating the same process as before, I found the partial flag:
M??1??r??S??4??_??k??4??a??
At this point it was clear to me what was going on, I should encounter 2 loops after this one and that’s exactly what happened. :)
Each following loop did the same but with a different key, which is the same as xoring the entire password with a 3 letter key.
For the curious, the XOR key was “#fB”
Flag
In the end, the password was M4g1karP_SPl4sh_l1ke_4ttacK
And hence the flag:
ndh2k18_M4g1karP_SPl4sh_l1ke_4ttacK
ENOENT