先来看看基于 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. NServiceBus官方文档翻译(二)NServiceBus 入门

    在这篇教程中我们将学习如何创建一个非常简单的由客户端向服务端发送消息的订单系统.该系统包括三个项目:Client.Server 和 Messages,我们将按照以下步骤来完成这个任务. 创建 Clie ...

  2. 『编程题全队』Alpha 阶段冲刺博客Day6

    1.每日站立式会议 1.会议照片 2.昨天已完成的工作统计 孙志威: 1.添加JSON处理模块 2.添加了团队看板中的添加团队任务功能 3.添加了团队看板中的添加按钮 孙慧君: 1.个人任务框UI的设 ...

  3. Beta 冲刺 七

    团队成员 051601135 岳冠宇 031602629 刘意晗 031602248 郑智文 031602330 苏芳锃 031602234 王淇 项目进展 岳冠宇 昨天的困难 换了种方法写了搜索栏, ...

  4. [转帖]Kubernetes及容器编排的总体介绍【译】

    Kubernetes及容器编排的总体介绍[译] 翻译自The New Stack<Kubernetes 生态环境>作者:JANAKIRAM MSV和 KRISHNAN SUBRAMANIA ...

  5. 在vue中如何动态修改title标签的值

    建议用vue-wechat-title插件为微信动态设置标题 1,首先安装插件 cnpm install vue-wechat-title --save 2,在main.js中引入 Vue.use(r ...

  6. bzoj1214 [HNOI2004]FTP服务器

    题目挺复杂的. 但有一点好,就是这题没数据,交个空程序就好了. begin end.

  7. 【题解】 bzoj4472: [Jsoi2015]salesman (动态规划)

    bzoj4472,懒得复制,戳我戳我 Solution: 题面意思:从\(1\)号节点出发,每到一个节点就必须停下,获得节点权值(每个节点只会获得一次),每个点有个规定的停留次数,求最大可获得多大权值 ...

  8. 【Luogu1344】追查坏牛奶(最小割)

    [Luogu1344]追查坏牛奶(最小割) 题面 洛谷 题解 裸的最小割,但是要求边的数量最小. 怎么办呢?给每条边的权值额外加上一个很大的值就了. #include<iostream> ...

  9. Luogu 1613 跑路(最短路径,倍增)

    Luogu 1613 跑路(最短路径,倍增) Description 小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零.可是小A偏偏又有赖床的坏毛病.于是 ...

  10. ASP.NET MVC —— Model之一模型模板

    http://www.cnblogs.com/lzhp/archive/2013/03/25/2981650.html Mvc model系列文章主要分为三部分:Model Templates,Mod ...