《黑客攻防技术-系统实战》第二章--栈溢出2
参考文献:
《黑客攻防技术宝典-系统实战》
《汇编语言》
上一节我们已经对栈有个一个清楚的认识,这节从以下几个点来讲解栈溢出:
1)栈缓冲溢出
2)控制EIP
3)利用漏洞获取特权
4)战胜不可执行栈
一. 栈缓冲溢出
这一节我们看下过多数据放进缓冲区之后,缓冲区将发生什么变化,在了解这些变化之后,我们就可以利用缓冲区溢出做一些骚操作了
先来看一个栗子:
#include <stdio.h> #include <stdlib.h> void return_input(void) { char array[30]; gets(array); printf("%s \n", array); } void main() { return_input(); return; }
编译:
gcc -mpreferred-stack-boundary=2 -g -o overflow overflow.c
会出现告警:
overflow.c: In function ‘return_input’: overflow.c:14:5: warning: ‘gets’ is deprecated (declared at /usr/include/stdio.h:638) [-Wdeprecated-declarations] gets(array);
也就是提示函数过时了,存在一定的问题,在这里我们先不关注这个,能够正常编译成功
这里我们运行一下程序:
ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss *** stack smashing detected ***: ./overflow terminated 已放弃 (核心已转储)
和我们预料的结果查不多, 正常来说这里会出现段错误出现core, 那为什么提示溢出,核心转储呢????
查资料之后才知道,该提示信息就是gcc提供的栈溢出保护机制在检测到程序存在缓冲区溢出时所打印出来的提示信息。大家可以想想, 我自己在linux系统跑一点代码,就能把系统搞崩溃了,那系统岂不是显的太过于脆弱了, 那gcc提供栈溢出保护机制是什么呢?
查看gcc的使用手册,我们可以知道该报机制为gcc的-fstack-protector一系列选项所提供的缓冲区溢出检测机制。下面为该机制的原理介绍:
当-fstack-protector启用时,当其检测到缓冲区溢出时(例如,缓冲区溢出攻击)时会立即终止正在执行的程序,并提示其检测到缓冲区 存在的溢出的问题。这种机制是通过在函数中的易被受到攻击的目标上下文添加保护变量来完成的。这些函数包括使用了allcoa函数以及缓冲区大小超过 8bytes的函数(此处不是很明白,上面的例子缓冲区大小为5同样触发了该机制)。这些保护变量在进入函数的时候进行初始化,当函数退出时进行检测,如 果某些变量检测失败,那么会打印出错误提示信息并且终止当前的进程。
其还提供一个-fstack-protector-all选项,其解释为: 其功能类似于-fstack-protector,但是其为所有的函数都进行栈溢出检测, 所以我们编译的时候最好能够加上这个选项,避免系统出问题
言归正传,我们看一下为什么提示溢出信息?
我们gdb反汇编看一下
1 (gdb) disassemble return_input 2 Dump of assembler code for function return_input: 3 0x00000000004005ed <+0>: push %rbp 4 0x00000000004005ee <+1>: mov %rsp,%rbp 5 0x00000000004005f1 <+4>: sub $0x30,%rsp 6 0x00000000004005f5 <+8>: mov %fs:0x28,%rax 7 0x00000000004005fe <+17>: mov %rax,-0x8(%rbp) 8 0x0000000000400602 <+21>: xor %eax,%eax 9 0x0000000000400604 <+23>: lea -0x30(%rbp),%rax 10 0x0000000000400608 <+27>: mov %rax,%rdi 11 0x000000000040060b <+30>: callq 0x4004f0 <gets@plt> 12 0x0000000000400610 <+35>: lea -0x30(%rbp),%rax 13 0x0000000000400614 <+39>: mov %rax,%rsi 14 0x0000000000400617 <+42>: mov $0x4006d4,%edi 15 0x000000000040061c <+47>: mov $0x0,%eax 16 0x0000000000400621 <+52>: callq 0x4004c0 <printf@plt> 17 0x0000000000400626 <+57>: mov -0x8(%rbp),%rax 18 0x000000000040062a <+61>: xor %fs:0x28,%rax 19 0x0000000000400633 <+70>: je 0x40063a <return_input+77> 20 0x0000000000400635 <+72>: callq 0x4004b0 <__stack_chk_fail@plt> 21 0x000000000040063a <+77>: leaveq 22 0x000000000040063b <+78>: retq 23 End of assembler dump.
我们可以看到有三个调用的指令分别在<+30> <+52> <+72>, 前两个是gets 和 printf 的
我们在gets() 和 retq 设置断点看下什么情况?
待续。。