SEED Labs – Buffer Overflow Attack Lab (Set-UID Version)
相关链接
- Lab 网址:https://seedsecuritylabs.org/Labs_20.04/Software/Buffer_Overflow_Setuid/
- 任务书:https://seedsecuritylabs.org/Labs_20.04/Files/Buffer_Overflow_Setuid/Buffer_Overflow_Setuid.pdf
- VM 手册:https://github.com/seed-labs/seed-labs/blob/master/manuals/vm/seedvm-manual.md
Environment Setup
关闭地址空间随机化:
|
|
将 /bin/sh 链接到没有对策的 shell:
|
|
Task 1
|
|
获得普通 shell。
Task 2 & Task 3
使用 gdb 调试 stack-L1-dbg 打印 ebp 的值和 buffer 的地址。
|
|
需要注意的是,从 gdb 获取的帧指针值与实际执行时不同。 这是因为 gdb 在运行被调试程序之前已经将一些环境数据压入了栈。 当程序直接运行时,堆栈中没有那些数据,因此实际的帧指针值会更大。
对 exploit.py 作如下修改:
start = 517 - len(shellcode) 将 shellcode 放在 content 的末尾。0xffffcb58 是之前调试得到的 ebp 值,这里没有使用 ebp + 8 而是 ebp + 100 作为返回地址的原因是调试时的栈帧可能比直接运行程序时的栈帧更深一点。为了覆盖返回地址,offset = ebp - &buffer + 4 = 112。
发起攻击,获得 root shell。
Task 4
要在未知缓冲区大小的情况下发起攻击。任务书提供的信息有:缓冲区大小为 100~200 字节;帧指针的始终是 4 的倍数,这意味着返回地址的地址也是 4 的倍数。
使用 gdb 调试 stack-L2-dbg 打印 ebp 的值:
对 exploit.py 作如下修改:
根据 Task3 及缓冲区大小为 100~200 字节,可以猜测,offset 的大小为 112~212,因此只需将 content 的这一段区域每 4 个字节填充恶意返回地址。ret 的值为 ebp + 200,比之前更大,这是为了防止缓冲区较小时,无法跳转到 NOP 指令。
发起攻击,获得 root shell。
Task 5
使用 gdb 调试 stack-L3-dbg 打印 rbp 的值和 buffer 的地址。
对 exploit.py 作如下修改:
由于 64 位地址最高 2 个字节始终为 0,strcpy()
遇 0 停止拷贝,因此 shellcode 应放在返回地址覆盖区域之前。start 应在返回地址覆盖区域之前尽可能地靠后,这样可以增加 NOP 指令的范围,使 shellcode 更容易被执行。但也不能靠到最后,否则会覆盖掉一些关键数据,导致攻击失败,实测 start 最大值为 162。实验中还发现了满足攻击 ret 的增量最小为 80,这说明调试时的栈帧比直接运行程序时的栈帧深了 80。start = 100,ret = 0x00007fffffffd920 + 100 是满足攻击的一组值。
发起攻击,获得 root shell。
Task 6
程序的缓冲区大小只有 10,无法放下 shellcode,也没有办法将 shellcode 复制到高地址。其实,在strcpy()
执行之前,我们可以打印 str 的地址并利用,str 存储了完整的 shellcode。为求偏移量,继续打印 rbp 和 buffer 的地址。
对 exploit.py 作如下修改:
offset = rbp - &buffer + 8 = 18。为了顺利执行 shellcode,我们希望 ret 跳转到字符串中返回地址与 shellcode 之间的 NOP 指令区域,对应 content 从 26 到 487。由 Task5 可得,程序实际运行时,栈的地址会增加 80,故 ret 增量的理论合适范围是 [106, 567],实测为 [106, 568]。这种攻击方式同样适用于上面已知缓冲区大小的情况。
发起攻击,获得 root shell。
Task 7
Task 7 将攻破 dash 的防御机制,先恢复 /bin/sh 的指向:
|
|
不使用setuid(0)
系统调用:
使用setuid(0)
系统调用:
获得 root shell。
证明对策已开启:
|
|
Task 8
开启地址随机化:
|
|
攻击失败:
使用如下 shell 脚本暴力破解:
|
|
经过 12331 次尝试后获得 root shell。
Task 9
关闭地址随机化:
|
|
重新攻击成功:
重新编译 stack.c(默认开启 StackGuard 保护):
|
|
攻击失败:
重新编译 call_shellcode.c(默认开启 NX 保护):
|
|
攻击失败: