“concolic execution”“Huffman tree”张口就来,周末随手用 Rust 写个 SMT 求解器——你身边大概也有这种人。他们似乎天生就能啃下复杂技术话题,而 JIT 漏洞利用,长期以来就像是专门留给他们的领地。
但一位作者最近决定打破这个印象。他自认不属于“聪明人”那一类,写不出 SMT 求解器,对 concolic execution 至今也说不清道不明。他把自己归为“靠蛮力硬扛弥补短板”的那一档。可就是这样一个人,最近开始研究浏览器里的 JavaScript JIT 编译器漏洞利用,并且发现:这事没想象中那么吓人。
![]()
为什么 JIT 漏洞总被当成高不可攀的领域
![]()
他坦言,自己拖了很久才动手,因为默认这个方向太难、不可能有进展。真正开始之后才发现,这是个有意思的话题,门槛并没有高到劝退的程度。他后悔没有更早投入去学。
这篇入门内容的目标很明确:讲清楚 JIT 编译器在 JavaScript 引擎里扮演什么角色,使用 JIT 编译器可能带来哪些类型的安全漏洞,以及分析这些 bug 时可以用什么工具。它不是一份 JIT 漏洞利用的全面指南,只是想让一个复杂话题变得更容易接近,让更多人敢往下深挖。
先搞懂 JIT 在引擎里干什么
在浏览器里,JavaScript 引擎负责执行你访问的网站中嵌入的 JS 代码。你打开一个网站,页面里带了 JS 代码,引擎就负责把它跑起来。JS 引擎通常用 C 或 C++ 编写。它之所以经常成为浏览器的被攻击目标,原因也很直接:引擎极其复杂,而且按设计就必须运行不受信任的代码。
JIT 编译器是 JS 引擎中负责做性能优化的组件。要理解它的作用,可以先看没有 JIT 时引擎怎么工作:JS 代码被解析、转成抽象语法树,最终转成字节码,由引擎的解释器执行。这个解释器可以称为基线解释器,在 V8 里它叫 Ignition。这个阶段的 JS 字节码可以视为未优化的。
基线解释器其实已经足以提供一个能跑 JS 的环境。JIT 编译器只是可选的优化组件,并非严格必需。一些不在浏览器里使用的 JS 引擎,甚至可能根本不带 JIT 编译器。现代浏览器也允许用户禁用相关功能。
![]()
上手之前,先备好这几样
这篇内容不要求你事先熟悉 JIT 编译器或 JavaScript 引擎。但如果你具备以下条件,会更容易跟上:
- 熟悉传统的内存破坏问题,比如越界读写和类型混淆;
- 对 JavaScript 至少有粗浅了解;
- 能熟练使用 GDB 这类调试器;
- 从源码构建 V8,以便跟着示例动手。
文中全程使用 D8,也就是 V8 的独立版本。V8 是 Chrome 使用的 JS 引擎。所讲内容很多并不局限于 V8,但涉及具体细节时会聚焦 V8。文中用到的示例漏洞,来自一个 V8 CTF 挑战。
公开资料比想象中多
好消息是,关于 JIT 漏洞和利用,公开研究已经相当多。作者列出的几份资料只是其中一部分,都不是阅读这篇内容的前置条件,但如果你对这个方向产生兴趣,值得去读:
- 一份 Black Hat USA 2018 的幻灯片,介绍 JavaScript 引擎和 JIT 编译器概念,并展示 JIT 漏洞示例;
- 一篇 V8 专题文章,走读 TurboFan——V8 中的 JIT 编译器,同时演示 Turbolizer 的用法,这个工具可以可视化 TurboFan 的行为;
- 一份讨论 JavaScript 引擎常见攻击、覆盖典型利用策略的演讲;
- 一篇 V8 利用系列文章,讨论 TurboFan,并给出自行分析它的技巧;
- 一份从 TurboFan 背景讲起、再深入具体 bug 与利用示例的演讲;
- 一个三篇系列的第一篇,介绍 TurboFan 及其优化阶段。
这些资料在文中会被多次引用。对想入门的人来说,它们构成了一条现成的路径:先建立概念,再跟着工具和示例一步步往下走。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.