许可优化
许可优化
产品
产品
解决方案
解决方案
服务支持
服务支持
关于
关于
软件库
当前位置:服务支持 >  软件文章 >  Linux x86环境下NX与ASLR绕过技术(续)

Linux x86环境下NX与ASLR绕过技术(续)

阅读数 8
点赞 0
article_banner

四、Stack Canaries

首先看一下Stack Canaries演进历史:

Stack Guard 是第一个使用 Canaries 探测的堆栈保护实现,它于 1997 年作为 GCC 的一个扩展发布。最初版本的 Stack Guard 使用 0x00000000 作为 canary word。尽管很多人建议把 Stack Guard 纳入 GCC,作为 GCC 的一部分来提供堆栈保护。但实际上,GCC 3.x 没有实现任何的堆栈保护。

GCC4.1开始,引入了Stack-smashing Protection(SSP,又称 ProPolice),它实现了两个功能:

  1. 栈中插入Canaries,实现栈保护
  2. 变量重排机制,局部变量中的数组放到栈上高地址位置,其它类型变量放到栈上低地址位置,这使得通过溢出覆盖其它变量变得更加困难

Canaries值的生成,一般有几种方法:

  • Terminator canaries 由于绝大多数的溢出漏洞都是由那些不做数组越界检查的 C 字符串处理函数引起的,而这些字符串都是以 NULL 作为终结字符的。选择 NULL, CR, LF 这样的字符作为 canary word 就成了很自然的事情。例如,若 canary word 为 0x000aff0d,为了使溢出不被检测到,攻击者需要在溢出字符串中包含 0x000aff0d 并精确计算 canaries 的位置,使 canaries 看上去没有被改变。然而,0x000aff0d 中的 0x00 会使 strcpy() 结束复制从而防止返回地址被覆盖。而 0x0a 会使 gets() 结束读取。插入的 terminator canaries 给攻击者制造了很大的麻烦。
  • Random canaries 这种 canaries 是随机产生的。并且这样的随机数通常不能被攻击者读取。这种随机数在程序初始化时产生,然后保存在一个未被隐射到虚拟地址空间的内存页中。这样当攻击者试图通过指针访问保存随机数的内存时就会引发 segment fault。但是由于这个随机数的副本最终会作为 canary word 被保存在函数栈中,攻击者仍有可能通过函数栈获得 canary word 的值。
  • Random XOR canaries 这种 canaries 是由一个随机数和函数栈中的所有控制信息、返回地址通过异或运算得到。这样,函数栈中的 canaries 或者任何控制信息、返回地址被修改就都能被检测到了。

一张图帮助理解:

下面通过调试,探索一下GCC中Canaries的具体实现。依然是使用Ubuntu x86环境,gcc version 4.9.2。

使用的程序代码如下:

void func(){     int i;     char buffer[64];     i = 1;     buffer[0] = 'a';} int main() {     func();     return 0;}

分别编译开启栈保护和去除栈保护的程序:

ez@ubuntu:~/workdir/Canaries$ gcc -fstack-protector -o demo_sp demo.c ez@ubuntu:~/workdir/Canaries$ gcc -fno-stack-protector -o demo_nosp demo.c

分别展示func函数的反汇编代码。

无栈保护代码:

(gdb) disass func Dump of assembler code for function func: 0x080483eb <+0>: push %ebp 0x080483ec <+1>: mov %esp,%ebp 0x080483ee <+3>: sub 0𝑥50, 0x50, 0x50,%esp 0x080483f1 <+6>: movl 0x1,-0x4(%ebp) 0x080483f8 <+13>: movb $0x61,-0x44(%ebp) 0x080483fc <+17>: leave 0x080483fd <+18>: ret End of assembler dump. (gdb)

观察到,使用-fno-stack-protector选项编译的程序,栈上没有任何保护措施。

开启栈保护代码:

(gdb) disass func Dump of assembler code for function func: 0x0804843b <+0>: push %ebp 0x0804843c <+1>: mov %esp,%ebp 0x0804843e <+3>: sub 0𝑥58, 0x58, 0x58,%esp 0x08048441 <+6>: mov %gs:0x14,%eax #读取gs寄存器,生成Canaries 0x08048447 <+12>: mov %eax,-0xc(%ebp) #在栈底部写入Canaries 0x0804844a <+15>: xor %eax,%eax 0x0804844c <+17>: movl 0x1,-0x50(%ebp) 0x08048453 <+24>: movb $0x61,-0x4c(%ebp) 0x08048457 <+28>: mov -0xc(%ebp),%eax 0x0804845a <+31>: xor %gs:0x14,%eax #函数返回前,检查Canaries值 0x08048461 <+38>: je 0x8048468 <func+45> #若未改变,跳到+45处正常返回 0x08048463 <+40>: call 0x8048310 <__stack_chk_fail@plt> #若发生栈溢出,执行__stack_chk_fail函数 0x08048468 <+45>: leave 0x08048469 <+46>: ret End of assembler dump. (gdb)

其中,从gs寄存器中读取的值,每次函数调用都是随机的,我们使用GDB调试验证之:

(gdb) b *0x08048447 Breakpoint 4 at 0x8048447 (gdb) r Starting program: /home/ez/workdir/Canaries/demo_sp Breakpoint 4, 0x08048447 in func () (gdb) i r eax eax 0xa3850c00 -1551561728 (gdb) r Starting program: /home/ez/workdir/Canaries/demo_sp Breakpoint 4, 0x08048447 in func () (gdb) i r eax eax 0xcc46de00 -867770880

通过跟踪__stack_chk_fail函数可以发现,它的实现比较复杂。大体流程是,首先调用__GI___fortify_fail函数,__GI___fortify_fail又调用__libc_message函数,__libc_message的最后调用backtrace_and_maps和__GI_abort函数,产生SIGABRT信号,并通过__GI___libc_secure_getenv根据系统环境变量决定是否产生coredump文件,__GI_abort执行到最后调用_exit,程序退出。

关于Canary名称的由来,我搜到一则有趣的小故事,矿井中的金丝雀

五、总结

  1. 所有具有任意代码执行能力的exp,均要绕过上述防护机制,本文只是拿缓冲区溢出举例,方法是通用的; 漏洞利用的关键是控制IP寄存器,但并不一定要直接覆盖,内核中大量的Ops结构,虚函数表,异常处理函数,GOT等都是很好的目标;

转载于:https://www.cnblogs.com/gm-201705/p/9901570.html
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

相关文章
技术文档
QR Code
微信扫一扫,欢迎咨询~
customer

online

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 board-phone 155-2731-8020
close1
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

姓名不为空

姓名不为空
手机不正确

手机不正确

手机不正确
公司不为空

公司不为空

公司不为空