In this post, I will be continuing the series on the Phoenix VM by exploit education by using radare2. The next challenge is called
stack-one, and located in the same location
stack-zero was. If you want to catch up, I started the series here.
Phoenix introduces basic memory corruption issues such as buffer overflows, format strings and heap exploitation without any form of modern exploit mitigation systems enabled. It has both 32 bit and 64 bit levels available, for both X86 and ARM systems.
In this post I will be focusing on the amd64 version of the
The following is the source code for the vulnerable binary
After reviewing the source code above, this challenge is almost identical to the last challenge here, in which we overwrote the
locals.changeme variable, but instead of simply changing the value within
locals.changeme, it looks like we need to overwrite that variable location in memory with another specific value of
0x496c5962. However, instead of using stdin as our input vector, the above code is using an program argument as its input, so I will need to send the payload as a program argument, as you can see in the code below.
You will notice the program is also using
strcpy() instead of
gets() for its data input. This is perfect, because
strcpy() is also considered an insecure function due to the lack of bounds checking when writing to fixed length variables.
The final piece of code is comparing the
locals.changeme value to a specific integer value, and on success you are presented with a success message, and if not, you are presented with the current value of
locals.changeme to see how far you were off.
It seems if I package a payload that includes the special integer after the 64 byte string, it should overwrite the
locals.changeme value with the correct value. Also, the payload will be sent over program argument instead of printing to stdin.
Since this challenge looks a lot like the last challenge, we can re-use a lot of the information. For instance, we still have the struct datatype loaded into memory as seen below. What is different however, is the fact we will be using a different attack vector, as this program uses the
strcpy() function when trying to copy data from the programs first argument into a fixed length buffer of 64 bytes, instead of using the
gets() function with stdin like the last challenge did.
We still have the ability to overflow the buffer with 64 + N characters, but in this specific instance the
changeme value needs to reflect the one in the source code (
0x496c5962). This can be done by creating a payload with Python, like we did in the last challenge, but with the required overwrite address for the
Before taking a look at the disassembly of the
stack-one binary, let’s run it from the cli to see what is happening from the client point of view.
As expected, the program is expecting one argument to be provided then instantly checks to see if the
changeme value has been updated correctly.
To get more information about the file, I am going to run the
rabin2 tool against the
stack-one binary to get a better idea of what features or protections the binary may be using, as I did in the last challenge.
The above output still shows that no security mechanisms are enabled for this binary, but just to make sure I will also check with the
checksec command as well.
As I have said before, checking the binary security features before trying to debug is probably a no brainer, so this is something that will come natural as you do more and more RE.
For the payload, I will be using the same payload from before, but with another element added to bytes 65 through 68 to reflect the value required from the source code.
As you can see in the command above, I am simply creating a buffer of 68 characters (64 for
buffer, and 4 for
changeme) and by printing the bytes in little endian format, they will be reversed in memory when viewing it in radare2. The above output was also written to a new file named
The next step is to create a new
rarun2 template for the
stack-one binary. This template will be very similar to the last one we did, but we will be changing the attack vector from
Notice, in order to use the contents of a file instead of a literal string, I needed to add the
@ symbol before the file path within the
arg1 option. With the above options set, we should be ready to test against the program by using the following command.
As usual, I will be analyzing the binary and any functions associated with the binary with the
afl commands respectively.
Next, I will seek to the
main() function so I can then switch to visual mode to set a breakpoint right before the
strcpy() function, so we can step through the actual overflow visually.
After getting into visual mode, I again press the
p key until I get to the window where I can see a clear view of the stack, as seen below.
As I did in the last challenge, I am going to resize the stack to show more than 64 bytes, by using the
: key to open up a command prompt, then the
e command to set the
stack.size variable to 128.
Now with the stack size increased to 128 bytes, I will set a breakpoint right before
strcpy() call as seen below.
Setting a break point at
0x004006b9, check to make sure it is set and then running program until it hits that breakpoint.
Now we should be sitting at the instructions before the call to
strcpy(), so I am going to go back into visual mode, to step through the call, to see how the buffer was overwritten.
The above image shows the call right before the call to
strcpy(), where the stack looks fairly empty with a few bytes here and there… but after I press the
s key, and step through the
strcpy() function, you can see the stack has overwritten the buffer, and the
changeme location with the correct value as seen below.
You can see in the above image, that the 64 ‘A’ characters overwrote exactly 64 bytes of the buffer, filling it up, then sending another 4 bytes to input the special value (
0x496c5962) that was required to pass the challenge. By continuing the execution of the program with the
dc command, you will receive the output that we passed the challenge.
This challenge was not much harder than the last, but did require some more knowledge about inputting data in little endian format while writing your payloads. Anyhow, I am moving on to the next challenge, and I hope to see you guys there.