Android内核漏洞学习——CVE-2014-3153分析(1)
字数 1995 2025-08-26 22:11:39

CVE-2014-3153 Android内核漏洞分析与利用教学文档

1. 漏洞概述

CVE-2014-3153是一个影响广泛的Linux内核提权漏洞,在Android系统中尤为著名。该漏洞由著名黑客Geohot利用并开发出TowelRoot工具,实现了简单粗暴的Android root提权。

漏洞本质是Linux内核中的use-after-free漏洞,涉及Futex(Fast Userspace muTexes)机制的实现问题。

2. Futex基础

2.1 Futex概念

Futex(快速用户空间互斥体)设计目的是加速glibc层的互斥访问速度,其核心思想是:

  • 在用户空间检查竞争情况
  • 无竞争时避免陷入内核,减少开销
  • 必要时才进入内核处理

2.2 Futex系统调用

主要系统调用接口:

long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, 
             u32 __user *uaddr2, u32 val2, u32 val3)

操作类型(op)包括:

  • FUTEX_WAIT/FUTEX_WAKE:基本阻塞/唤醒操作
  • FUTEX_LOCK_PI/FUTEX_UNLOCK_PI:优先级继承锁操作
  • FUTEX_WAIT_REQUEUE_PI/FUTEX_CMP_REQUEUE_PI:涉及漏洞的关键操作

3. 漏洞成因分析

3.1 Relock问题

futex_lock_pi_atomic函数中存在relock问题:

static int futex_lock_pi_atomic(u32 __user *uaddr, ...)
{
    // 尝试获取锁:比较uaddr是否为0,若是则设置为TID
    if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
        return -EFAULT;
    
    // 如果获取成功(curval为0)
    if (unlikely(!curval))
        return 1;
    ...
}

问题:uaddr是用户空间变量,攻击者可手动设为0,绕过锁检查实现重复上锁,导致:

  • 未调用futex_unlock_pi释放锁就再次上锁
  • 遗漏必要的收尾工作(如唤醒阻塞线程、修改pi_state等)

3.2 Requeue问题

涉及两个关键函数:

  1. futex_wait_requeue_pi:在uaddr1上等待,准备被移动到uaddr2
  2. futex_requeue:唤醒uaddr1最高优先级线程,并将等待线程转移到uaddr2

问题调用序列

  1. futex_wait_requeue_pi(uaddr1, uaddr2) - 正常等待
  2. futex_requeue(uaddr1, uaddr2) - 正常唤醒,返回1(成功)
  3. futex_requeue(uaddr2, uaddr2) - 异常调用,返回0xffffffea(导致crash)

根本原因:内核未检查uaddr1和uaddr2是否相同,允许不合逻辑的自引用调用。

4. 漏洞利用原理

4.1 利用步骤

  1. 初始锁定

    • 线程1调用futex_lock_pi(&B)成功锁定B,B值设为线程TID
  2. 等待requeue

    • 线程2调用futex_wait_requeue_pi(&A, &B)
    • 初始化futex_qrt_mutex_waiter结构体
    • 在A上等待,futex_q加入A的PI chain
  3. 首次requeue尝试

    • 线程1调用futex_requeue_pi(&A, &B)
    • futex_proxy_trylock_atomic尝试获取B锁失败
    • rt_mutex_start_proxy_lock也失败
    • 线程2阻塞在B的rt_mutex上,rt_waiter加入waiter list
  4. 用户态解锁

    • 利用relock漏洞,用户态将B设为0
  5. 异常requeue调用

    • 调用futex_requeue_pi(&B, &B)
    • futex_proxy_trylock_atomic再次被调用
    • 因B=0,futex_lock_pi_atomic成功获取锁
    • requeue_pi_wake_futex唤醒线程2
    • q->rt_waiter被置NULL
  6. UAF触发

    • futex_wait_requeue_pi认为未进入内核等待
    • 未清理rt_waiter(实际已在栈上)
    • 线程结束后回收等待链表,引用未清理的rt_waiter导致use-after-free

4.2 关键数据结构

  • futex_q:表示一个futex等待队列项
  • rt_mutex_waiter:实时互斥锁的等待者结构
  • pi_state:优先级继承状态

5. 漏洞利用代码分析

典型利用模式伪代码:

// 线程1
futex_lock_pi(&B);  // 锁定B

// 线程2
futex_wait_requeue_pi(&A, &B);  // 在A上等待被移动到B

// 线程1
futex_requeue_pi(&A, &B);  // 尝试将线程2从A移动到B
*(int*)&B = 0;              // 用户态解锁B
futex_requeue_pi(&B, &B);   // 触发漏洞的关键调用

// 此时已造成rt_waiter的UAF条件

6. 防护与修复

修复措施包括:

  1. 添加uaddr1和uaddr2相同性检查
  2. 完善锁状态管理,防止relock
  3. 加强rt_waiter生命周期管理

