在linux内核中利用递归
字数 1935 2025-08-20 18:17:07

Linux内核递归利用漏洞分析与利用教学

1. 漏洞背景与前提条件

1.1 Linux内核堆栈特性

Linux内核堆栈与用户空间堆栈有显著差异:

  • 大小限制

    • 32位x86架构:4096-8192字节
    • x86-64架构:16384字节
    • THREAD_SIZE_ORDERTHREAD_SIZE宏定义
  • 分配方式

    • 使用内核的buddy分配器分配
    • 没有防护页(guard page)保护
    • 溢出会导致与正常数据重叠

1.2 堆叠文件系统(Stacked Filesystem)

  • 定义:将另一个文件系统中的文件夹作为后备存储的文件系统
  • 常见类型
    • ecryptfs:透明加密文件系统
    • overlayfs:合并多个文件系统的统一视图
  • 潜在风险
    • 每层文件系统都会增加内核堆栈深度
    • 可能导致内核堆栈溢出
  • 防护措施
    • 通过FILESYSTEM_MAX_STACK_DEPTH限制嵌套层数(默认最多两层)

1.3 procfs特殊文件

  • /proc/[pid]/mem:暴露进程的整个虚拟地址空间
  • /proc/[pid]/environ:暴露进程的环境变量内存区域(mm->env_startmm->env_end)
  • /proc/[pid]/cmdline:暴露进程的命令行参数内存区域(mm->arg_startmm->arg_end)

2. 漏洞原理

2.1 漏洞形成机制

  1. ecryptfs的mmap特性

    • ecryptfs支持mmap操作
    • 不能简单转发到底层文件系统的mmap处理程序
    • 需要自己的页面缓存进行映射
    • 处理页面错误时使用底层文件系统的VFS读处理程序(kernel_read())
  2. 攻击链构建

    • 创建进程A,设置其环境变量区域指向有效加密数据
    • /proc/$A为底层文件系统创建ecryptfs挂载点
    • /tmp/$A/environ映射到进程B的内存
    • 重复此过程构建多层映射链
  3. 递归触发

    • 进程C访问映射区域触发页面错误
    • 错误处理导致ecryptfs从/proc/$B/environ读取
    • 进而导致进程B中的页面错误
    • 继续递归直到内核堆栈溢出

2.2 关键突破点

  • 环境变量区域控制

    • 使用prctl(PR_SET_MM, PR_SET_MM_MAP...)设置arg_startarg_endenv_startenv_end
    • 允许将proc文件指向任意虚拟内存范围
  • 堆栈布局利用

    • 精确控制递归深度
    • 利用堆栈帧中的"洞"避免破坏关键数据(如canary和thread_info结构)

3. 漏洞利用技术

3.1 利用步骤

  1. 设置初始进程

    • 创建进程A,加载有效加密的ecryptfs文件到其内存
    • 配置环境区域指向该加密数据
  2. 构建ecryptfs挂载

    • /proc/$A为底层文件系统创建ecryptfs挂载点
    • 访问/tmp/$A/environ获取解密视图
  3. 创建映射链

    • 将解密视图映射到进程B的内存
    • 重复此过程构建多层映射
  4. 触发递归

    • 在链的末端使用FUSE映射暂停执行
    • 通过管道分配内存覆盖堆栈
  5. 控制执行流

    • 精确覆盖返回地址
    • 绕过KASLR(若未启用)
    • 保持addr_limitKERNEL_DS

3.2 关键技术细节

  • 堆栈对齐技巧

    • 混合使用environcmdline文件(不同堆栈帧大小)
    • 结合write()系统调用和VFS写入处理程序控制深度
  • 内存操作原语

    void kernel_write(unsigned long addr, char *buf, size_t len) {
        int pipefds[2];
        pipe(pipefds);
        write(pipefds[1], buf, len);
        close(pipefds[1]);
        read(pipefds[0], (char *)addr, len);
        close(pipefds[0]);
    }
    
  • 权限提升

    • 覆盖coredump处理程序
    • 触发SIGSEGV以root权限执行处理程序
    char *core_handler = "|/tmp/crash_to_root";
    kernel_write(0xffffffff81e87a60, core_handler, strlen(core_handler)+1);
    

4. 漏洞修复

  1. 补丁1 (2f36db710093):

    • 禁止在没有mmap处理程序的情况下通过ecryptfs打开文件
  2. 补丁2 (e54ad7f1ee26):

    • 禁止在procfs之上堆叠任何文件系统
  3. 长期防护建议

    • 在内核堆栈添加防护页
    • 将thread_info结构从堆栈底部移除

5. 教学总结

关键知识点

  1. 理解Linux内核堆栈与用户空间堆栈的区别
  2. 掌握堆叠文件系统的工作原理和安全影响
  3. 学习procfs特殊文件的访问机制
  4. 掌握通过递归触发内核堆栈溢出的技术
  5. 学习精确控制堆栈布局和绕过防护的技术

