首页/新闻资讯/正文详情

CTF Linux 内核 Pwn:SMEP/SMAP 与用户代码不可执行防护的攻防全解析

发布时间:2026/9/25 14:49:45 来源:云帆数科 栏目:资讯中心
CTF Linux 内核 Pwn:SMEP/SMAP 与用户代码不可执行防护的攻防全解析
文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载本篇文章聚焦 CTF Linux 内核 Pwn 中最基础也最关键的防御机制——SMEPSupervisor Mode Execution Protection管理模式执行保护即内核态不可执行用户态代码。文章以仓库 user-code-execution.md 为主体结合仓库中 bypass-smep.md、ret2usr.md 与 basic-knowledge.md 的源码级佐证系统讲解 SMEP 的原理、开启/关闭方式、状态检测、绕过思路以及它与 ret2usr、KPTI 的攻防演进关系。读完本文你将能看懂 CTF 内核题中 boot 脚本的smep参数含义、用grep smep /proc/cpuinfo判断保护状态、理解 CR4 寄存器第 20 位的攻防意义并能复现强网杯 2018 core 一题中通过 ROP 关闭 SMEP 的完整提权流程。攻击起源ret2usr 与内核态执行用户代码在引入 SMEP 之前内核态代码可以直接执行用户态的代码。正如 user-code-execution.md 所述如果攻击者控制了内核中的执行流就可以转而执行处于用户态的代码。由于用户态代码是攻击者完全可控的攻击的构造与调试成本远低于在内核态构造复杂的 ROP 链因此这种手法在当时十分流行。仓库 ret2usr.md 对这种攻击做了精确定义在【未】开启 SMAP/SMEP 保护的情况下用户空间无法访问内核空间的数据但是内核空间可以访问/执行用户空间的数据因此ret2usr这种攻击手法应运而生——通过 kernel ROP 以内核的 ring 0 权限执行用户空间的代码以完成提权。具体来说ret2usr 的攻击流程为攻击者先在内核态找到一个漏洞如栈溢出劫持内核控制流将返回地址直接指向用户空间预先构造好的提权函数典型为调用commit_creds(prepare_kernel_cred(NULL))获得 root用户空间函数执行完毕后通过手工构造的swapgs; iretq汇编代码回到用户态并启动 shell。与常规 kernel ROP在内核空间用大量 gadget 完成提权并利用内核中已有的swapgs; iretq返回用户态相比ret2usr 的显著优势正如 ret2usr.md 总结的我们只需要劫持内核执行流而无需在内核空间构造复杂的 ROP 链条——在用户空间写一段提权代码显然比在难以调试的内核空间堆 gadget 简单得多。正是为了封堵这条捷径CPU 厂商与内核研究者提出当 CPU 处于内核态ring0时禁止执行用户态的代码。在 Linux 内核中这一防御措施的实现与指令集架构强相关——x86 下对应 SMEPARM 下对应 PXN。x86 下的实现SMEP 与 CR4 寄存器的第 20 位SMEPSupervisor Mode Execution Protection是 Intel 在 Ivy Bridge 一代处理器开始引入的硬件特性。其核心语义为当 CPU 处于 ring0管理模式/supervisor mode时尝试取指执行用户空间ring3页面上的代码会触发页错误page fault从而直接终结内核态跳去执行用户态代码这类攻击。在 x86 架构中SMEP 的开关由控制寄存器 CR4 决定。CR4 用于控制 CPU 的各种特性其中**第 20 位bit 20**标记 SMEP 是否开启置 1 表示开启保护置 0 表示关闭保护。仓库 user-code-execution.md 使用了 CR4 寄存器位图直观展示该布局与之配套的还有 SMAPSupervisor Mode Access Protection管理模式访问保护对应 user-data-access.md 的主题——CR4 第 21 位用于阻止内核态直接访问用户态的数据。两者通常同时开启正如 basic-knowledge.md 所概括的隔离矩阵默认用户态不可直接访问内核态的数据、执行内核态的代码SMEP内核态不可执行用户态的代码CR4 bit 20SMAP内核态不可访问用户态的数据CR4 bit 21KPTI用户态不可看到内核态的页表且内核态不可执行用户态的代码模拟。bypass-smep.md 中给出了一个可验证的 CR4 位解析示例当$CR4 0x1407f0 000 1 0100 0000 0111 1111 0000时SMEP 保护开启而 CR4 是可通过mov指令修改的因此只要执行mov cr4, 0x1407e0即 0x1407e0 对应 bit 20 为 0即可关闭 SMEP。用 GDB 调试内核时可用info registers cr4查看当前值及其启用的标志位例如(gdb) info registers cr4 cr4 0x3006f0 [ SMAP SMEP OSXMMEXCPT OSFXSR PGE MCE PAE PSE ]开启与关闭QEMU 参数与 GRUB 配置原文档给出了两种应用场景下的开关方法这里结合仓库其他文档中的实际用法做完整展开。默认状态开启SMEP 保护默认开启现代 x86_64 内核编译时默认启用CONFIG_X86_SMAP/CONFIG_X86_SMEP相关支持且硬件支持时默认使能。开启QEMU-append参数使用 QEMU 启动内核进行 CTF 调试时可在内核命令行-append选项中添加smep来开启qemu-system-x86_64 \ -cpu kvm64,smep,smap \ -kernel ./bzImage \ -initrd ./rootfs.cpio \ -append root/dev/ram rw consolettyS0 oopspanic panic1 quiet kaslr需要说明的是仓库 bypass-smep.md 与 ret2usr.md 中展示的典型写法是-cpu参数加smep如-cpu kvm64,smep,smap而 user-code-execution.md 写的是-append选项加smep。两者本质都是通过内核命令行/CPU 特性开关控制保护位实操中以前者-cpu显式声明 CPU 特性更为常见后者等价于在启动参数层面要求内核启用该特性。实际调试时无论用哪种写法都以/proc/cpuinfo与 GDB 中的 CR4 值为准进行确认。关闭GRUB 引导参数nosmep在真实机器上非 QEMU关闭 SMEP需要修改 GRUB 配置。在/etc/default/grub中向如下两行的...内追加nosmepGRUB_CMDLINE_LINUX_DEFAULTquiet GRUB_CMDLINE_LINUXinitrd/install/initrd.gz然后运行update-grub并重启系统即可关闭 SMEPsudo update-grub sudo reboot同理若需关闭 SMAP则追加nosmap参见 user-data-access.md。关闭QEMU-append/-cpu参数使用 QEMU 启动的内核可以在-append选项中添加nosmep来关闭 SMEP更常见的做法是在-cpu参数中使用负号前缀显式关闭如 ret2usr.md 中的写法#!/bin/sh qemu-system-x86_64 \ -enable-kvm \ -cpu host,-smep,-smap \ # ...状态查看/proc/cpuinfo 与 GDB通过 /proc/cpuinfo 检测在目标内核内执行如下命令若输出中发现smep字符串则说明 SMEP 已开启否则未开启grep smep /proc/cpuinfo其输出形如flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse ... smep smap ...在 QEMU 场景下也可以直接在宿主机上检查启动脚本确认保护是否开启例如 bypass-smep.md 中给出的排查方式$ cat run.sh | grep -i smep -cpu kvm64,smep,smap \通过 GDB 查看 CR4在调试内核时可用info registers cr4查看 CR4 当前值与启用的标志位直接确认 SMEP/SMAP 是否生效参见上文示例。Attack SMEP内核态修改 CR4 绕过虽然 SMEP 能拦住直接跳去执行用户代码但它并非不可绕过。原文档给出的核心思路是把 CR4 寄存器的第 20 位置 0从而重新允许内核态执行用户态代码。结合仓库 bypass-smep.md 的实战记录绕过分为两条技术路径。路径一ROP gadget 修改 CR4既然 CR4 可由mov指令写入那么在劫持控制流后攻击者可以在内核空间中搜索并串联可修改 CR4 的 gadget用 ROP 链完成关闭。由于 SMAP 与 SMEP 通常同时开启一般会直接给 CR4 赋值为0x6f0——该值同时将 bit 20SMEP与 bit 21SMAP清零从而一次性关闭两项保护。仓库中 user-code-execution.md 指出内核中修改 cr4 的代码最终会调用到native_write_cr4从另一个维度看内核中也存在固定的修改 cr4 代码片段例如refresh_pce、set_tsc_mode等函数中都有可利用的mov cr4, ...指令序列。这意味着若采用调用函数思路可尝试在内核中定位native_write_cr4并为之构造参数即 0x6f0若采用纯 gadget思路可搜索mov cr4, rax; ...; ret这类指令片段配合pop rdi; ret、and rax, rdi; ret等 gadget先读出当前 CR4 再用掩码清零目标位后写回。bypass-smep.md 给出的 2018 强网杯 core 一题解法正是后者先用mov rax, cr4; ...读出 CR4再用and rax, rdi与掩码0xffffffffffcfffff将 bit 20/21 清掉最后用mov cr4, rax; ...写回随后即可 ret2usr。其关键 ROP 片段如下注意地址已随 KASLR 加上偏移rop_chain[i] MOV_RAX_CR4_ADD_RSP_8_POP_RBP_RET kernel_offset; rop_chain[i] *(size_t*) arttnba3; /* 占位数据 */ rop_chain[i] *(size_t*) arttnba3; rop_chain[i] POP_RDI_RET kernel_offset; rop_chain[i] 0xffffffffffcfffff; /* 清除 SMEP(bit20)/SMAP(bit21) 的掩码 */ rop_chain[i] AND_RAX_RDI_RET kernel_offset; rop_chain[i] MOV_CR4_RAX_PUSH_RCX_POPFQ_RET kernel_offset; rop_chain[i] (size_t) ret2usr_attack; /* 关闭保护后直接跳到用户态提权函数 */当 SMEP 生效而攻击者未做绕过时直接 ret2usr 会触发内核报错并 panic。仓库 bypass-smep.md 中保留了实际运行失败时的截图证据报错信息明确提示无法执行用户态代码疑似 SMEP上述完整 exp含 canary 泄露、符号地址解析、ROP 链构造可在 bypass-smep.md 中查阅此处不再整段重复。路径二ret2dir —— 从地址映射维度绕过除了改 CR4还有另一种不碰寄存器的绕过思路——ret2dir。basic-knowledge.md 对其做了概括利用内核线性映射区对物理地址空间的完整映射找到用户空间对应页框的内核空间地址利用该内核地址完成对用户空间的访问即一个内核空间地址与一个用户空间地址映射到了同一个页框上。也就是说不再跳转去执行用户空间地址上的代码而是跳到同一物理页在内核线性映射区中的别名地址执行。由于该地址属于内核地址空间SMEP 无法识别它其实对应的是用户数据页从而绕过了检查。相关更深入的分析可参考仓库 ret2dir.md。补充访问用户数据与 copy_from/to_user顺带说明SMAP 负责的是访问而非执行用户态数据。仓库 user-data-access.md 指出即使开启 SMAP内核中也存在合法的用户数据访问通道copy_from_user与copy_to_user这两个函数会在拷贝期间临时清空禁止访问用户态内存的标志位这也是驱动与用户程序交换数据的标准途径。在绕过 SMAP 时同样可以借助这两个函数读写用户态内存。攻防演进KPTI 让 ret2usr 与 SMEP-bypass 成为过去式SMEP-bypass 的有效性还取决于另一个保护——KPTIKernel Page-Table Isolation。basic-knowledge.md 对 KPTI 与 ret2usr 的关系给出了明确的结论KPTI 同时还令内核页表中属于用户地址空间的部分不再拥有执行权限这使得 ret2usr 彻底成为过去式。其原理是开启 KPTI 后内核页表中的用户地址空间不再设置可执行位NX因此即使攻击者通过 ROP 成功把 CR4 的 SMEP 位清零内核去执行用户空间代码时仍会因对应页顶级表项没有执行权限而直接 panic。仓库 bypass-smep.md 结尾对此有同样清晰的判断对于开启了 KPTI 的内核而言内核页表的用户地址空间无执行权限因此当内核尝试执行用户空间代码时由于对应页顶级表项没有设置可执行位因此会直接 panic这意味着 ret2usr 已经是过去式了相应地与之伴生的 smep bypass 也便成为了过去式。因此面对现代 CTF 内核题目通常同时开启 KASLR、SMEP、SMAP、KPTI、FGKASLR 等正确的攻击路径是在内核空间中完成提权ROP 调用commit_creds(prepare_kernel_cred(NULL))再利用内核中已有的swapgs; iretq片段回到用户态而不是尝试跳去执行用户空间代码。仓库 kpti.md 与 kpti-bypass.md 详细讨论了该场景下的对抗手法可作延伸阅读。实战速查QEMU 启动与保护状态核对综合原文档与仓库其他实战文档给出一个可直接套用的 CTF 内核题启动与核对流程查看启动脚本确认保护配置。典型开启 SMEP/SMAP 的启动参数qemu-system-x86_64 \ -m 128M \ -cpu qemu64-v1,smep,smap \ -kernel ./bzImage \ -initrd ./rootfs.cpio \ -append root/dev/ram rw consolettyS0 oopspanic panic1 quiet kaslr \ -s \ -netdev user,idt0, -device e1000,netdevt0,idnic0 \ -nographic进入内核后核对状态grep smep /proc/cpuinfo # 有 smep 字符串则开启 grep smap /proc/cpuinfo # 有 smap 字符串则开启 cat /proc/cpuinfo | grep -i smep判断攻击路径若-append中无nopti/ptioff或内核较新默认 KPTI 开启则 ret2usr 不可行需走完整的内核空间 ROP若题目显式关闭了 KPTI 且仅开启 SMEP如部分老题则可先用 ROP 将 CR4 置为0x6f0关闭 SMEP/SMAP再 ret2usr 提权强网杯 2018 core 即此路线。关闭保护以便本地调试修改/etc/default/grub的GRUB_CMDLINE_LINUX_DEFAULT与GRUB_CMDLINE_LINUX追加nosmep nosmap执行update-grub后重启QEMU 场景则用-cpu host,-smep,-smap或-append ... nosmep nosmap。延伸阅读隔离机制总览默认、SMEP、SMAP、KPTI 的对照readme.mdSMAP用户数据不可访问专题user-data-access.mdKPTI 专题kpti.mdret2usr 完整原理与 2018 强网杯 core 原始 expret2usr.mdSMEP-bypass 完整分析含 CR4 gadget 链与完整 expbypass-smep.mdret2dir不修改 CR4 的 SMEP 绕过思路ret2dir.mdLinux 内核 Pwn 基础知识ring 模型、cred 提权、KASLR/SMAP/SMEP/KPTI 综述basic-knowledge.md赞分享文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载相关推荐ctf-wiki 内核 PwnSMEP/SMAP 防护原理与 ROP 绕过实战强网杯 2018 corectf wiki 内核 PwnSMEP/SMAP 防护原理与 ROP 绕过实战强网杯 2018 core 本文是 ctf wiki 内核 ROP 系列文章文档网络安全教程CTF 内核 pwn 防护系列Linux 内核 SMAPSupervisor Mode Access Protection原理、开关配置与绕过手法详解CTF 内核 pwn 防护系列Linux 内核 SMAPSupervisor Mode Access Protection原理、开关配置与绕过手法详解 在文档网络安全教程Linux 内核防御机制__ro_after_init 只读数据保护与 mmap_min_addr 空指针防护解析CTF-Wiki 内核 Pwn 篇Linux 内核防御机制 __ro_after_init 只读数据保护与 mmap_min_addr 空指针防护解析CTF Wiki 内核 Pwn 篇 导文档网络安全教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

