Files
Sec-Interview/Chapter26/26-2.md
T
2025-09-25 04:04:35 +08:00

54 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
### 讲讲 Linux 平台的漏洞缓解机制
**1. 堆栈保护(Stack Smashing Protection, SSP**
这是最基础,也是最重要的堆栈溢出缓解机制
- **原理:** 在函数调用时,编译器会在栈上的**局部变量和返回地址之间插入一个随机的“金丝雀值”(Canary Value**
- **工作方式:**
- 函数进入时,金丝雀值被推入栈中
- 函数返回前,程序会检查这个金丝雀值是否被改变
- 如果金丝雀值被修改,说明发生了缓冲区溢出,程序会立即终止(通常会调用 `__stack_chk_fail` 函数),而不是让攻击者控制程序流
- **局限性:** 攻击者可以通过覆盖低地址的变量或利用其他漏洞(如格式化字符串漏洞)来泄露金丝雀值,从而绕过此保护
**2. 地址空间布局随机化(Address Space Layout Randomization, ASLR**
ASLR 是一个非常有效的漏洞缓解机制,它让攻击者难以预测内存中关键数据的位置
- **原理:** 每次程序启动时,ASLR 会将程序的主要内存区域(如**可执行文件基址、堆、栈和共享库(DLL/SO)**)加载到随机的地址上
- **工作方式:** 攻击者在利用漏洞时,通常需要知道某个函数(例如 `system` 函数)或某个数据(例如返回地址)的精确内存地址。ASLR 打破了这种确定性,使得攻击者无法在不知道这些地址的情况下构造 ROP 链(Return-Oriented Programming
- **局限性:**
- **熵不足:** 早期版本的 ASLR 随机化范围有限,攻击者可以通过暴力破解或多次尝试来绕过
- **信息泄露:** 如果程序存在信息泄露漏洞(如格式化字符串漏洞),攻击者可以泄露出某个模块的基址,从而推算出其他所有函数的地址,绕过 ASLR
**3. 不可执行内存(Non-Executable Memory/ NX 位(No-eXecute**
这是为了防止攻击者将恶意代码注入数据段(如堆或栈)并执行而设计的
- **原理:** CPU 的 MMU(内存管理单元)会根据内存页的权限来决定是否允许执行该页中的代码。NX 位被设置在页表项中,如果该位为 1,则该页不可执行
- **工作方式:** 操作系统会将堆、栈等数据段标记为**不可执行**。当攻击者利用缓冲区溢出将 Shellcode(恶意代码)写入栈上并尝试执行时,CPU 会抛出异常,阻止代码的执行
- **局限性:**
- **ROP 攻击:** ROPReturn-Oriented Programming)是一种绕过 NX 位的方法。攻击者不注入代码,而是通过利用程序本身已有的代码片段(称为“gadgets”),并精心构造返回地址链来执行恶意逻辑
- **JIT(即时编译)代码:** 对于一些需要动态生成和执行代码的应用程序(如 Java 或 JavaScript 引擎),它们需要创建可执行的内存区域,这可能会被攻击者利用
**4. 只读重定位(Read-Only Relocations, RELRO**
RELRO 旨在保护程序在加载后不被修改,特别是全局偏移表(GOT)和过程链接表(PLT)
- **原理:**
- **GOTGlobal Offset Table):** 存储了外部共享库函数的实际地址
- **PLTProcedure Linkage Table):** 负责将函数调用重定向到 GOT
- **工作方式:**
- **部分 RELRO:** 在程序加载时,`.got` 段是可写的,因为加载器需要填充外部函数的地址。加载后,`.got` 段变为只读
- **完全 RELRO:** 将 GOT 表完全设置为只读,所有重定位都在程序加载前完成
- **局限性:** 攻击者无法再利用 GOT 覆写漏洞来劫持程序流。然而,它并不能防御所有类型的攻击
**5. 控制流完整性(Control Flow Integrity, CFI**
CFI 是一种更高级的保护机制,它旨在确保程序执行的控制流不会被攻击者劫持
- **原理:** CFI 在编译和链接阶段为每个间接调用(如函数指针调用)和返回指令创建元数据,并在运行时检查这些元数据,确保控制流的跳转是合法的、预期的
- **工作方式:**
- **向前边沿 CFIForward-Edge):** 保护间接函数调用,确保函数指针只能跳转到其类型兼容的函数
- **向后边沿 CFIBackward-Edge):** 保护函数返回,确保返回地址不会被篡改
- **局限性:** CFI 的实现较为复杂,并且可能引入性能开销。虽然能防御 ROP 攻击,但并不能防御所有类型的攻击,且可以被绕过