First we identify what type of binary we are dealing with:
Running objdump -t delphi, we can see some symbols of the binary and from these we can conclude it is a compiled Golang program:
Now we have to make sure our system finds the libtwenty.so object file (just add the directory where you have libtwenty.so to the LD_LIBRARY_PATH environment variable):
So when we run this program, we are prompted with:
OK, so we have a place to input data… let’s first look for a place we can latch onto:
Alright so we found main (really main.main, since this is a Golang program), and we also found a function “main.doTheMagic”, interesting… let’s try to see if we can get there.
We first find where our input is being read in:
If we continue to step (Whenever I debug, I can’t help but think about Vampire Weekend’s Step, naturally that is on a loop when I’m doing this :D), we end up here:
Alright, so it compares the length of our input to 2 and if it is smaller then it will presumablely quit.
Moving forward…
So it looks like the program checks to make sure the first two characters of the string are “go”, so let’s give that a try to see if anything different happens:
So “go” is definetly what we want for the first part of our payload.
Let’s see where this takes us now…
Sweet :D, we can get to the magic function now…
So it looks like our input is being split on spaces. We need to see how many parameters this thing expects…
If you take into consideration the control flow going on here, and taking a peak at the bottom of our magic function:
It seems to me we want to go into that function and in order to do that we would have to have rax == 3. Since we know the value in rax is controlled by our split function’s return value, we are going to have 3 parameters in our payload, one of them being “go”. Thus, it will look something like this:
Alright, so let’s checkout the check answer function:
Looks like this function calls this function: 0x400f80. I guess we should check that out then:
Well then, I guess our check_answer function is really apart of that libtwenty.so shared object file since we see our program using the plt to call it.
What is inside this check_answer function?
Ooo, a strcat and system call as well as no input validation… interesting… let’s try to see if we can get there:
So here is where our control flow can take either the red or blue pill and we want the “ja” to fail so we don’t end up at the end of the function, but instead in this interesting piece of code:
Which does some calculation stuff and then jumps to rax. OK, so in our comparison code we take 42 and add it to our second parameter. At this point we can guess our payload will look something like this:
So if we start with 42 and add the number we specified, how can we get that to be less than or equal to 4? Hmmm… well an integer overflow would sure do the trick :D This assembly actually looks really funky, like why would you use the ax register and add it to WORD [rbp-0x2] and compare 4 to the WORD [rbp-0x2]? Since a WORD is only two bytes, if we send in the maximum value of a WORD and add it to any value, the carry bit is going to be discarded because we will have exceeded the size of a WORD. So what if we send the largest size of a WORD - 42 == 2^16 - 42 == 65494?
Woah, eax is 0! So now we are going to hit that weird jump code. Now the question is, what does eax have to be to get the system code to be called? Well we could do the math here, or since we know eax can only be 0, 1, 2 or 4 we could just try setting eax to be those different numbers until we get it to work :D
Boom! So we got that system call to be executed and all it does right now is “echo ". But if you look at the code again, it simply concatinates the 2nd part of our payload to the echo without checking for special characters, meaning we can just put a semicolon and execute arbituary commands :D
Not too bad of a challenge, really was more reversing than actually exploitation. So when it all boils down, you have to reverse a basic command protocol, exploit an integer overflow and use metacharacter injection. For 200 points I would say that is reasonable :D