7. 参考资源

  1. Linux内核源码:kernel/futex.c
  2. 《漏洞战争》CVE-2014-3153章节
  3. 相关技术博客分析文章

8. 教学实验建议

实验环境搭建:

  • 受影响内核版本(如Linux 3.4)
  • QEMU模拟环境
  • 配套的漏洞利用代码

实验步骤:

  1. 复现基本崩溃
  2. 分析崩溃时的内核状态
  3. 构造完整提权利用
  4. 验证修复方案的有效性

注意:本漏洞涉及内核关键数据结构操作,实验需在可控环境中进行,避免影响生产系统。

CVE-2014-3153 Android内核漏洞分析与利用教学文档 1. 漏洞概述 CVE-2014-3153是一个影响广泛的Linux内核提权漏洞,在Android系统中尤为著名。该漏洞由著名黑客Geohot利用并开发出TowelRoot工具,实现了简单粗暴的Android root提权。 漏洞本质是Linux内核中的use-after-free漏洞,涉及Futex(Fast Userspace muTexes)机制的实现问题。 2. Futex基础 2.1 Futex概念 Futex(快速用户空间互斥体)设计目的是加速glibc层的互斥访问速度,其核心思想是: 在用户空间检查竞争情况 无竞争时避免陷入内核,减少开销 必要时才进入内核处理 2.2 Futex系统调用 主要系统调用接口: 操作类型(op)包括: FUTEX_WAIT / FUTEX_WAKE :基本阻塞/唤醒操作 FUTEX_LOCK_PI / FUTEX_UNLOCK_PI :优先级继承锁操作 FUTEX_WAIT_REQUEUE_PI / FUTEX_CMP_REQUEUE_PI :涉及漏洞的关键操作 3. 漏洞成因分析 3.1 Relock问题 在 futex_lock_pi_atomic 函数中存在relock问题: 问题 :uaddr是用户空间变量,攻击者可手动设为0,绕过锁检查实现重复上锁,导致: 未调用 futex_unlock_pi 释放锁就再次上锁 遗漏必要的收尾工作(如唤醒阻塞线程、修改pi_ state等) 3.2 Requeue问题 涉及两个关键函数: futex_wait_requeue_pi :在uaddr1上等待,准备被移动到uaddr2 futex_requeue :唤醒uaddr1最高优先级线程,并将等待线程转移到uaddr2 问题调用序列 : futex_wait_requeue_pi(uaddr1, uaddr2) - 正常等待 futex_requeue(uaddr1, uaddr2) - 正常唤醒,返回1(成功) futex_requeue(uaddr2, uaddr2) - 异常调用,返回0xffffffea(导致crash) 根本原因 :内核未检查uaddr1和uaddr2是否相同,允许不合逻辑的自引用调用。 4. 漏洞利用原理 4.1 利用步骤 初始锁定 : 线程1调用 futex_lock_pi(&B) 成功锁定B,B值设为线程TID 等待requeue : 线程2调用 futex_wait_requeue_pi(&A, &B) 初始化 futex_q 和 rt_mutex_waiter 结构体 在A上等待, futex_q 加入A的PI chain 首次requeue尝试 : 线程1调用 futex_requeue_pi(&A, &B) futex_proxy_trylock_atomic 尝试获取B锁失败 rt_mutex_start_proxy_lock 也失败 线程2阻塞在B的rt_ mutex上, rt_waiter 加入waiter list 用户态解锁 : 利用relock漏洞,用户态将B设为0 异常requeue调用 : 调用 futex_requeue_pi(&B, &B) futex_proxy_trylock_atomic 再次被调用 因B=0, futex_lock_pi_atomic 成功获取锁 requeue_pi_wake_futex 唤醒线程2 q->rt_waiter 被置NULL UAF触发 : futex_wait_requeue_pi 认为未进入内核等待 未清理 rt_waiter (实际已在栈上) 线程结束后回收等待链表,引用未清理的 rt_waiter 导致use-after-free 4.2 关键数据结构 futex_q :表示一个futex等待队列项 rt_mutex_waiter :实时互斥锁的等待者结构 pi_state :优先级继承状态 5. 漏洞利用代码分析 典型利用模式伪代码: 6. 防护与修复 修复措施包括: 添加uaddr1和uaddr2相同性检查 完善锁状态管理,防止relock 加强 rt_waiter 生命周期管理 7. 参考资源 Linux内核源码: kernel/futex.c 《漏洞战争》CVE-2014-3153章节 相关技术博客分析文章 8. 教学实验建议 实验环境搭建: 受影响内核版本(如Linux 3.4) QEMU模拟环境 配套的漏洞利用代码 实验步骤: 复现基本崩溃 分析崩溃时的内核状态 构造完整提权利用 验证修复方案的有效性 注意:本漏洞涉及内核关键数据结构操作,实验需在可控环境中进行,避免影响生产系统。