1. 漏洞背景与环境准备CVE-2024-1086是Linux内核netfilter子系统中nf_tables组件的一个高危漏洞属于典型的UAFUse-After-Free类型。这个漏洞影响范围相当广从v3.15到v6.8-rc1的内核版本都可能中招特别是v5.14到v6.6之间的版本风险最高。我在第一次尝试复现时就因为这个版本范围判断失误浪费了不少时间。搭建实验环境时我强烈建议使用虚拟机。我选择了Ubuntu 22.04作为基础系统主要考虑两点一是这个LTS版本稳定性好二是官方仓库提供了丰富的内核版本选择。最开始我图省事直接用了系统默认的5.15内核结果发现根本不在漏洞影响范围内只能重头再来。准备工具链时这几个包必不可少sudo apt install make gcc fakeroot build-essential \ ncurses-dev xz-utils libssl-dev bc flex libelf-dev \ bison dwarves zstd特别是dwarves这个包很多教程里都没提但在编译新版本内核时缺了它就会报错。我在这里栽过跟头编译到一半突然失败排查半天才发现是这个依赖没装。2. 内核编译的坑与技巧2.1 源码获取与配置从清华镜像站下载内核源码确实快很多wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v6.x/linux-6.3.13.tar.xz tar -xf linux-6.3.13.tar.xz cd linux-6.3.13关键的一步是内核配置。新手最容易犯的错误就是直接复制别人的.config文件。我有次偷懒用了网上找的配置结果编译出来的内核连网卡驱动都没带虚拟机直接断网。现在我的做法是make defconfig # 生成默认配置 make menuconfig # 手动调整在menuconfig界面里要特别注意这几个选项CONFIG_NF_TABLES 必须启用默认是模块形式CONFIG_USER_NS 要打开CONFIG_STATIC_USERMODEHELPER 建议编译进内核2.2 编译加速技巧第一次完整编译内核花了我将近两小时后来发现几个提速诀窍使用-j$(nproc)参数充分利用CPU核心先make -j$(nproc)编译内核再单独make modules如果只是修改配置重新编译可以跳过make clean实测下来8核机器上完整编译大约40分钟增量编译只需5-10分钟。记得编译前先free -h看看内存小于8GB容易爆内存。3. 漏洞复现的曲折历程3.1 第一次失败尝试按照网上的教程我下载了漏洞利用代码git clone https://github.com/Notselwyn/CVE-2024-1086 cd CVE-2024-1086 make运行后却卡在了这一步[!] failed to find kernel code segment... CONFIG_STATIC_USERMODEHELPER disabled?检查发现确实是内核配置问题。这里有个细节即使.config文件里设置了CONFIG_STATIC_USERMODEHELPERy实际编译时也可能因为依赖项不满足而被自动禁用。正确的验证方式是grep CONFIG_STATIC_USERMODEHELPER /boot/config-$(uname -r)3.2 成功复现的关键换了6.1.72内核后终于成功。这个版本有个优势Ubuntu官方提供了预编译包省去编译时间wget https://kernel.ubuntu.com/mainline/v6.1.72/amd64/linux-*.deb dpkg -i linux-*.deb reboot提权成功的瞬间终端里跳出那个梦寐以求的uid0(root)时真是有种通关打BOSS的成就感。完整的漏洞利用过程其实分几步创建用户命名空间CLONE_NEWUSER创建网络命名空间CLONE_NEWNET设置nftables规则触发UAF通过内存喷射spray控制执行流4. 漏洞缓解方案实测4.1 禁用nf_tables模块最直接的防护方法就是禁用问题模块echo blacklist nf_tables /etc/modprobe.d/blacklist.conf update-initramfs -u reboot验证是否生效lsmod | grep nf_tables # 应该无输出注意这会导致基于nftables的防火墙规则全部失效。如果系统在用firewalld记得先切回iptables模式firewall-cmd --set-backendiptables4.2 限制用户命名空间对于容器环境完全禁用用户命名空间可能影响太大。折中的方案是限制普通用户使用echo kernel.unprivileged_userns_clone0 /etc/sysctl.conf sysctl -p我在Docker环境中测试发现这会导致容器启动失败docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed...解决方案是给Docker授权sudo chmod us /usr/bin/docker5. 对容器环境的影响评估在K8s集群中直接禁用用户命名空间显然不现实。我的测试环境用kubeadm搭建发现两个关键点Containerd配置需要在/etc/containerd/config.toml中启用userns[plugins.io.containerd.grpc.v1.cri.containerd] userns_enable truePodSecurityPolicy需要允许privileged容器或者明确授权securityContext: runAsUser: 0 usernsOptions: mode: host性能方面启用用户命名空间会导致约5-10%的IO性能下降这点在数据库类容器中特别明显。我的测试数据显示MySQL容器在启用userns后TPS下降了约8%。6. 内核调试技巧分享在复现过程中这几个调试方法帮了大忙查看内核日志dmesg -wH | grep -i nft动态调试nf_tablesecho file nf_tables* p /sys/kernel/debug/dynamic_debug/control崩溃分析安装crash工具apt install crash crash /usr/lib/debug/boot/vmlinux-$(uname -r) /var/crash/xxx.crash有一次漏洞利用导致内核panic通过crash工具的bt命令查看调用栈很快就定位到是内存释放后又被引用的位置。7. 给安全研究新手的建议版本选择要谨慎我建议用6.1.x系列内核这个版本段资料多且稳定善用QEMU调试比纯虚拟机更方便观察内核行为qemu-system-x86_64 -kernel bzImage -append consolettyS0 -nographic保持实验记录我养成了用asciinema录屏的习惯能完整复现操作过程理解原理比复现更重要花时间研究漏洞的root cause比单纯提权更有价值记得第一次看到漏洞利用代码时那些内存操作看得我头皮发麻。后来把PoC拆解成小段单独测试才慢慢理解其中的精妙之处。比如这个spray技巧for (int i 0; i 16000; i) { pipe2(pipefd, O_DIRECT); write(pipefd[1], buf, PAGE_SIZE); }其实就是通过大量管道占用内存提高UAF后控制目标内存的概率。
从CVE-2024-1086漏洞复现失败到成功:一次内核安全实践的技术复盘
1. 漏洞背景与环境准备CVE-2024-1086是Linux内核netfilter子系统中nf_tables组件的一个高危漏洞属于典型的UAFUse-After-Free类型。这个漏洞影响范围相当广从v3.15到v6.8-rc1的内核版本都可能中招特别是v5.14到v6.6之间的版本风险最高。我在第一次尝试复现时就因为这个版本范围判断失误浪费了不少时间。搭建实验环境时我强烈建议使用虚拟机。我选择了Ubuntu 22.04作为基础系统主要考虑两点一是这个LTS版本稳定性好二是官方仓库提供了丰富的内核版本选择。最开始我图省事直接用了系统默认的5.15内核结果发现根本不在漏洞影响范围内只能重头再来。准备工具链时这几个包必不可少sudo apt install make gcc fakeroot build-essential \ ncurses-dev xz-utils libssl-dev bc flex libelf-dev \ bison dwarves zstd特别是dwarves这个包很多教程里都没提但在编译新版本内核时缺了它就会报错。我在这里栽过跟头编译到一半突然失败排查半天才发现是这个依赖没装。2. 内核编译的坑与技巧2.1 源码获取与配置从清华镜像站下载内核源码确实快很多wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v6.x/linux-6.3.13.tar.xz tar -xf linux-6.3.13.tar.xz cd linux-6.3.13关键的一步是内核配置。新手最容易犯的错误就是直接复制别人的.config文件。我有次偷懒用了网上找的配置结果编译出来的内核连网卡驱动都没带虚拟机直接断网。现在我的做法是make defconfig # 生成默认配置 make menuconfig # 手动调整在menuconfig界面里要特别注意这几个选项CONFIG_NF_TABLES 必须启用默认是模块形式CONFIG_USER_NS 要打开CONFIG_STATIC_USERMODEHELPER 建议编译进内核2.2 编译加速技巧第一次完整编译内核花了我将近两小时后来发现几个提速诀窍使用-j$(nproc)参数充分利用CPU核心先make -j$(nproc)编译内核再单独make modules如果只是修改配置重新编译可以跳过make clean实测下来8核机器上完整编译大约40分钟增量编译只需5-10分钟。记得编译前先free -h看看内存小于8GB容易爆内存。3. 漏洞复现的曲折历程3.1 第一次失败尝试按照网上的教程我下载了漏洞利用代码git clone https://github.com/Notselwyn/CVE-2024-1086 cd CVE-2024-1086 make运行后却卡在了这一步[!] failed to find kernel code segment... CONFIG_STATIC_USERMODEHELPER disabled?检查发现确实是内核配置问题。这里有个细节即使.config文件里设置了CONFIG_STATIC_USERMODEHELPERy实际编译时也可能因为依赖项不满足而被自动禁用。正确的验证方式是grep CONFIG_STATIC_USERMODEHELPER /boot/config-$(uname -r)3.2 成功复现的关键换了6.1.72内核后终于成功。这个版本有个优势Ubuntu官方提供了预编译包省去编译时间wget https://kernel.ubuntu.com/mainline/v6.1.72/amd64/linux-*.deb dpkg -i linux-*.deb reboot提权成功的瞬间终端里跳出那个梦寐以求的uid0(root)时真是有种通关打BOSS的成就感。完整的漏洞利用过程其实分几步创建用户命名空间CLONE_NEWUSER创建网络命名空间CLONE_NEWNET设置nftables规则触发UAF通过内存喷射spray控制执行流4. 漏洞缓解方案实测4.1 禁用nf_tables模块最直接的防护方法就是禁用问题模块echo blacklist nf_tables /etc/modprobe.d/blacklist.conf update-initramfs -u reboot验证是否生效lsmod | grep nf_tables # 应该无输出注意这会导致基于nftables的防火墙规则全部失效。如果系统在用firewalld记得先切回iptables模式firewall-cmd --set-backendiptables4.2 限制用户命名空间对于容器环境完全禁用用户命名空间可能影响太大。折中的方案是限制普通用户使用echo kernel.unprivileged_userns_clone0 /etc/sysctl.conf sysctl -p我在Docker环境中测试发现这会导致容器启动失败docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed...解决方案是给Docker授权sudo chmod us /usr/bin/docker5. 对容器环境的影响评估在K8s集群中直接禁用用户命名空间显然不现实。我的测试环境用kubeadm搭建发现两个关键点Containerd配置需要在/etc/containerd/config.toml中启用userns[plugins.io.containerd.grpc.v1.cri.containerd] userns_enable truePodSecurityPolicy需要允许privileged容器或者明确授权securityContext: runAsUser: 0 usernsOptions: mode: host性能方面启用用户命名空间会导致约5-10%的IO性能下降这点在数据库类容器中特别明显。我的测试数据显示MySQL容器在启用userns后TPS下降了约8%。6. 内核调试技巧分享在复现过程中这几个调试方法帮了大忙查看内核日志dmesg -wH | grep -i nft动态调试nf_tablesecho file nf_tables* p /sys/kernel/debug/dynamic_debug/control崩溃分析安装crash工具apt install crash crash /usr/lib/debug/boot/vmlinux-$(uname -r) /var/crash/xxx.crash有一次漏洞利用导致内核panic通过crash工具的bt命令查看调用栈很快就定位到是内存释放后又被引用的位置。7. 给安全研究新手的建议版本选择要谨慎我建议用6.1.x系列内核这个版本段资料多且稳定善用QEMU调试比纯虚拟机更方便观察内核行为qemu-system-x86_64 -kernel bzImage -append consolettyS0 -nographic保持实验记录我养成了用asciinema录屏的习惯能完整复现操作过程理解原理比复现更重要花时间研究漏洞的root cause比单纯提权更有价值记得第一次看到漏洞利用代码时那些内存操作看得我头皮发麻。后来把PoC拆解成小段单独测试才慢慢理解其中的精妙之处。比如这个spray技巧for (int i 0; i 16000; i) { pipe2(pipefd, O_DIRECT); write(pipefd[1], buf, PAGE_SIZE); }其实就是通过大量管道占用内存提高UAF后控制目标内存的概率。