[转]现代Linux系统上的栈溢出攻击 (4)

让我们来回顾下整个过程,缓冲区被溢出了,数据被复制到缓冲区外面并且覆盖掉了那个“金丝雀”值(译者注: windows 上面也有类似的机制,不过在windows上这个值叫做安全cookies )同时也覆盖掉了函数的返回地址。但是,悲剧的是在函数就要返回到那个被改写的地址继续执行的时候,函数检查了下那个金丝雀值是不是被改写了。于是函数没有返回而是执行另外一个函数安全的让进程退出了。现在坏消息来了,对于一个攻击者并没有一个很好的方式来绕过这个检测。你可能会想到暴力猜解那个金丝雀值。但是这个值每次都不同,除非你非常的幸运被你猜到了 (译者注:概率:1/2^32),而且这样做也是费时而且容易被发现的。但是还有好消息,那就是在很多的情况下这个并不能阻止溢出攻击。举例来说,栈里面的金丝雀值只是保护SIP不被非法的改写,但是它不能阻止函数的局部变量被改写。这就很容易导致下一步的溢出,这会在下面的文章里演示。上面讲的保护机制有效的阻止我们老的攻击方式的攻击,但是马上这种保护机制就会失效。

4.2 NX:不可执行内存

你可能注意到我们不仅仅去掉了-fno-stack-protector这个标识,同时也去掉了-zexecstack标识,(也就是允许执行栈中的代码)现代的操作系统是不允许这种情况发生的,系统把需要写入数据的内存标识为可行,把保存指令的内存标识为可执行,但是不会有一块内存被同时标识为可写和可执行的。因此我们既不能在可执行的内存区域写入我们的shellcode 也不能在可写入的地方执行我们的shellcode (译者注:哈哈 系统的保护错误很变态吧 本来内存就只要可读 或者 可写属性 后来加入的 可执行 属性大大增强了系统的安全性)。我们需要另外的一种方式来让欺骗程序执行我们的代码,答案就是ROP(Return-Oriented Programming),这个技巧就是使用程序中已经有的代码片段,也就是位于可执行文件的.text节里面代码,使用一种方式将这些代码片段链到一起使他们看来就像我们以前的shellcode。关于此,我不会深入的讲解,但是我会在文件的结尾给大家一个例子。还是让我先展示下如果程序如果执行堆栈里的代码会发送的情况(肯定是执行失败了)。

-----------------------------------

$ cat nx.c

int main(int argc, char **argv) {

char shellcode[] =

"\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff"

"\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48"

"\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21";

void (*func)() = (void *)shellcode;

func();

}

$ gcc nx.c -o nx -zexecstack

$ ./nx

Hax!$

$ gcc nx.c -o nx

$ ./nx

Segmentation fault (core dumped)

-----------------------------------

我们把我们要执行的代码放到了堆栈上的一个数组里,然后让一个函数指针指向这个数组,然后执行这个函数。当我们编译的时候和之前一样带上 –zexecstack,我们的shellcode 就会执行,但是如果不带上这个选项,栈空间就会被标识为不可执行的,程序也就会随着一个段错误而执行失败。

4.3 ASLR:地址空间随机化

我们为了演示那个经典的溢出攻击,做的最后一件事就是关掉 ASLR,通过在root下执行echo "0" > /proc/sys/kernel/randomize_va_space 。ASLR可以确保每次程序被加载的时候,他自己和他所加载的库文件都会被映射到虚拟地址空的不同地址处。这就意味着我们不能使用我们自己在gdb里面调试时的地址了。因为这个程序在运行的时候这个地址有可能变成另外一个。要注意当你调试一个程序的时候 gdb 会关掉ASLR。但是我们可以在调试的时候打开这个选项,以便我们可以更真实的看到程序执行时发送的一切,具体看下面的演示

(输出的过长字符串在右边截断了,左边显示的地址信息才是最重要的):

-----------------------------------