AUTOSAR BSW开发核心链路与配置避坑指南
AUTOSAR BSW开发核心链路与配置避坑指南

AUTOSAR BSW 开发这个方向,刚入行的人最容易懵圈:资料多、模块多、工具链复杂,光是 NVM、COM、CANIF、ECUC 这些缩写就能把人绕晕。我当年从 MCAL 裸机开发转到 BSW 集成时,第一个月基本是在看文档和调配置中度过的,很… · 2026/9/25 14:49:45

【Codex】用PPT文案额外描述优化课件生成细节:TaoToken统一Key接入与config.toml配置实战
【Codex】用PPT文案额外描述优化课件生成细节:TaoToken统一Key接入与config.toml配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 14:49:33

OpenShell Docker 计算驱动(openshell-driver-docker)深度解析:双容器隔离架构、身份解析与安全配置实战
OpenShell Docker 计算驱动(openshell-driver-docker)深度解析:双容器隔离架构、身份解析与安全配置实战

【免费下载链接】OpenShell OpenShell is the safe, private runtime for autonomous AI agents. 项目地址: https://gitcode.com/gh_mirrors/op/OpenShell 点击查看 免费下载 OpenShell 的 Docker 计算驱动为本地与远程 OpenShell Gateway 提供基于 Docker 的沙箱… · 2026/9/25 14:49:33

