SpiderMonkey 漏洞利用简介(一)
字数 1324 2025-08-03 16:49:35

SpiderMonkey 漏洞利用简介(一)

介绍

本文是SpiderMonkey JavaScript引擎漏洞利用系列的第一部分,主要介绍基础知识和背景。SpiderMonkey是Mozilla Firefox浏览器使用的JavaScript引擎,本文从一个从未编写过浏览器漏洞利用的开发者角度出发,介绍了如何开始研究JavaScript引擎漏洞利用。

环境设置

获取源码

Mozilla使用mercurial进行开发,但也维护只读的GIT镜像:

git clone --depth 1 https://github.com/mozilla/gecko-dev.git

编译JavaScript Shell

  1. 首先应用必要的补丁文件
  2. 安装Mozilla-Build工具链
  3. 配置x64调试版本:
autoconf-2.13
mkdir build.asserts
cd build.asserts
../configure --host=x86_64-pc-mingw32 --target=x86_64-pc-mingw32 --enable-debug
mozmake -j2

SpiderMonkey基础知识

JS::Values和JSObjects

JavaScript对象在内存中的表示:

  • JS::Value是JavaScript值的内部表示
  • 高17位(JSVAL_TAG)用于编码类型信息
  • 低47位(JSVAL_TAG_SHIFT)是普通类型的值或指向JSObject的指针

JS::Value结构

union alignas(8) Value {
  private:
    uint64_t asBits_;
    double asDouble_;

    struct {
        union {
            int32_t i32_;
            uint32_t u32_;
            JSWhyMagic why_;
        } payload_;

类型标记

enum JSValueType : uint8_t
{
    JSVAL_TYPE_DOUBLE = 0x00,
    JSVAL_TYPE_INT32 = 0x01,
    JSVAL_TYPE_BOOLEAN = 0x02,
    JSVAL_TYPE_UNDEFINED = 0x03,
    // ...其他类型
};

对象内存布局

JavaScript对象主要由两部分组成:

  1. 形状对象(Shape) - 描述属性
  2. 存储元素或属性值的存储槽(Slots)

对象层次结构

JSObject
  ↑
JS::ShapedObject
  ↑
JS::NativeObject
  ↑
JS::ArrayObject (和其他特定对象类型)

调试技巧

  • 使用Math.atan2设置断点
  • 使用objectAddress获取对象地址
  • 使用dumpObject查看对象详细信息

Shapes(形状)

Shape对象描述对象的属性:

  • 每个属性对应一个Shape对象
  • 通过父字段链接形成形状链
  • 包含属性名和槽号信息

Shape结构

class js::Shape {
    js::GCPtr<js::BaseShape *> base_;
    js::PreBarriered<jsid> propid_;  // 属性名
    uint32_t immutableFlags;         // 包含槽号信息
    uint8_t attrs;
    uint8_t mutableFlags;
    js::GCPtr<js::Shape *> parent;   // 父Shape
    js::KidsPointer kids;
};

属性查找示例

  1. 获取对象地址
  2. 找到shapeOrExpando_字段指向的Shape
  3. 遍历Shape链获取所有属性信息
  4. 从immutableFlags中提取槽号
  5. 在对象存储中查找对应槽的值

Slots(存储槽)

属性值存储在对象的内存区域中:

  • 紧接在对象头之后
  • 每个槽存储一个JS::Value
  • 数组有特殊的ObjectElements头存储长度信息

ObjectElements结构

struct js::ObjectElements {
    uint32_t flags;
    uint32_t initializedLength;
    uint32_t capacity;
    uint32_t length;  // 对于数组
};

数组内存布局示例

+-------------------+ 0x00
| group_            |
+-------------------+ 0x08
| shapeOrExpando_   |
+-------------------+ 0x10
| slots_            |
+-------------------+ 0x18
| elements_         |
+-------------------+ 0x20
| ObjectElements    |
| (flags, lengths)  |
+-------------------+ 0x30
| element[0]        |
+-------------------+ 0x38
| element[1]        |
+-------------------+ 
| ...               |

调试工具

sm.js扩展

作者开发了WinDbg JavaScript扩展sm.js,用于:

