d3d d3d is a computer security researcher and bug bounty hunter, that ❤'s exploit development, writing security tools and helping others learn about Information Security.

Exploit Exercise’s Phoenix x64 VM – Stack One

4 min read

Exploit Exercises

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.

Virtual Machine

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 stack-one challenge.

Source Code

The following is the source code for the vulnerable binary stack-one file.

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.

Debugging

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 changeme variable.

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 stack-one-payload.txt.

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 stdin, to arg1.

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 aaa and 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.

d3d d3d is a computer security researcher and bug bounty hunter, that ❤'s exploit development, writing security tools and helping others learn about Information Security.

Leave a Reply

Your email address will not be published. Required fields are marked *

×

*NOTE*

I am currently updating the site, so posts will starting showing up from my previous blog very soon.