先来看看基于 Red Hat 与 Fedora 衍生版(例如 CentOS)系统用于阻止栈溢出攻击的内核参数,主要包含两项:

kernel.exec-shield

可执行栈保护,字面含义比较“绕”,

实际上就是用来控制能否执行存储在栈

中的代码,其值为1时表示禁止;为0时表示允许;默认为1,表示禁止执行栈

中的代码,如此一来,即便覆盖了函数的返回地址导致栈溢出,也无法执行

shellcode

查看与修改系统当前的可执行栈保护参数:

[root@localhost 桌面]# sysctl -a | grep -e exec

ernel.exec-shield = 1

[root@localhost 桌面]# cat /proc/sys/kernel/exec-shield

1

[root@localhost 桌面]# sysctl -w kernel.exec-shield=0

kernel.exec-shield = 0

[root@localhost 桌面]# cat /proc/sys/kernel/exec-shield

0

注意:

一,只有在学习和测试栈溢出攻击的原理时,才建议关闭可执行栈保护机制

二,在基于 Debian 与 Ubuntu 衍生版

(例如 BackTrack 5 Release 3)的系统上,不支持可执行栈保护机制:

root@bt:~# uname -a

Linux bt 3.2.6 #1 SMP Fri Feb 17 10:40:05 EST 2012 i686 GNU/Linux

root@bt:~# sysctl -a | grep -e kernel.exec

error: permission denied on key 'vm.compact_memory'

error: permission denied on key 'dev.parport.parport0.autoprobe'

error: permission denied on key 'dev.parport.parport0.autoprobe0'

error: permission denied on key 'dev.parport.parport0.autoprobe1'

error: permission denied on key 'dev.parport.parport0.autoprobe2'

error: permission denied on key 'dev.parport.parport0.autoprobe3'

error: permission denied on key 'net.ipv4.route.flush'

error: permission denied on key 'net.ipv6.route.flush'

root@bt:~#

或许是社区的开发人员认为,有下面另一种叫做堆栈地址随机化的机制,就足够应对缓冲区溢出攻击了,也可能是由于 Debian / Ubuntu 面向运行桌面应用居多的用户群体,它并不像销售给企业公司用户的 Red Hat 类发行版那样,对安全性的要求更为严格,才能保护用户的服务器,资产安全

kernel.randomize_va_space

堆栈地址随机初始化,很好理解,就是在每次将程序加载到内存时,进程地

址空间的堆栈起始地址都不一样,动态变化,导致猜测或找出地址来执行

shellcode 变得非常困难,它和可执行栈保护的区别在于,后者即便是找到了

地址也是无法执行的;所有的 2.6 以上版本的  Linux 内核都支持并启用了

这一项特性;

查看与修改系统当前的堆栈地址随机初始化参数:

[root@localhost 桌面]# sysctl -a | grep randomize

kernel.randomize_va_space = 2

[root@localhost 桌面]# cat /proc/sys/kernel/randomize_va_space

2

[root@localhost 桌面]# sysctl -w kernel.randomize_va_space=0

kernel.randomize_va_space = 0

[root@localhost 桌面]# cat /proc/sys/kernel/randomize_va_space

0

参数值为2时,表示启用随机地址功能;0表示关闭;

基于 Debian 与 Ubuntu 衍生版默认支持并且启用了随机地址功能:

1

2

root@bt:~# sysctl -a | grep -e kernel.randomize

kernel.randomize_va_space = 2

下面,我们在一个启用了随机地址功能的机器上,查看执行同一个程序4次加载的动态链接共享库的入口地址(linux-gate.so.1),发现每次的入口地址都不同,验证了随机地址的效果:

[root@centos6-5 桌面]# cat /proc/sys/kernel/randomize_va_space

2

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x00dff000)

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x00503000)

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x00213000)

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x004b5000)

[root@centos6-5 桌面]#

同理,关闭随机地址功能,连续5次查看执行程序时加载的 linux-gate.so.1 入口地址:

[root@centos6-5 桌面]# sysctl -w kernel.randomize_va_space=0

