文章目录
一、实验描述
缓冲区溢出的常用攻击方法是用 shellcode 的地址来覆盖漏洞程序的返回地址,使得漏洞程序去执行存放在栈中 shellcode。为了阻止这种类型的攻击,一些操作系统使得系统管理员具有使栈不可执行的能力。这样的话,一旦程序执行存放在栈中的 shellcode 就会崩溃,从而阻止了攻击。
不幸的是上面的保护方式并不是完全有效的,现在存在一种缓冲区溢出的变体攻击,叫做 return-to-libc 攻击。这种攻击不需要一个栈可以执行,甚至不需要一个 shellcode。取而代之的是我们让漏洞程序跳转到现存的代码(比如已经载入内存的 libc 库中的 system()函数等)来实现我们的攻击。
二、实验准备
系统用户名: shiyanlou
实验楼提供的是 64 位 Ubuntu linux,而本次实验为了方便观察汇编语句,我们需要在 32 位环境下作操作,因此实验之前需要做一些准备。
2.1 输入命令安装一些用于编译 32 位 C 程序的软件包
sudo apt-get update
sudo apt-get install lib32z1 libc6-dev-i386 #这个过程耗时有点长,请等待一会
sudo apt-get install lib32readline-gplv2-dev
2.2 输入命令 linux32 进入 32 位 linux 环境,输入 /bin/bash 使用 bash
三、实验步骤
3.1初始设置
Ubuntu 和其他一些 Linux 系统中,使用地址空间随机化来随机堆(heap)和栈(stack)的初始地址,这使得猜测准确的内存地址变得十分困难,而猜测内存地址是缓冲区溢出攻击的关键。因此本次实验中,我们使用以下命令关闭这一功能:
sudo sysctl -w kernel.randomize_va_space=0
实验截图:
此外,为了进一步防范缓冲区溢出攻击及其它利用 shell 程序的攻击,许多 shell 程序在被调用时自动放弃它们的特权。因此,即使你能欺骗一个 Set-UID 程序调用一个 shell,也不能在这个 shell 中保持 root 权限,这个防护措施在/bin/bash 中实现。
linux 系统中,/bin/sh 实际是指向/bin/bash 或 /bin/dash 的一个符号链接。为了重现这一防护措施被实现之前的情形,我们使用另一个 shell 程序(zsh)代替 /bin/bash。下面的指令描述了如何设置 zsh 程序:
sudo su
cd /bin
rm sh
ln -s zsh sh
exit
实验截图:
为了防止缓冲区溢出攻击,最近版本的 gcc 编译器默认将程序编译设置为栈不可执行,而你可以在编译的时候手动设置是否使栈不可执行:
gcc -z execstack -o test test.c #栈可执行
gcc -z noexecstack -o test test.c #栈不可执行
本次实验的目的,就是展示这个“栈不可执行”的保护措施并不是完全有效,所以我们使用-z noexecstack,或者不手动指定而使用编译器的默认设置。
3.2漏洞程序
把以下代码保存为“retlib.c”文件,保存到 /tmp 目录下。代码如下:
/* retlib.c */
/* This program has a buffer overflow vulnerability. */
/* Our task is to exploit this vulnerability */