  • 查看SpiderMonkey内部结构
  • 检查对象内存布局
  • 辅助漏洞利用开发

TTD (Time Travel Debugging)

使用TTD可以:

  • 记录程序执行
  • 前后浏览执行历史
  • 更容易分析复杂对象状态变化

漏洞利用计划

作者计划分三步开发漏洞利用:

  1. basic.js - 针对特定版本js.exe的硬编码利用
  2. kaizen.js - 动态解析偏移,使用JIT生成ROP gadgets
  3. ifrit.js - 针对Firefox浏览器,使用JIT编写完整payload

总结

本文介绍了SpiderMonkey引擎的基础知识,包括:

  • JS::Value的内部表示
  • JavaScript对象的内存布局
  • 属性存储机制(Shapes和Slots)
  • 调试工具和方法
  • 漏洞利用的开发计划

这些基础知识为后续实际的漏洞利用开发奠定了基础。在第二部分中,将详细介绍具体的漏洞利用过程和技术。

SpiderMonkey 漏洞利用简介(一) 介绍 本文是SpiderMonkey JavaScript引擎漏洞利用系列的第一部分,主要介绍基础知识和背景。SpiderMonkey是Mozilla Firefox浏览器使用的JavaScript引擎,本文从一个从未编写过浏览器漏洞利用的开发者角度出发,介绍了如何开始研究JavaScript引擎漏洞利用。 环境设置 获取源码 Mozilla使用mercurial进行开发,但也维护只读的GIT镜像: 编译JavaScript Shell 首先应用必要的补丁文件 安装Mozilla-Build工具链 配置x64调试版本: SpiderMonkey基础知识 JS::Values和JSObjects JavaScript对象在内存中的表示: JS::Value 是JavaScript值的内部表示 高17位(JSVAL_ TAG)用于编码类型信息 低47位(JSVAL_ TAG_ SHIFT)是普通类型的值或指向JSObject的指针 JS::Value结构 类型标记 对象内存布局 JavaScript对象主要由两部分组成: 形状对象(Shape) - 描述属性 存储元素或属性值的存储槽(Slots) 对象层次结构 调试技巧 使用 Math.atan2 设置断点 使用 objectAddress 获取对象地址 使用 dumpObject 查看对象详细信息 Shapes(形状) Shape对象描述对象的属性: 每个属性对应一个Shape对象 通过父字段链接形成形状链 包含属性名和槽号信息 Shape结构 属性查找示例 获取对象地址 找到shapeOrExpando_ 字段指向的Shape 遍历Shape链获取所有属性信息 从immutableFlags中提取槽号 在对象存储中查找对应槽的值 Slots(存储槽) 属性值存储在对象的内存区域中: 紧接在对象头之后 每个槽存储一个JS::Value 数组有特殊的ObjectElements头存储长度信息 ObjectElements结构 数组内存布局示例 调试工具 sm.js扩展 作者开发了WinDbg JavaScript扩展 sm.js ,用于: 查看SpiderMonkey内部结构 检查对象内存布局 辅助漏洞利用开发 TTD (Time Travel Debugging) 使用TTD可以: 记录程序执行 前后浏览执行历史 更容易分析复杂对象状态变化 漏洞利用计划 作者计划分三步开发漏洞利用: basic.js - 针对特定版本js.exe的硬编码利用 kaizen.js - 动态解析偏移,使用JIT生成ROP gadgets ifrit.js - 针对Firefox浏览器,使用JIT编写完整payload 总结 本文介绍了SpiderMonkey引擎的基础知识,包括: JS::Value的内部表示 JavaScript对象的内存布局 属性存储机制(Shapes和Slots) 调试工具和方法 漏洞利用的开发计划 这些基础知识为后续实际的漏洞利用开发奠定了基础。在第二部分中,将详细介绍具体的漏洞利用过程和技术。