kernel.randomize_va_space = 0

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x00110000)

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x00110000)

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x00110000)

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x00110000)

[root@centos6-5 桌面]# ldd /bin/ls | grep linux-gate.so.1

linux-gate.so.1 =>  (0x00110000)

再来看看 GCC 4.1 版本以后引入的两个编译参数:

(默认情况下,编译时不会指定这两个参数,用于阻止缺乏安全编码意识的程序员写出存在缓冲区溢出漏洞的程序,

但是站在逆向工程的角度来看,指定这两个参数,特意构造有漏洞的程序,对于学习和理解栈溢出的原理还是有帮助的;

再次提醒,这里介绍的两个编译参数必须同时打开,而且还要同时禁用前面讲的可执行栈保护与栈地址随机初始化,满足这4个条件后,一般而言,就可以测试 shellcode 的效果了

GCC 编译选项  -fno-stack-protector

禁用栈保护功能,默认是启用的;

gcc 的栈保护机制是指,在栈的缓冲区(大小通常由程序员给定)写入内容前

,在结束地址之后与返回地址之前,放入随机的验证码,由于栈帧是从内存高

址段向内存低址段增长的(回顾第一张图),结束地址在高址段;返回地

址在低址段,栈溢出时,会从高址段向低址段覆盖数据,因此如果想要覆盖返

回地址的内容,必定先覆盖结束地址,验证码,才能覆盖返回地址,

因此可以通过比较写入缓冲区前后的验证码是否发生改变,来检测并阻止溢出

攻击

GCC 编译选项  -z execstack

启用可执行栈,默认是禁用的;

该选项与 ld 链接器有关:ld 链接器在链接程序的时候,如果所有的 .o 文

件的堆栈段都标记为不可执行,那么整个库的堆栈段才会被标记为不可执行;

相反,即使只有一个 .o 文件的堆栈段被标记为可执行,那么整个库的堆栈段

将被标记为可执行,

换言之,默认是所有的 .o 文件的堆栈段都标记为不可执行

检查堆栈段可执行性的方法是:

1

[root@centos6-5vm /]# readelf -lW stack-overflow1-test | grep GNU_STACK

找出在输出中有无 E 标记;有 E 标记就说明堆栈段是可执行的,其中,

stack-overflow1-test  为我们编写的简单栈溢出测试程序,源码如下:

#include <stdio.h>

greeting(char *temp1, char *temp2){

char name[20];

strcpy(name, temp2);

printf("hello  %s  %s\n", temp1, name);

}

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

greeting(argv[1], argv[2]);

printf("bye  %s  %s\n", argv[1], argv[2]);

}

这是一个典型的存在缓冲区溢出漏洞的程序,greeting 函数定义了一个只有20字节大小的字符数组(缓冲区),strcpy 函数不检查用户输入的第二个参数(由 main 函数的第二个参数传递)是否超过20字节,就写入这个缓冲区中

我们用 gcc 默认参数配置来编译这个源文件,然后检查堆栈段的可执行性:

[root@centos6-5vm /]# gcc -v -Wall  -o stack-overflow1-test stack-overflow1-test.c