SQL注入之报错注入原理与实战:从报错函数到靶场通关
SQL注入之报错注入原理与实战:从报错函数到靶场通关

1. 报错注入到底是啥:先搞懂"报错"这个动作的本质很多人第一次听说"报错注入"的时候,脑子里第一反应是:数据库都报错了,这不等于告诉管理员有人在搞事吗?还能利用报错来拿数据?我自己最… · 2026/9/25 15:20:46

Atlas 300V 24G推理卡部署YOLOv8实战:环境搭建、模型转换与性能调优
Atlas 300V 24G推理卡部署YOLOv8实战:环境搭建、模型转换与性能调优

有没有被"atlas"这个词绕晕过?最近后台好几个朋友都在问同一个问题:Atlas 300V 24G到底是不是运算加速卡,以及怎么拿它在本地部署YOLO。我自己在边缘端做过几轮目标检测方案选型,把Atlas 300V这块卡从通电到跑起YOLOv8的… · 2026/9/25 15:20:33

在 VS Code 中,一键安装 MCP Server!TaoToken 统一 Key 配置实战
在 VS Code 中,一键安装 MCP Server!TaoToken 统一 Key 配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 15:20:15

swagger-codegen 生成 Java 客户端 FakeApi 全端点实战指南:okhttp4-gson-parcelableModel 版本解析与调用
swagger-codegen 生成 Java 客户端 FakeApi 全端点实战指南:okhttp4-gson-parcelableModel 版本解析与调用

开发工具代码生成API设计 【免费下载链接】swagger-codegen swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition. 项目地址: http… · 2026/9/25 15:20:15

Agent技能系统设计指南:从Prompt堆砌到稳定落地的工程实践
Agent技能系统设计指南:从Prompt堆砌到稳定落地的工程实践

做了大半年AI Agent应用,我最深的感受是:会聊天的模型到处都是,能稳定干活的Agent万里挑一。刚开始做Agent时我跟大多数人的思路一样——把Prompt写得越来越长,把工具越堆越多,结果模型反而越来越"飘"&#… · 2026/9/25 15:20:09

从浏览器触发 AWS Lambda 的跨服务示例实战——基于 aws-doc-sdk-examples 的 lambda-for-browser 教程
从浏览器触发 AWS Lambda 的跨服务示例实战——基于 aws-doc-sdk-examples 的 lambda-for-browser 教程

示例工程教程后端 【免费下载链接】aws-doc-sdk-examples Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below. 项目地… · 2026/9/25 15:20:09

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码