聚焦源代码安全,网罗国内外最新资讯!

编译:奇安信代码卫士团队

本文叙述的是作者还在谷歌 Project Zero (GPZ) 团队工作时发生的事情。说明了做漏洞研究更令人沮丧的一面:当你看到打补丁版本时,才意识到自己错过了就在眼前的一个 bug!如下为正文:

可疑代码

写好 oob_timestamp exploit (https://bugs.chromium.org/p/project-zero/issues/detail?id=1986)后,我花时间试图找到另外一个可 exploit 的漏洞。一般而言,如果你已经有了研究平台(另一个 exploit)帮助你分析,那么再开发一个 exploit 就会容易得多。比如,转储内核内存,确保堆喷射将对象放在预期位置。盲目地开发一个 exploit,就像我开发 voucher_swap 那样会难得多。(oob_timestamp:我依靠 checkra1n 在A11 上引导该 exploit,之后将其扩展到 A13)。因此我以为将下一个 exploit 偏离 oob_timestamp 应该会避免后续必须重新引导的问题。

由于我已经花了很长的时间为 oob_timestamp 逆向 iOS 13.3 (17C54),因此我决定在新的用户客户端上继续投入。我写了一个小程序,枚举可从 app 沙箱触及的 IOUserClient 类(在这个过程中发现了另外一个 bug)并查找之前并未研究的类。

先来快速了解下 Apple 内核:Apple 的内核被称作 XNU,而 IOKit 是 XNU 执行驱动的C++框架。虽然用户空间中的 app 可调用 IOServiceGetMatchingServices() 将句柄放到驱动中,但是这款 app 实际上无法对原始的驱动句柄做太多的工作。相反,该 app 需要指令驱动,调用 IOServiceOpen() 创建一个“用户客户端”,传递它想要的用户客户端类型。由于该用户客户端向用户空间提供多数功能,因此它会受限于沙箱检查,确保该 app 能够开放用户客户端的请求类型。一旦该 app 拥有为驱动所用的用户客户端句柄,那么该 app 就能通过调用用户客户端句柄上的函数如 IOConnectCallMethod() 等,指定该 app 想要调用的方法的 “选择器(selector)” (索引)和用户客户端进行交互。在内核中,IOConnectCallMethod() 将使用该选择器来索引用户客户端提供的方法表,调用所需方法。

当扫描可以打开的客户端时,我发现了一个可触及的类:H11ANEInDirectPathClient,它是 H11ANEIn 驱动的用户客户端。之前未见过该类,但搜索后得知它并不开源,也就是说代码的安全审计可能很少,因此很可能会存在一些比该内核开源部分更容易发现的 bug。

在逆向的过程中,我发现了一些有意思的事。首先,H11ANEIn 似乎实际上拥有2个用户客户端:H11ANEInDirectPathClient (我已经打开的)和 H11ANEInUserClient (我无法在沙箱中打开的)。读取方法 H11ANEIn::newUserClient()中的字符串后发现 H11ANEInDirectPathClient 是 H11ANEInUserClient 的低权限版本,因此我能打开前一个但打不开后一个就合理了。

if ( type == 1 ) // H11ANEInDirectPathClient{_os_log_internal(...,"%s : ... : Creating direct evaluate client\n","virtual IOReturn H11ANEIn::newUserClient(...)");...}else // H11ANEInUserClient{_os_log_internal(...,"%s : ... : Creating default full-entitlement client\n","virtual IOReturn H11ANEIn::newUserClient(...)");...}

从 IOKit 用户客户端中查找漏洞的传统起始点是从所提供的外部方法中查找。它们通常是内核缓存镜像中函数指针靠近用户客户端 vtable 的可识别表。如下是我为两个用户客户端识别出的外部方法表,奇怪的是它们在内核缓存中背靠背而不是位于各自的 vtable 附近:

另外,在查看这两个表的交叉引用时我还发现一个情况:由于这些类基本相似,只不过其中一个是另外一个的低权限版本,苹果公司做出了异于寻常的决策:共享了与这两种用户客户端类型之间共享功能相对应的外部方法表的部分!

从每个用户客户端访问外部方法表之间重叠部分的 ::externalMethod() 方法中就可明显看出这一点。H11ANEInDirectPathClient 版本如下:

int H11ANEInDirectPathClient::externalMethod(H11ANEInDirectPathClient *this, u32 selector, IOExternalMethodArguments *args, IOExternalMethodDispatch *method, void *target){if ( !target )target = this;if ( selector <= 33 )method = &H11ANEInDirectPathClient_ExternalMethods_34[selector];return IOUserClient::externalMethod(this, selector, args, method, target);}

H11ANEInUserClient 版本如下:

int H11ANEInUserClient::externalMethod(H11ANEInUserClient *this, u32 selector, IOExternalMethodArguments *args, IOExternalMethodDispatch *method, void *target){if ( !target )target = this;if ( selector <= 33 )method = &H11ANEInUserClient_ExternalMethods_34[selector];return IOUserClient::externalMethod(this, selector, args, method, target);}

由于每个版本均可访问34种方法,而数组中的前3个方法为 H11ANEInDirectPathClient 保留,这就意味着最后3个将为 H11ANEInUserClient 保留,似乎共有37种方法。

于是,我开始深入挖掘可被 H11ANEInDirectPathClient 访问的方法,很快就认为该驱动钟的代码质量并不是很高。例如,我发现3500行的方法 H11ANEIn::ANE_ProgramSendRequest_gated()可通过选择器2和33触及,在该函数的顶部出现一些非常容易实现的界外读取漏洞。

由于args 的内容完全受控,因此  args->totInputBuffers 计数可能会随意变高,超过数组 inputBufferSymbolIndex 和 inputBufferSurfaceId的末端。

由于代码质量看似较低,而我并不太愿意遍历长度为数千行代码的函数,于是尝试一些非常容易的模糊测试。虽然模糊测试的经验有限,但我之前曾写过一个模糊测试工具,会从传递随机生成值得用户空间盲调 IOConnectCallMethod();令人惊讶的是,在找到真正得内核漏洞之前,这样做就足够了。于是,我决定使用这个模糊测试器并将其指向 H11ANEInDirectPathClient。

就在启动该模糊测试器 app 的一秒内,设备就有反应了。

我当然对这样的进展很兴奋,但实际上该 bug 是一个非常不起眼的空指针解引用;而且在 iOS 不可利用。进一步模糊测试后似乎也没有触发别的 bug,于是我向苹果公司发送了一个简略的非安全报告,称这部分代码可能会有问题,之后转身离开了 H11ANEInDirectPathClient。

再次邂逅符号

时间快进到8月底。

和之前的 iOS 12 测试版一样,某些 iOS 14 测试版中包含了一个符号化的内核缓存。我还没机会深挖这些问题,但我认为增加符号(尤其是可从错误的 C++ 方法名称中引用的有限的类型信息)将更快地逆转数千行 H11ANEIn 函数,因此更有价值。于是,我打开 IDA 并再次跳到外部方法表,查看是否有一些明显的变化。

我发现了外部方法表的一些情况:

很奇怪,H11ANEInDirectPathClient 和 H11ANEInUserClient的外部方法表都定义了符号。这就诡异了:我以为代码会由IOExternalMethodDispatch 结构的单一数组组成,因此 H11ANEInDirectPathClient 能够从0开始索引34种方法,而 H11ANEInUserClient 可以从3开始索引这34种方法。在这样的安排下,应该只有一个符号,而且是整个数组只有一个符号。

这时,我才发现:我关于外部方法数组重叠的认识纯粹是无稽之谈,而外部方法的“共享”是 H11ANEInDirectPathClient 造成的界外访问!较低权限的客户端应该只有3个方法,但不巧的是边界检查时存在一个错字,使得 H11ANEInDirectPathClient 能够访问并从更高权限的客户端调用外部方法。如此,H11ANEInDirectPathClient 向 H11ANEInUserClient 做出的每个调用都是间接地在 this 指针上触发了类型混淆!

事后诸葛亮,我意识到“共享外部方法数组”的安排并不合理:这样的安排不惜慎之又慎,避免多个用户客户端的两个类之间出现类型混淆问题,而且并不存在这种预防措施。当我反编译新的内核缓存中的 H11ANEInDirectPathClient::externalMethod() 时,证实了这一点,并且发现选择器上的边界检查从33减少到2,也就是说该 bug 已修复。

所以,我竟然错过了一直在眼前飘着的问题,我通过创造一种重叠方法表的概念证明了它存在的合理性。当然,雪上加霜的是,我之前报告的空指针解引用非安全问题只有在调用其中的两个界外方法才能实现。

另外一个复制粘贴问题

为什么会出现这个 bug?由于有 bug 的版本中包含了对 ::externalMethod() 实现的边界检查,因此我认为它是另外一个复制粘贴问题。我猜测,在苹果的源代码中, H11ANEInUserClient::externalMethod() 实际是这样的:

IOReturn H11ANEInUserClient::externalMethod(u32 selector, IOExternalMethodArguments *args,IOExternalMethodDispatch *method, void *target){if ( !target )target = this;if ( selector < H11ANEInUserClient::sMethodCount )method = &H11ANEInUserClient::sMethods[selector];return super::externalMethod(this, selector, args, method, target);}

我猜测该代码被复制粘贴,用于创建 H11ANEInDirectPathClient 版本,但作者不小心忘记在选择器检查中更改类型名称:

IOReturn H11ANEInDirectPathClient::externalMethod(u32 selector, IOExternalMethodArguments *args,IOExternalMethodDispatch *method, void *target){if ( !target )target = this;if ( selector < H11ANEInUserClient::sMethodCount )method = &H11ANEInDirectPathClient::sMethods[selector];return super::externalMethod(this, selector, args, method, target);}

除此之外,编译器背靠背放置外部方法表通常是很容易犯的错误,使该 bug 有可能被利用(与我所知道的以往的界外外部方法相反)。话虽如此,但我尚未检查该问题实际的可利用性。

结论

那么,我们能从这件事中学到什么?

首先,真的很容易错过 bug,即使是你认为应该是很明显就能看出来的 bug。我真想为自己错过这个 bug踢自己一脚,关键自己还像戏精一样证明这种代码模式为何会出现的合理性。如果说我必须一而再再而三地吸取某个教训,那么一定是对代码的固有怀疑,永远不要认为它现在做的事情是故意这样做的。

其次,虽然复制粘贴真的能够快速创建代码,但它也能快速制造 bug,而扫一眼源代码难以发现它的本质。通过查看反汇编程序可以很容易地看出2个数组是“重叠的”,但很难发现复制粘贴的代码中使用了两个非常类似的类名称中其中一个错误的名称。虽然这并不能百分百地解决问题,但它有助于将复制粘贴的代码分解为可复用的辅助函数。

最后,即使是我在查看符号化的内核缓存时发现了该 bug,但我并不想让苹果公司认为发布符号会带来安全风险。当苹果公司不慎发布符号化的内核缓存或开发二进制时,安全研究员喜上眉梢,但这只是因为这样做会节约逆向的时间,而不是因为它可使事情逆转。不管是否存在符号,任何有能力的攻击者最终会找到 bug;缺乏 bug 符号所起的作用只是让别人(比如我)看不到而最终没有报告该 bug。因此,保留符号是一种极其薄弱的保护措施,它只会阻止低阶攻击者且使已被发现的 bug 存在更久的时间。

你是否也有这种捶胸顿足的情况?来呀,在留言区互相伤害呀(ㄒoㄒ)~

推荐阅读

苹果修复三个已遭利用的 iOS 0day

从 CVE-2020-1048 到 CVE-2020-17001:Windows打印机模块中多个提权漏洞分析

原文链接

https://googleprojectzero.blogspot.com/2020/11/oops-i-missed-it-again.html

题图:Pixabay License

本文由奇安信代码卫士编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。

奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的

产品线。

 觉得不错,就点个 “在看” 或 "赞” 吧~

亲历漏洞研究最让人难受的地方:看到打补丁版本,才知漏洞一直近在眼前(详述)...相关推荐

  1. 袁哥写的漏洞研究方法总结

    一.前期准备,建立安全模型: 1.熟悉软件功能.功能实现,配置等: 如:IIS的虚拟目录.脚本映射: 2.根据功能,分析安全需求,建立安全模型: IIS外挂,文件类型识别,目录正确识别:目录限制: 外 ...

  2. 美国物理超级计算机,美国科学家在物理学的一个分支领域朝着开发超级计算机迈进了一步。这一分支领域研究的是人眼看不见的粒子。...

    美国科学家在物理学的一个分支领域朝着开发超级计算机迈进了一步.这一分支领域研究的是人眼看不见的粒子. 这些科学家在<自然>杂志上发表文章称,"用量子信息学的语言来说,我们已经制造 ...

  3. 最先进的NAS算法不如随机搜索,瑞士学者研究结果让人吃惊,也令人怀疑

    晓查 发自 凹非寺 量子位 出品 | 公众号 QbitAI 最先进的神经架构搜索(NAS)算法竟然不如随机搜索? 来自瑞士电信和EPFL的研究者提出了一种评价NAS搜索阶段的测试基准.他们发现,最先进 ...

  4. 亲历!给大龄IT人的几点求职建议

    亲历!给大龄IT人的几点求职建议 作者/来源:公众号丨漂洋过海的渔夫 大家好,我是那个43岁下岗,面试了15家公司,重新就业的大龄IT男. 今天继续分享我的求职故事和感悟-- 人到中年,有时很难做到从 ...

  5. Java反序列化漏洞研究

    Java反序列化漏洞研究 漏洞原理 java序列化就是把对象转换成字节流,便于保存在内存.文件.数据库中:反序列化即逆过程,由字节流还原成对象.当反序列化的输入来源于程序外部,可以被用户控制,恶意用户 ...

  6. Winamp栈溢出漏洞研究【转载】

    课程简介 Winamp是一款非常经典的音乐播放软件,它于上世纪九十年代后期问世.与现在音乐播放软件行业百家争鸣的情况不同,当时可以说Winamp就是听音乐的唯一选择了,相信那个时代的电脑玩家是深有体会 ...

  7. 墨云科技 web漏洞研究岗一面复盘

    墨云科技 web漏洞研究岗一面复盘 1.xss的分类说一下 2.xss怎么防御的 3.详细讲讲什么是DOM,越详细越好 4.反射型XSS和DOM型XSS的区别 5.富文本XSS了解过吗,说一下 6.你 ...

  8. 针对CVE-2015-2545漏洞研究分析

    本文讲的是 针对CVE-2015-2545漏洞研究分析, 1. 概述 这是一种MSOffice漏洞,允许通过使用特殊的 Encapsulated PostScript (EPS)图形文件任意执行代码. ...

  9. OWASP 十大漏洞研究

    首先要说一下,本文很多摘抄自此博客,这位同学珠玉在前不敢擅用,大家有兴趣可以直接看此博客. (19条消息) OWASP top 10漏洞原理及防御(2017版官方)_wwl012345的博客-CSDN ...

最新文章

  1. MMX Intrinsics各函数介绍
  2. 通过mrtrix3进行概率纤维追踪+核磁共振影像数据处理
  3. 基于ACE Proactor框架下高并发、大容量吞吐程序设计既最近的一个产品开发总结
  4. 中年人在“洗脑课”上迷了路
  5. Android照片墙完整版,完美结合 内存方案 LruCache 和 硬盘方案 DiskLruCache
  6. Spark Structure Streaming(一)之简介
  7. 实验2.5 用递归的方法编写函数求Fibonacci 级数,观察递归调用的过程
  8. 年仅 5 岁的 Rust 如何成为最受欢迎的编程语言?
  9. 解决默写浏览器中点击input输入框时,placeholder的值不消失的方法
  10. Oracle集群(RAC)及 jdbc 连接双机数据库
  11. 向集合中添加Person类型并对其排序
  12. C 字符串转换为c语言字符串,OC字符串与C语言字符串之间的相互转换
  13. 修复下载后已发生损坏的压缩包(.rar)文件
  14. windows7创建wlan热点分享网络
  15. 视频加水印,怎么给视频加水印?
  16. 测试工具:adb+perfdog+charles+tidevice+Monkey
  17. 全国计算机一级选择题免费,全国计算机一级考试选择题试题与详细答案
  18. ORACLE OGG同步时更新分区字段值的问题
  19. linux创建用户,添加及修改shell
  20. 元素偏移量 offset 系列

热门文章

  1. word2003怎么做目录与正文的连接
  2. 拿什么奉献给你,我的敏感信息(转)
  3. sprintboot入门
  4. 2019.3.9笔试
  5. AI考拉技术分享会--IDE 常用功能 for Node.js
  6. 工业互联网方案商“全应科技”获明势领投Pre-A轮融资
  7. 微信公共开发人员文档 阅读笔记
  8. lucene 分词相关的类
  9. 查询存储过程,数据库对象的创建历史
  10. j2ee高并发时使用全局变量需要注意的问题