$ gdb -q ./oldskool

Reading symbols from /home/me/.hax/vuln/oldskool...done.

(gdb) set disable-randomization off

(gdb) break main

Breakpoint 1 at 0x4005df: file oldskool.c, line 11.

(gdb) run

Starting program: /home/me/.hax/vuln/oldskool

Breakpoint 1, main (argc=1, argv=0x7fffe22fe188) at oldskool.c:11

11 go(argv[1]);

(gdb) i proc map

process 6988

Mapped address spaces:

Start Addr End Addr Size Offset objfile

0x400000 0x401000 0x1000 0x0 /home/me/.hax/vuln

0x600000 0x601000 0x1000 0x0 /home/me/.hax/vuln

0x601000 0x602000 0x1000 0x1000 /home/me/.hax/vuln

0x7f0e120ef000 0x7f0e122a4000 0x1b5000 0x0 /lib/x86_64-linux-

0x7f0e122a4000 0x7f0e124a3000 0x1ff000 0x1b5000 /lib/x86_64-linux-

0x7f0e124a3000 0x7f0e124a7000 0x4000 0x1b4000 /lib/x86_64-linux-

0x7f0e124a7000 0x7f0e124a9000 0x2000 0x1b8000 /lib/x86_64-linux-

0x7f0e124a9000 0x7f0e124ae000 0x5000 0x0

0x7f0e124ae000 0x7f0e124d0000 0x22000 0x0 /lib/x86_64-linux-

0x7f0e126ae000 0x7f0e126b1000 0x3000 0x0

0x7f0e126ce000 0x7f0e126d0000 0x2000 0x0

0x7f0e126d0000 0x7f0e126d1000 0x1000 0x22000 /lib/x86_64-linux-

0x7f0e126d1000 0x7f0e126d3000 0x2000 0x23000 /lib/x86_64-linux-

0x7fffe22df000 0x7fffe2300000 0x21000 0x0 [stack]

0x7fffe23c2000 0x7fffe23c3000 0x1000 0x0 [vdso]

0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]

(gdb) run

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /home/me/.hax/vuln/oldskool

Breakpoint 1, main (argc=1, argv=0x7fff7e16cfd8) at oldskool.c:11

11 go(argv[1]);

(gdb) i proc map

process 6991

Mapped address spaces:

Start Addr End Addr Size Offset objfile

0x400000 0x401000 0x1000 0x0 /home/me/.hax/vuln

0x600000 0x601000 0x1000 0x0 /home/me/.hax/vuln

0x601000 0x602000 0x1000 0x1000 /home/me/.hax/vuln

0x7fdbb2753000 0x7fdbb2908000 0x1b5000 0x0 /lib/x86_64-linux-

0x7fdbb2908000 0x7fdbb2b07000 0x1ff000 0x1b5000 /lib/x86_64-linux-

0x7fdbb2b07000 0x7fdbb2b0b000 0x4000 0x1b4000 /lib/x86_64-linux-

0x7fdbb2b0b000 0x7fdbb2b0d000 0x2000 0x1b8000 /lib/x86_64-linux-

0x7fdbb2b0d000 0x7fdbb2b12000 0x5000 0x0

0x7fdbb2b12000 0x7fdbb2b34000 0x22000 0x0 /lib/x86_64-linux-

0x7fdbb2d12000 0x7fdbb2d15000 0x3000 0x0

0x7fdbb2d32000 0x7fdbb2d34000 0x2000 0x0

0x7fdbb2d34000 0x7fdbb2d35000 0x1000 0x22000 /lib/x86_64-linux-

0x7fdbb2d35000 0x7fdbb2d37000 0x2000 0x23000 /lib/x86_64-linux-

0x7fff7e14d000 0x7fff7e16e000 0x21000 0x0 [stack]

0x7fff7e1bd000 0x7fff7e1be000 0x1000 0x0 [vdso]

0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]

-----------------------------------

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdfxd.html