SEED Labs – Buffer Overflow Attack Lab (Set-UID Version)

注意
本文最后更新于 2023-10-21,文中内容可能已过时。

关闭地址空间随机化:

1
sudo sysctl -w kernel.randomize_va_space=0

将 /bin/sh 链接到没有对策的 shell:

1
sudo ln -sf /bin/zsh /bin/sh
1
2
3
make
./a32.out
./a64.out

获得普通 shell。

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231018002543997.png

使用 gdb 调试 stack-L1-dbg 打印 ebp 的值和 buffer 的地址。

1
2
3
4
5
6
touch badfile
make
gdb stack-L1-dbg
b bof
r
n

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020155718763.png

需要注意的是,从 gdb 获取的帧指针值与实际执行时不同。 这是因为 gdb 在运行被调试程序之前已经将一些环境数据压入了栈。 当程序直接运行时,堆栈中没有那些数据,因此实际的帧指针值会更大。

对 exploit.py 作如下修改:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020162257325.png

start = 517 - len(shellcode) 将 shellcode 放在 content 的末尾。0xffffcb58 是之前调试得到的 ebp 值,这里没有使用 ebp + 8 而是 ebp + 100 作为返回地址的原因是调试时的栈帧可能比直接运行程序时的栈帧更深一点。为了覆盖返回地址,offset = ebp - &buffer + 4 = 112。

发起攻击,获得 root shell。

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020163532625.png

要在未知缓冲区大小的情况下发起攻击。任务书提供的信息有:缓冲区大小为 100~200 字节;帧指针的始终是 4 的倍数,这意味着返回地址的地址也是 4 的倍数。

使用 gdb 调试 stack-L2-dbg 打印 ebp 的值:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020183618875.png

对 exploit.py 作如下修改:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020185334945.png

根据 Task3 及缓冲区大小为 100~200 字节,可以猜测,offset 的大小为 112~212,因此只需将 content 的这一段区域每 4 个字节填充恶意返回地址。ret 的值为 ebp + 200,比之前更大,这是为了防止缓冲区较小时,无法跳转到 NOP 指令。

发起攻击,获得 root shell。

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020185139250.png

使用 gdb 调试 stack-L3-dbg 打印 rbp 的值和 buffer 的地址。

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020204554661.png

对 exploit.py 作如下修改:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020221841732.png

由于 64 位地址最高 2 个字节始终为 0,strcpy()遇 0 停止拷贝,因此 shellcode 应放在返回地址覆盖区域之前。start 应在返回地址覆盖区域之前尽可能地靠后,这样可以增加 NOP 指令的范围,使 shellcode 更容易被执行。但也不能靠到最后,否则会覆盖掉一些关键数据,导致攻击失败,实测 start 最大值为 162。实验中还发现了满足攻击 ret 的增量最小为 80,这说明调试时的栈帧比直接运行程序时的栈帧深了 80。start = 100,ret = 0x00007fffffffd920 + 100 是满足攻击的一组值。

发起攻击,获得 root shell。

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231020221610829.png

程序的缓冲区大小只有 10,无法放下 shellcode,也没有办法将 shellcode 复制到高地址。其实,在strcpy()执行之前,我们可以打印 str 的地址并利用,str 存储了完整的 shellcode。为求偏移量,继续打印 rbp 和 buffer 的地址。

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021163155362.png

对 exploit.py 作如下修改:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021163725980.png

offset = rbp - &buffer + 8 = 18。为了顺利执行 shellcode,我们希望 ret 跳转到字符串中返回地址与 shellcode 之间的 NOP 指令区域,对应 content 从 26 到 487。由 Task5 可得,程序实际运行时,栈的地址会增加 80,故 ret 增量的理论合适范围是 [106, 567],实测为 [106, 568]。这种攻击方式同样适用于上面已知缓冲区大小的情况。

发起攻击,获得 root shell。

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021163623721.png

Task 7 将攻破 dash 的防御机制,先恢复 /bin/sh 的指向:

1
sudo ln -sf /bin/dash /bin/sh

不使用setuid(0)系统调用:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021170528716.png

使用setuid(0)系统调用:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021170750192.png

获得 root shell。

证明对策已开启:

1
ls -l /bin/sh /bin/zsh /bin/dash

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021171136521.png

开启地址随机化:

1
sudo /sbin/sysctl -w kernel.randomize_va_space=2

攻击失败:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021211157663.png

使用如下 shell 脚本暴力破解:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
SECONDS=0
value=0
while true; do
	value=$(( $value + 1 ))
	duration=$SECONDS
	min=$(($duration / 60))
	sec=$(($duration % 60))
	echo "$min minutes and $sec seconds elapsed."
	echo "The program has been running $value times so far."
	./stack-L1
done

经过 12331 次尝试后获得 root shell。

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021211742695.png

关闭地址随机化:

1
sudo /sbin/sysctl -w kernel.randomize_va_space=0

重新攻击成功:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021212423975.png

重新编译 stack.c(默认开启 StackGuard 保护):

1
2
gcc -DBUF_SIZE=100 -z execstack -m32 -o stack-L1 stack.c
sudo chown root stack-L1 && sudo chmod 4755 stack-L1

攻击失败:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021213502738.png

重新编译 call_shellcode.c(默认开启 NX 保护):

1
2
3
4
gcc -m32 -o a32.out call_shellcode.c
gcc -o a64.out call_shellcode.c
sudo chown root a32.out a64.out
sudo chmod 4755 a32.out a64.out

攻击失败:

https://f005.backblazeb2.com/file/img-buckets-oqh/2023/10/image-20231021214435619.png