
1) 【一句话结论】缓冲区溢出是程序因边界检查缺失导致输入数据覆盖函数返回地址等控制流信息,从而执行任意代码;360通过数据执行保护(DEP)禁止栈/堆上代码执行、地址空间布局随机化(ASLR)随机化内存地址来防护该漏洞。
2) 【原理/概念讲解】程序调用函数时,栈帧中会保存局部变量、函数参数、返回地址(即函数执行完毕后跳转的地址)。当用户输入数据超过缓冲区大小,就会发生“溢出”,将多余数据写入缓冲区后,继续覆盖栈上的返回地址,将其改写为恶意代码的地址。此时程序执行流程被劫持,跳转到恶意代码执行。类比:把栈想象成一个“数据容器”,每个函数调用容器顶部放一个“返回标签”(标记跳转位置),若输入数据装得太多,容器溢出后,标签被恶意代码的标签替换,程序就会跳转到恶意代码执行。
3) 【对比与适用场景】
| 对比项 | 缓冲区溢出漏洞 | 360防护机制(DEP/ASLR) |
|---|---|---|
| 定义 | 程序因边界检查不足导致数据溢出覆盖控制流 | DEP禁止栈/堆上代码执行;ASLR随机化内存地址 |
| 核心利用目标 | 返回地址(控制流信息) | 阻止代码执行(DEP)、随机化地址(ASLR) |
| 发生位置 | 栈(函数调用时局部变量区) | 栈(DEP)、程序加载地址(ASLR) |
| 典型触发条件 | 输入数据长度 > 缓冲区大小 | 系统开启DEP/ASLR(现代系统默认开启) |
| 注意点 | 需精确计算偏移量覆盖返回地址 | 部分旧系统可能未开启,需结合其他漏洞利用 |
4) 【示例】
C语言栈溢出伪代码(展示偏移量计算):
void vulnerable_func(char *input) {
char buffer[8]; // 缓冲区大小8字节
strcpy(buffer, input); // 无边界检查,若input长度>8,溢出覆盖返回地址
}
int main() {
char large_input[20] = "A" * 20; // 输入长度20,超过buffer的8
vulnerable_func(large_input);
// 栈帧偏移:buffer在栈顶,返回地址在buffer之后(偏移量如8+4=12字节,假设返回地址4字节)
// 输入20字节,strcpy会将前8字节写入buffer,剩余12字节覆盖返回地址
}
解释:栈帧中,buffer在栈顶,返回地址在buffer之后(偏移量如8+4=12字节,假设返回地址4字节)。当输入20字节,strcpy会将前8字节写入buffer,剩余12字节覆盖返回地址,将其改写为shellcode地址,程序跳转执行shellcode。
5) 【面试口播版答案】
“面试官您好,我来回答缓冲区溢出漏洞的问题。核心结论是:缓冲区溢出是程序因边界检查缺失导致输入数据覆盖函数返回地址等控制流信息,从而执行任意代码;360通过数据执行保护(DEP)禁止栈/堆上代码执行、地址空间布局随机化(ASLR)随机化内存地址来防护该漏洞。
原理上,程序调用函数时,栈帧中会保存局部变量、函数参数、返回地址(即函数执行完毕后跳转的地址)。当用户输入数据超过缓冲区大小,就会发生“溢出”,将多余数据写入缓冲区后,继续覆盖栈上的返回地址,将其改写为恶意代码的地址。此时程序执行流程被劫持,跳转到恶意代码执行。比如把栈想象成一个“数据容器”,每个函数调用容器顶部放一个“返回标签”(标记跳转位置),若输入数据装得太多,容器溢出后,标签被恶意代码的标签替换,程序就会跳转到恶意代码执行。
利用步骤通常包括:1. 确定缓冲区大小和偏移量(通过fuzzing工具测试不同输入长度,找到覆盖返回地址的精确长度,比如用A*n测试,直到返回地址被覆盖);2. 构造payload,包含NOP滑板(填充0x90指令,使跳转地址落在滑板内,确保跳转后能执行shellcode);3. 在payload末尾放置shellcode(恶意代码,如系统调用指令);4. 发送payload触发溢出,覆盖返回地址为shellcode地址,执行任意代码。
360的防护方面,DEP(数据执行保护)通过CPU的NX(No-Execute)标志位标记栈/堆为不可执行区域,即使覆盖了返回地址,也无法执行恶意代码;ASLR(地址空间布局随机化)通过操作系统随机化程序加载基址、库文件基址、堆栈基址,每次运行这些地址不同,攻击者难以预测目标地址,从而增加利用难度。
总结:缓冲区溢出通过覆盖控制流信息实现任意代码执行,而360通过DEP(禁止执行)和ASLR(随机化地址)从执行权限和地址预测两个层面进行防护。”
6) 【追问清单】
7) 【常见坑/雷区】