(***************省略部分输出*************

GNU C (GCC) 版本 4.4.7 20120313 (Red Hat 4.4.7-4) (i686-redhat-linux)

由 GNU C 版本 4.4.7 20120313 (Red Hat 4.4.7-4) 编译,GMP 版本 4.3.1,MPFR 版本 2.4.1。

GGC 准则:--param ggc-min-expand=100 --param ggc-min-heapsize=131072

Compiler executable checksum: 5f02f32570d532de29ae0b402446343a

stack-overflow1-test.c:2: 警告:返回类型默认为‘int’

stack-overflow1-test.c: 在函数‘greeting’中:

stack-overflow1-test.c:4: 警告:隐式声明函数‘strcpy’

stack-overflow1-test.c:4: 警告:隐式声明与内建函数‘strcpy’不兼容

stack-overflow1-test.c: 在文件层:

stack-overflow1-test.c:8: 警告:返回类型默认为‘int’

stack-overflow1-test.c: 在函数‘main’中:

stack-overflow1-test.c:11: 警告:在有返回值的函数中,控制流程到达函数尾

stack-overflow1-test.c: 在函数‘greeting’中:

stack-overflow1-test.c:6: 警告:在有返回值的函数中,控制流程到达函数尾

COLLECT_GCC_OPTIONS='-v' '-Wall' '-o' 'stack-overflow1-test' '-mtune=generic' '-march=i686'

as -V -Qy -o /tmp/ccv9qpvk.o /tmp/ccT7rHyO.s

GNU assembler version 2.20.51.0.2 (i686-redhat-linux) using BFD version version 2.20.51.0.2-5.36.el6 20100205

***************省略部分输出*************

可以看到, -Wall  选项(参考前文解释)显示所有的警告和错误信息,对于增加程序的可移植性非常有帮助,例如它指出在源码的二行,greeting 自定义函数没有定义返回类型,将采用默认返回类型:int

另外,在 greeting 函数中,调用 strcpy 函数前未声明和定义(在程序中调用 strcpy 函数需要包含系统头文件 string.h)

同样,我们没有为 main 函数指定返回类型

在上面的例子中,虽然每个警告都非致命的语法或词法错误,但是 -Wall 选项确实可以“强制”培养程序员的良好编程习惯

言归正传,检查生成的二进制可执行文件:

[root@centos6-5vm /]# readelf -lW stack-overflow1-test | grep GNU_STACK

GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

其中没有 E 标记,这说明该程序即便存在溢出漏洞,但是由于 GCC 的堆栈段不可执行保护机制,该漏洞也没有太大被利用的可能性

我们“故意”关掉 GCC 的堆栈段不可执行保护机制:指定 -z execstack  选项,再次编译源文件:

[root@centos6-5vm /]# gcc -v -Wall -z execstack -o stack-overflow1-test stack-overflow1-test.c

[root@centos6-5vm /]# readelf -lW stack-overflow1-test | grep GNU_STACK

GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4

这次的输出中,带有 E 标记,说明堆栈段是可执行的,

再次强调,在 CentOS6.5 中,要真正能利用这个程序测试你编写的 shellcode ,需要执行下面操作:

[root@localhost 桌面]# sysctl -w kernel.randomize_va_space=0

kernel.randomize_va_space = 0

[root@localhost 桌面]# sysctl -w kernel.exec-shield=0

kernel.exec-shield = 0

[root@localhost 桌面]# gcc -v -fno-stack-protector -z execstack -g -o stack-overflow1-test stack-overflow1-test.c

ubuntu –buffer-overflow

Ubuntu下面的GCC默认开启了Stack Smashing Protector,如果想在这个系统中学习缓冲区溢出的原理,在编译时要加上fno-stack-protector选项,否则运行时会出现*** stack smashing detected ***: xxx terminated,而不是期望的Segmentation fault。同时还需要加上允许栈执行的选项。

gcc -fno-stack-protector -z execstack -mpreferred-stack-boundary=2 -ggdb -o xxx xxx.c

execstack

用于阻止缓冲区溢出攻击的 Linux 内核参数与 gcc 编译选项的更多相关文章

  1. CSAPP:逆向工程【缓冲区溢出攻击】

    逆向工程[缓冲区溢出攻击] 任务描述 掌握函数调用时的栈帧结构,利用输入缓冲区的溢出漏洞,将攻击代码嵌入当前程序的栈帧中,使程序执行我们所期望的过程. 主要方法 溢出的字符将覆盖栈帧上的数据,会覆盖程 ...

  2. Linux下缓冲区溢出攻击的原理及对策(转载)

    前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实现 ...

  3. Linux下缓冲区溢出攻击的原理及对策

    前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈 帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实 ...

  4. linux内核参数sysctl.conf,TCP握手ack,洪水攻击syn,超时关闭wait

    题记:优化Linux内核sysctl.conf参数来提高服务器并发处理能力 PS:在服务器硬件资源额定有限的情况下,最大的压榨服务器的性能,提高服务器的并发处理能力,是很多运维技术人员思考的问题.要提 ...

  5. linux内核参数sysctl.conf,TCP握手ack,洪水攻击syn,超时关闭wait(转)

    http://www.xshell.net/linux/Linux_sysctl_conf.html 优化Linux内核sysctl.conf参数来提高服务器并发处理能力 Posted by 破冰 o ...

  6. CSAPP缓冲区溢出攻击实验(上)

    CSAPP缓冲区溢出攻击实验(上) 下载实验工具.最新的讲义在这. 网上能找到的实验材料有些旧了,有的地方跟最新的handout对不上.只是没有关系,大体上仅仅是程序名(sendstring)或者參数 ...

  7. CSAPP缓冲区溢出攻击实验(下)

    CSAPP缓冲区溢出攻击实验(下) 3.3 Level 2: 爆竹 实验要求 这一个Level的难度陡然提升,我们要让getbuf()返回到bang()而非test(),并且在执行bang()之前将g ...

  8. CSAPP阅读笔记-变长栈帧,缓冲区溢出攻击-来自第三章3.10的笔记-P192-P204

    一.几个关于指针的小知识点: 1.  malloc是在堆上动态分配内存,返回的是void *,使用时会配合显式/隐式类型转换,用完后需要用free手动释放. alloca是标准库函数,可以在栈上分配任 ...

  9. Linux内核参数配置

    Linux在系统运行时修改内核参数(/proc/sys与/etc/sysctl.conf),而不需要重新引导系统,这个功能是通过/proc虚拟文件系统实现的. 在/proc/sys目录下存放着大多数的 ...

随机推荐

  1. Java并发编程(详解wait(), notify(),sleep())

    http://blog.csdn.net/luckyzhoustar/article/details/48179161

  2. 基于Struts2+Hibernate的朋友圈留言网站开发的质量属性

    在课堂上我们了解了质量高于功能,质量属性是指影响质量的相关因素,是对质量的描述.现在我们对基于SSH的交友网站开发的质量属性可以从以下几个方向进行分析: (1)可用性: 当错误发生时,使用可用性战术进 ...

  3. 分析code

    1 using System; //跟系统说明一下可能会用到这个dll里面的东西 using System.Collections.Generic; //引用集合类命名空间 using System. ...

  4. SMS

    SMS:(Short Messaging Service)手机短信服务 . 一种存储和转发服务,短消息并不是直接从发送人发送到接收人,而始终通过 SMS 中心进行转发的.如果接收人处于未连接状态(可能 ...

  5. formidable模块的使用

    Node.js的Formidable模块的使用   今天总结了下Node.js的Formidable模块的使用,下面做一些简要的说明. 1)     创建Formidable.IncomingForm ...

  6. ESXi 20181229 刚学到的知识点

    1. 查看性能 能够获取到服务器的电源消耗 这里很明显的就能看到 2路服务器的情况下 电源在300w 以下,  平均值 270w 左右. 2. 然后在配置里面能够看到 服务器的信息 设置还能看到 序列 ...

  7. Oracle18c show pdbs 命令的使用.

    解决来源: https://community.oracle.com/thread/4124293 我本机 连接oracle数据库 想看下pdb 结果发现不行 提示内容为: SP2-: The SHO ...

  8. win 批处理

    前言 批处理文件(batch file)包含一系列 DOS命令,通常用于自动执行重复性任务.用户只需双击批处理文件便可执行任务,而无需重复输入相同指令.编写批处理文件非常简单,但难点在于确保一切按顺序 ...

  9. 【大数据】Scala学习笔记

    第 1 章 scala的概述1 1.1 学习sdala的原因 1 1.2 Scala语言诞生小故事 1 1.3 Scala 和 Java  以及 jvm 的关系分析图 2 1.4 Scala语言的特点 ...

  10. Linux_MySql_tar_安装(转)

    系统版本:CentOs 7.* Mysql版本:5.7.17(自己测试版本) 根据博主[大大的橙子]博文转载记录(大部分照搬了,只修改少许部分) 一.基本环境部署 #卸载系统自带的Mariadb [r ...