CTF: Monty Python
Last updated
Last updated
The CTF challenge required answers to 3 questions like in Monty Python's bridge of death.
Upon decompiling in Ghidra, we see the questions and conditions upon which flag would be returned:
As we can see, to get the flag (print_flag()) we need to make sure that all three conditions on the questions are wrong otherwise the program would exit using the "throw_into_gorge_of_eternal_peril()" function.
Let's see question1:
Upon entering the string mentioned here, strcmp works and question 1 would be answered correctly.
Let's see question2:
Hmmm, 2 variables are input and func2 is called and variable 1 is assigned it's value. Function returns true when a is not equal to b. It returns false when a is equal to b. As in the main() we can see that the question2() must return 0.
So, to make question2 return 0, variable 1 and variable 2 in the function should be equal. Which means after func2() is done, variable 1 should remain the same.
Let's see func2 now.
Inspect the three conditions here. When func2 is called from question2(), 3 parameters are sent: variable1, 0 and 0x14 which is 20 in decimal. So, the value of variable 1 and variable 2 must lie in [0,20].
Finally in func2 we can see the main operating condition.
iVar1 = 0 + (20-0)/2
if param_1 (which is variable 1 in question2()) is less than 10, value changes. If it is greater than 10, value changes. Only way value remains same is if variable 1 in question2() is 10. And by extension variable 2 should be 10 too to make the 2nd condition in main() false and allow further execution.
Thus: 10 and 10
Finally, question3() should return 0 to continue execution and print flag.
Here is what question 3 looked like:
For simplicity, I rewrote this using simple variable names:
Here, we can see for this function to return 0, we need to make d=0. For that to happen i needs to be 10. So, for 9 executions we have to make this: "if (((0xff < b) || (0xff < c)) || (i != (char)forestOfEwing[(long)b * 0x100 + (long)c]))
" condition false 9 times.
Now, it is easy to provide b and c with inputs less than 0xff (255 in decimal) but the third or condition is tricky. We need to find elements in the array forestOfEwing at indices b*256 + c == index which is equal to i's current value.
Upon inspecting the array, we see this:
It is an array of 65536 elements. At first, it seemed like all elements were 0x00, but when I copied it I started finding 0x01, 0x02,...0x09 indices:
Now, let's start with condition when i=1. a*256+b must be equal to 53937 while a and b are in (0,255)
To solve this I used z3 theorem prover in python and found the solution:
I automated this using a python script and found all the solutions:
Great! We have all the answers now. I created a small python script to help input all this data in the binary:
Let's get the flag!
Pretty nifty tool, z3 right? Here is a brief on theorem solvers: https://hexisanoob.gitbook.io/hexisanoob/enum-and-initial-compromise/buffer-overflow-prep/theorem-proving