实践建议

  1. 在实验环境中复现漏洞时,注意内核版本和配置
  2. 研究不同架构下的堆栈布局差异
  3. 探索现代内核防护机制(如KASLR、stack canary)的绕过技术
  4. 分析其他类型的递归导致的内核漏洞

防御措施

  1. 及时应用内核安全更新
  2. 启用所有可用的内核安全特性(KASLR等)
  3. 限制非特权用户的特殊文件系统访问
  4. 监控系统调用和proc文件访问的异常模式
Linux内核递归利用漏洞分析与利用教学 1. 漏洞背景与前提条件 1.1 Linux内核堆栈特性 Linux内核堆栈与用户空间堆栈有显著差异: 大小限制 : 32位x86架构:4096-8192字节 x86-64架构:16384字节 由 THREAD_SIZE_ORDER 和 THREAD_SIZE 宏定义 分配方式 : 使用内核的buddy分配器分配 没有防护页(guard page)保护 溢出会导致与正常数据重叠 1.2 堆叠文件系统(Stacked Filesystem) 定义 :将另一个文件系统中的文件夹作为后备存储的文件系统 常见类型 : ecryptfs:透明加密文件系统 overlayfs:合并多个文件系统的统一视图 潜在风险 : 每层文件系统都会增加内核堆栈深度 可能导致内核堆栈溢出 防护措施 : 通过 FILESYSTEM_MAX_STACK_DEPTH 限制嵌套层数(默认最多两层) 1.3 procfs特殊文件 /proc/[pid]/mem :暴露进程的整个虚拟地址空间 /proc/[pid]/environ :暴露进程的环境变量内存区域( mm->env_start 到 mm->env_end ) /proc/[pid]/cmdline :暴露进程的命令行参数内存区域( mm->arg_start 到 mm->arg_end ) 2. 漏洞原理 2.1 漏洞形成机制 ecryptfs的mmap特性 : ecryptfs支持mmap操作 不能简单转发到底层文件系统的mmap处理程序 需要自己的页面缓存进行映射 处理页面错误时使用底层文件系统的VFS读处理程序( kernel_read() ) 攻击链构建 : 创建进程A,设置其环境变量区域指向有效加密数据 以 /proc/$A 为底层文件系统创建ecryptfs挂载点 将 /tmp/$A/environ 映射到进程B的内存 重复此过程构建多层映射链 递归触发 : 进程C访问映射区域触发页面错误 错误处理导致ecryptfs从 /proc/$B/environ 读取 进而导致进程B中的页面错误 继续递归直到内核堆栈溢出 2.2 关键突破点 环境变量区域控制 : 使用 prctl(PR_SET_MM, PR_SET_MM_MAP...) 设置 arg_start 、 arg_end 、 env_start 和 env_end 允许将proc文件指向任意虚拟内存范围 堆栈布局利用 : 精确控制递归深度 利用堆栈帧中的"洞"避免破坏关键数据(如canary和thread_ info结构) 3. 漏洞利用技术 3.1 利用步骤 设置初始进程 : 创建进程A,加载有效加密的ecryptfs文件到其内存 配置环境区域指向该加密数据 构建ecryptfs挂载 : 以 /proc/$A 为底层文件系统创建ecryptfs挂载点 访问 /tmp/$A/environ 获取解密视图 创建映射链 : 将解密视图映射到进程B的内存 重复此过程构建多层映射 触发递归 : 在链的末端使用FUSE映射暂停执行 通过管道分配内存覆盖堆栈 控制执行流 : 精确覆盖返回地址 绕过KASLR(若未启用) 保持 addr_limit 为 KERNEL_DS 3.2 关键技术细节 堆栈对齐技巧 : 混合使用 environ 和 cmdline 文件(不同堆栈帧大小) 结合 write() 系统调用和VFS写入处理程序控制深度 内存操作原语 : 权限提升 : 覆盖coredump处理程序 触发SIGSEGV以root权限执行处理程序 4. 漏洞修复 补丁1 (2f36db710093): 禁止在没有mmap处理程序的情况下通过ecryptfs打开文件 补丁2 (e54ad7f1ee26): 禁止在procfs之上堆叠任何文件系统 长期防护建议 : 在内核堆栈添加防护页 将thread_ info结构从堆栈底部移除 5. 教学总结 关键知识点 理解Linux内核堆栈与用户空间堆栈的区别 掌握堆叠文件系统的工作原理和安全影响 学习procfs特殊文件的访问机制 掌握通过递归触发内核堆栈溢出的技术 学习精确控制堆栈布局和绕过防护的技术 实践建议 在实验环境中复现漏洞时,注意内核版本和配置 研究不同架构下的堆栈布局差异 探索现代内核防护机制(如KASLR、stack canary)的绕过技术 分析其他类型的递归导致的内核漏洞 防御措施 及时应用内核安全更新 启用所有可用的内核安全特性(KASLR等) 限制非特权用户的特殊文件系统访问 监控系统调用和proc文件访问的异常模式