栈溢出保护原理 您所在的位置:网站首页 金丝雀值 栈溢出保护原理

栈溢出保护原理

2023-09-15 20:02| 来源: 网络整理| 查看: 265

栈溢出保护原理——Stack Canaries

Stack Canaries (取名自地下煤矿的金丝雀,因为它能比矿工更早地发现煤气泄露,有预警的作用)

是一种对抗栈溢出攻击的技术,即SSP安全机制

Canary的值是栈上的一个随机数,在程序启动时随机生成并保存在比函数返回地址更低的位置。由于栈溢出是从低地址向高地址进行覆盖,因此攻击者要想控制函数的返回指针,就一定要先覆盖到Canary。程序只需要在函数返回前检查Canary是否被篡改,就可以达到保护栈的目的。

一,Canaries的分类

canaries 通常可分为3类:terminator,random 和random XOR,具体的实现有StackGuard,StackShield,proPoliced等。

Terminator canaries:由于许多栈溢出都是由于字符串操作(如strcpy)不当所产生的,而这些字符串由NULL“\x00”结尾,换个角度看就是会被“\x00”所截断。基于这一点,terminator canaries将低位设置为“\x00”,既可以防止被泄露,也可以防止被伪造,截断字符还包括CR(0x0d),LF(0x0a),EOF(0xff)。**Random canaries:**为了防止canaries被攻击者猜到,random canaries通常在程序初始化时就随机生成,并保存在一个相对安全的地方。当然如果攻击者知道他的位置,还是有可能被读出来的,随机数通常由/dev/urandom生成,有时也使用当前时间的哈希。**Random XOR canaries:**与random canaries类似,但是多了一个XOR操作,这样无论是canaries被篡改还是与之XOR的控制数据被篡改,都会发生错误,这样就增加了攻击难度。

GCC包含多个与Canaries有关的参数,这里先使用最常见的

参数作用-fstack-protector对alloca系列函数和内部缓冲区大于八个字节的函数启用保护-fstack-protector-strong增加对包含局部数组定义和地址引用的函数保护-fstack-protector-all对所有函数启用保护-fstack-protecto-explicit对包含stack protect属性的函数启用保护-fno-stack-protector禁用保护 //一 ┌──(root💀kali)-[/home/kali/桌面/ctf_workstation/aslr] └─# python -c 'print("A"*30)' | ./fno.out 255 ⨯ zsh: done python -c 'print("A"*30)' | zsh: segmentation fault ./fno.out //二 ┌──(root💀kali)-[/home/kali/桌面/ctf_workstation/aslr] └─# python -c 'print("A"*30)' | ./f.out *** stack smashing detected ***: terminated zsh: done python -c 'print("A"*30)' | zsh: abort ./f.out

可以看到开启Canaries后,程序终止并抛出错误“stack smashing deteced”,表示检测到了栈溢出。

其反汇编代码如下

0x555555555151 mov rax,QWORD PTR fs:0x28 0x55555555515a mov QWORD PTR [rbp-0x8],rax

在linux中,fs寄存器被用于存放线程局部存储(Thread Local Stroage ,TLS),TLS主要是为了避免多个线程同时访问同一全局变量或静态变量时导致的冲突,尤其是多个线程同时需要修改这一变量时。TLS为每个使用该全局变量的线程都提供一个变量值的副本,每个副本都可以独立的改变自己的副本,而不会和其他线程冲突。

二,Canaries的实现

从TLS取出Canary后,程序就将其插入rbp-0x8的位置暂时保存。在函数返回前,又从栈上将其取出,并与TLS中的Canary进行异或比较,从而确定两个值是否相等。如果不相等就说明发生了栈溢出,然后跳转到__stack_chk_fail()函数中,程序终止并抛出错误;否则程序正常退出。

如果是32位程序,那么Canary就变成了gs寄存器偏移为0x14的地方

脚本checksec.sh对Canary的检测也是根据是否存在**__stack_chk_fail(或者__intel_security_cookie)**进行判断的。

在这里插入图片描述

可以看到这里将rbp-var_8处的值给了rax,并将rax的值和fs:28h的值进行异或。最后再根据结果选择跳转到哪个地址。

以64位程序为例,在程序加载时glibc中的ld.so首先初始化TLS,包括为其分配空间以及设置fs寄存器指向TLS,这一部分是通过arch_protl系统调用完成的。然后程序调用security_init()函数,生成Canary的stack_chk_guard,并放入fs:0x28。

需要注意的是为了使Canary具有截断效果,其最低位被设置为0x00。当然如果dl_random指针为NULL,那么Canary为定值。

攻击Canaries的主要目的是避免程序崩溃,那么就有两种思路:第一种将Canaries的值泄露出去,然后在栈溢出时覆盖上去,使其保持不变;第二种则是同时篡改TLS和栈上的Canaries,这样在检查的时候就能通过。

的值泄露出去,然后在栈溢出时覆盖上去,使其保持不变;第二种则是同时篡改TLS和栈上的Canaries,这样在检查的时候就能通过。**



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有