NyaVM [RE]
Read. Understand. Patch. Get flag. A cool challenge that requires patching binaries. Second RE challenge from DSO-NUS 2021.
Challenge Description
Help! It seems that my VM snapshot has problems with Meowing...
Can you help me fix my VM's Meow and recover my real flag?
Files (Any of the links are fine):
https://nusdsoctf2.s3-ap-southeast-1.amazonaws.com/S3/NyaVM/nyavm
https://nusdsoctf.s3-ap-southeast-1.amazonaws.com/S3/NyaVM/nyavm
>> Note if a submitted flag doesn't work, you may have to TrY HaRDer
>> Flag format conversion may have to be done for this challenge (Refer to notifications)
Solution
First thing to do: play around with the binary.
-------------------------------------
Welcome to Meow VM Terminal!
-------------------------------------
Select an action:
1. Load VM snapshot
2. Run VM
3. Pause VM
4. Meow in VM
5. Quit
>
In short, we need to load the vm, run it, then make it meow. But upon doing so, we get this
++++++++++++++++++++++++++++++++++
VM successfully started
++++++++++++++++++++++++++++++++++
Select an action:
1. Load VM snapshot
2. Run VM
3. Pause VM
4. Meow in VM
5. Quit
> 4
++++++++++++++++++++++++++++++++++
boom?!
and then the program exits. So we need to somehow patch the binary to fix this, and the flag will come out…?
Throwing things into ghidra, we see gibberish every where, as expected from a stripped binary. So I wasted most of my time reading through the code and understanding what each function does. I’ll only run through the few important ones that are related to the solution.
No decompilation? Then we’ll just have to select the function block (from the label to a return instruction), and create our own function.
We’re interested in the function in case 4, since that’s when we make the VM meow.
Let’s do some analysing of what each function does and rename things.
So here we see the two key
s that are responsible of checking whether the VM is loaded and running (it can be found in the functions of case 1 and 2). The problem lies in the second if
statement, there doesn’t seem to be anything in the program’s execution flow that allows the change of that value to not satisfy that condition, so this leads to one possible workaround: patching the binary (not surprising huh? :P)
Side note: I am not sure what the function randomize
does, but it seems to not affect the program execution in any way meaningful, so I ended up ignoring it.
With this, the VM won’t go boom. One thing to keep in mind when patching binaries is that we should only change a k-byte instruction to another k-byte instruction to avoid memory alignment issues (#saynotosegfaults)
Changing the instruction here in ghidra doesn’t affect the original binary, we need to write this patch back to the executable with the help of a ghidra script.
Also notice near the end of the function, there’s an if statement checking for the result of big_compare
(we’ll check this out later), if it is non-zero, the program will exit (you can verify this by looking at the use of that variable continue_if_0
in the main function). So, here’s big_compare
:
The function returns 0 at the inner most if block, so that means we need to run through all the functions (and have them return 0 as well).
They all look basically the same: a big condition and some return statements with a random function call before the return. At first glance I thought I might need to use z3 to solve for it, but then I remembered patching, so I essentially only need to remove the if statements (jump instructions in the context of assembly) to change the program execution in my favor.
To make sure I don’t miss anything, I ensure that all those random function calls are also executed and that the function returns 0. With that in mind, I just replace all the jump instructions to a few nop
instructions (with the correct number of bytes).
For example:
Final result after patching everything:
++++++++++++++++++++++++++++++++++
VM successfully started
++++++++++++++++++++++++++++++++++
Select an action:
1. Load VM snapshot
2. Run VM
3. Pause VM
4. Meow in VM
5. Quit
> 4
++++++++++++++++++++++++++++++++++
Meow!
++++++++++++++++++++++++++++++++++
Congrats! You found the real flag!
-------------------------------------
Nya! Thank you!
Here's your flag:
e22bdd97faabbd70da25dd18135b6cead0199fbbaee585e22473dfc2d8630975
a'!3:xxx'$x:$ap^!'^ae%W^^%eeZ00x!!$p0'x0%vav:x:ZWx$%$$%p0xa+$ve$
-------------------------------------
Nya! Thank you!
Here's your flag:
680fe2228d2ed6a30836b15331bbc77200da78271464e2ec52d1dd1a7269d4bd
-------------------------------------
Nya! Thank you!
Here's your flag:
flag: c4263f5e6660537f56c5d3a67d4142369d53785c44d4cf4aba931f5af5c3c96d
I actually missed out one if statement initially and got the bottom two fake flags only T.T
Flag: DSO-NUS{e22bdd97faabbd70da25dd18135b6cead0199fbbaee585e22473dfc2d8630975}