triple_fetch - ianbeer [https://bugs.chromium.org/p/project-zero/issues/detail?id=1247]
这是针对 CVE-2017-7047 的利用程序,该漏洞是 libxpc 中的一个逻辑错误,允许恶意消息发送者发送由共享内存支持(backed)的 xpc_data 对象。xpc 消息的消费者似乎没有预料到,当接收者正在处理 xpc_data 对象时,其缓冲区的内容可能被发送者修改。
该项目利用 CVE-2017-7047 构建了一个概念验证的远程 lldb debugserver 存根(stub),能够附加到 iOS 上的所有用户空间进程并进行远程调试。
以下是该漏洞利用程序的高级概述,详细的深入分析文章可能稍后发布。现在请参阅代码以了解更多细节 :)
第一部分
该利用程序针对 NSXPC 进行攻击,NSXPC 是一个 Objective-C 远程过程调用实现,被许多 iOS 服务使用(1)。一个 NSXPC 消息由一个 bplist16 序列化对象构成,该对象位于一个 XPC 序列化的 xpc_data 对象内部,而这个 xpc_data 对象又位于一个 mach 消息中。
bplist16 对象除其他内容外,还包含一个 Objective-C 类型编码字符串(2),该字符串将由 CoreFoundation 中的函数 ___NSMS1 解析。此函数并未预料到要解析的字符串内容会发生变化,本利用程序利用这一点,通过利用字符串中某一部分将从内存中读取三次的事实,构建了一个堆溢出原语(heap overflow primitive)。通过在三个不同的、精心选择的值之间切换,我们能够用任意字节溢出已选择的堆分配大小。
minibplist16.c 包含了 bplist 序列化的最小实现以及其工作原理的讨论。
外层的 XPC 消息包含堆整理(heap groom)。它使用自定义的 XPC 序列化协议,通过构建具有冲突键的 XPC 字典来整理堆,从而构建分配和释放原语。外层 XPC 消息还包含一个堆喷射(heap spray,使用共享内存对象的多个副本以保持低内存使用量)以及一个 mach 端口发送权限名称喷射(mach port send right name spray)。
溢出操作将 Objective-C 对象的 isa 类指针指向一个堆喷射的假对象,这样当对该假对象调用方法时,栈会转移到一个小的 ROP 栈上。ROP 会暴力破解喷射的 mach 端口发送权限名称,尝试将目标的发送权限发送到其自身的任务端口,遍历每个候选的喷射发送权限名称。利用程序监听所有喷射的端口,如果攻击成功,它将收到目标任务端口的发送权限,此时它完全控制了目标任务。
插曲
该利用程序针对由 coreauthd 守护进程托管的 com.apple.CoreAuthentication.daemon 服务,该守护进程以 root 身份运行。此服务可以从应用沙盒访问。在我最初使利用程序工作后的一些实验表明,从 coreauthd 的上下文中,processor_set_tasks API 能够获取设备上所有用户空间进程的任务端口的发送权限。这自 2012 年以来已是公开知识,著名 iOS 内部研究员 Jonathan Levin 在他的网站上(3)详细介绍了相关历史。Levin 在 2015 年上传的代码至今仍然有效——它不需要越狱设备,只需要在标准设备上拥有 root 权限。
第二部分
我想通过此利用程序构建的调试器的主要目标是能够附加到任意进程、设置断点,并在命中时检查和修改寄存器和内存状态。我没有从头实现 gdb 或 lldb 远程协议,而是决定对 lldb 的 debugserver 项目进行必要的修改,然后使用利用程序运行它。
为了避免使用需要禁用或绕过代码签名的软件断点,我对 debugserver 进行了修补,使其仅使用硬件断点。ARM64 有 16 个硬件断点寄存器,这意味着你最多只能拥有 16 个活动断点。
ARM 硬件断点的原型支持确实存在于 lldb 的 debugserver 代码中,但需要一些修改才能工作。例如,我必须添加代码来修补被调试进程中的 pthread_introspection_hook 函数指针,使其始终崩溃,这样我就能检测到新线程的创建,并将硬件断点状态传播到新创建的线程中,然后继续执行,就好像从未崩溃过一样。
我还修补了附加和继续执行的代码,使其直接通过任务端口挂起和恢复任务,而不是使用 ptrace 和信号。
构建提示
一切应该适用于所有运行 iOS 10.0 到 10.3.2(含)的 iOS 设备。我在以下设备上测试过:
iPhone 7 + 10.3.2 iPod Touch + 10.1.1 iPad Mini 2 + 10.2
我包含了一个预构建的 debugserver 二进制文件,建议你使用它,但 lldb 的 debugserver 补丁也包含在 debugserver.diff 中。
构建 debugserver 并不太难。我基于以下 git 修订版本工作: lldb: 0db640c4cd1ec4e4c2580336fa5f53be029c5bc7 llvm: ec48fd127774a4b67c72ea7c3057b5c964375e77 clang: b6e778e0bfa2fc32f8821c6b33762f5cb6724659
应用提供的 debugserver.diff。
构建需要(最近的)cmake 和 ninja,你可以从源代码或二进制文件从你喜欢的 Mac 包管理器获取。
(4) 有一份关于如何在 MacOS 上设置正常 llvm 构建的指南,可能会有所帮助。
你需要将一堆头文件符号链接到你的 iOS SDK 中,至少包括:
xpc/ launchd.h libproc.h sys/proc_info.h sys/kern_control.h net/route.h mach/mach_vm.h mach/shared_region.h sys/ptrace.h crt_externs.h
以下 cmake 命令应该能给你所有需要的提示:
cmake -G "Ninja" -DCMAKE_OSX_ARCHITECTURES="armv7;armv7s;arm64" -DCMAKE_TOOLCHAIN_FILE=../cmake/platforms/iOS.cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_RUNTIME=Off -DLLVM_INCLUDE_TESTS=Off -DLLVM_INCLUDE_EXAMPLES=Off -DLLVM_ENABLE_BACKTRACES=Off ../
ninja debugserver
然后你需要签名或伪造签名 debugserver 二进制文件,并替换提供的 xcode 项目中的那个。
代码签名
利用程序项目默认会安装一个改进版的 mach_portal amfid hook(这次支持胖文件并且没有硬编码偏移 :) )
如果你只是想调试,你可以用自己的证书签名 debugserver 二进制文件,并禁用 amfid hook。
如果你确实使用 amfid hook,请记住它运行在的应用仍受后台代码执行限制的约束。该应用确实通过 beginBackgroundTaskWithName 请求了更多时间。
用法:
将你的主机和目标 iDevice 连接到同一个无线网络,记下 iDevice 的 IP 地址。
构建并运行利用程序应用。我建议在 xcode 内进行,但独立运行也可以。
稍等片刻。如果几分钟后没有成功,硬重启设备,再等一会儿,然后重试。
如果成功,它应该打印 "patched debugserver listening on port 1234"
如果你点击 "get process listing" 按钮,你应该会看到 ps 的输出
(如果你使用 xcode,更容易看到输出,但利用程序也会显示输出)
找到你感兴趣的目标进程,记下它的 pid。
在主机上从命令行启动 lldb: $ lldb (lldb)
将平台设置为远程 iOS: (lldb) platform select remote-ios
连接到 debugserver 存根: (lldb) process connect connect://192.168.0.172:1234
(其中 192.168.0.172 是 iDevice 的 IP 地址)
附加到你感兴趣的进程: (lldb) attach 55
...稍等片刻,debugserver 正在以详细模式运行...
Process 55 stopped
Executable module set to "/usr/libexec/backboardd".
你已经附加上了 :)
设置一个断点: (lldb) break set --name malloc Breakpoint 1: 4 locations.
继续:
(lldb) c Process 55 resuming Process 55 stopped
malloc libsystem_malloc.dylibmalloc:
-> 0x1936161e0 <+0>: stp x20, x19, [sp, #-0x20]!
0x1936161e4 <+4>: stp x29, x30, [sp, #0x10]
0x1936161e8 <+8>: add x29, sp, #0x10 ; =0x10获取回溯:
(lldb) bt
malloc frame #1: 0x0000000100099648 backboardd_mh_execute_header + 71240
frame #2: 0x00000001945bf218 CoreFoundation__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56 frame #3: 0x00000001945be9cc CoreFoundation__CFRunLoopDoSource1 + 436
frame #4: 0x00000001945bc4b0 CoreFoundation__CFRunLoopRun + 1840 frame #5: 0x00000001944ea2b8 CoreFoundationCFRunLoopRunSpecific + 444
frame #6: 0x0000000194537b44 CoreFoundationCFRunLoopRun + 112 frame #7: 0x00000001000a5ba8 backboardd_mh_execute_header + 121768
frame #8: 0x00000001000a5bec backboardd_mh_execute_header + 121836 frame #9: 0x00000001936a5850 libsystem_pthread.dylib_pthread_body + 240
frame #10: 0x00000001936a5760 libsystem_pthread.dylib_pthread_start + 284 frame #11: 0x00000001936a2d94 libsystem_pthread.dylibthread_start + 4故障排除:
安装最新版本的 XCode(在 8.3.3 上开发并测试) 如果 lldb 连接失败,请确保你已安装目标 iOS 版本的 SDK
注意事项:
我希望修复这些问题,但目前非常忙,抱歉!
运行其他 PoC:
如果你将二进制文件放在此项目的 pocs 文件夹中,你可以通过在设备上的 UI 中选择它并点击 "exec bundle binary" 来让利用程序执行它。
它仍然会在应用沙盒内运行,但如果应用有一个名为 privileged_task_port 的符号,它将被赋予 launchd 任务端口的发送权限。triple_fetch_sdk 文件夹包含一个示例项目,展示了如何使用它来构建 PoC,例如触发有趣进程中的行为,然后你可以使用 debugserver 调试它们。
它还包含了远程调用/端口/文件/内存 API,使你可以轻松地在其他进程中调用函数,并移动文件描述符、mach 端口和内存。
(1) [https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html] (2) [https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html] (3) [http://newosxbook.com/articles/PST2.html] (4) [https://gist.github.com/thlorenz/a068c202f2487ec13809]
本项目包含基于 lldb 的代码(debugserver.diff)和二进制文件(debugserver),后者受以下许可证约束:
University of Illinois/NCSA Open Source License
Copyright (c) 2010 Apple Inc. All rights reserved.
Developed by:
LLDB Team
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.
Neither the names of the LLDB Team, copyright holders, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.