I had a bit of free time to listen in on PancakesCon over the weekend and participated in the CTF. I didnt place very well, but I was the only one to solve the reversing challenge, so I thought Id write it up. The challenge tells us we need to enter a password and has a link to a page.
Clicking the link brings us to a web page with an input box to enter a password and a ‘Check’ button.
Looking at the html source, we can see a reference to wasm_exec.js and below that a reference to wasm.wasm.
The wasm_exec.js looked mostly uninteresting. The interesting bits are in the wasm.wasm file. Wasm is the WebAssembly binary file format. I used https://webassembly.github.io/wabt/doc/wasm-decompile.1.html to decompile the .wasm file into a readable C-like syntax.
Looking through the decompiled .wasm for interesting functions there is one named ‘runtime_run_1_gowrapper’
Digging through this function, there is a snippet that looks interesting.
Figure 5: String compare operations
This looks like it could be where it compares our input with something? First it checks if a[5] is equal to 33. So what is ‘a’? Looking at the code doesnt provide much help, and this is the only other reference to a[5] that I found.
I decided it was time to go to the debugger to see if that could give us any insight. I Set a breakpoint at line 1445 (Figure 5) in the wasm.wasm module in Chrome, entered ‘Password’ in the input box and hit the ‘Check’ button.
To the right you can see the stack window and it is comparing 8 to 33. This looks like it might be our password length. Trying again with a longer password proves this to be true. So we have a password with length 33, now lets figure out what the password is.
In figure 5 we see a compares between string ‘b’ and various memory offsets, ie 66224. WebAssembly stores its strings in a single buffer and then references those strings by location and size. These strings are stored at the start of our decompiled code (or the bottom if youre looking in the browser) along with the starting memory offset.
I first wrote some python code to find the strings that coincide with the offsets in our string compare. I started by creating a string 65536 bytes long and then appended the above rodata string afterwards. Next I concatenated the the strings together to get our password.
But that password didnt work.
Back to the debugger and setting a breakpoint on the first stringEqual and stepping in, we can see the first letter of our password being compared with ‘L’ (76 is the decimal ascii representation) with the ‘a’ (97) from the last 4 letters of our password.
There are two ‘L’s in our string, but I tried adjusting the offsets to point to the first ‘L’ and ran my script again and we get the correct solution.
Entering that as our password gives us the congrats message.
I am not sure why the offsets didnt match up with the ones in the wasm file. There are probably better tools when dealing with wasm files, but I have not messed with wasm lately and havent kept up with the tooling.
The CTF was a lot of fun and I wish I had more time to play. I look forward to seeing the solutions to some of the challenges that I didnt complete. Let me know if you have any questions, suggestions, or comments.