G.O.S.S.I.P 阅读推荐 2024-08-19 到底是谁的错?

今天我们要介绍的论文GlobalConfusion: TrustZone Trusted Application 0-Days by Design是知名安全研究团队HexHive发表于USENIX Security 2024的研究成果。在这篇论文中,作者对当前可信执行环境也就是TEE中的 可信应用(TA) 使用的接口规范——GlobalPlatform Internal Core API 进行了调研,发现它的设计往往会导致开发人员犯错,然后顺藤摸瓜找到了一系列的安全漏洞:

我们专栏频道似乎对关于TEE的安全研究论文情有独钟,过去的几年已经介绍了非常多的相关研究成果,因此TEE的一些预备知识想必大家都比较熟悉了,这里我们就不再过多去花费篇幅介绍。在本文中,涉及到TEE的相关知识点都在下图中展示出来了——本文主要关注的是normal world(也就是移动操作系统和移动APP端)和secure world(也就是TEE和TA)之间的代码调用、数据交换这个过程中涉及的接口的问题,同时也就确定了威胁模型——假定攻击者能够控制normal world,但只能通过向secure world发送受控的数据来实施攻击。

当前虽然有很多家不同的TEE OS开发商,但是大家基本上都遵循一套事实标准——GP TEE Internal Core API——来为运行在TEE OS上的TA提供资源(有点类似POSIX),大家可以访问下面的网址去了解这套标准的更多细节:

https://globalplatform.org/specs-library/tee-internal-core-api-specification/

在GP TEE Internal Core API标准中,有一些设计考虑是存在问题的,也被本文作者抓个正着(当然本文并不是第一个抓住这类问题的,但是作者算是第一个系统性地去大规模研究这类问题的)。作者把这类问题称为GlobalConfusion,那么到底什么是GlobalConfusion呢?请看下面这两个API接口:它们是normal world和TA建立会话的关键接口,第一个接口TA_OpenSessionEntryPoint负责建立TA与外部的会话,同时一般也负责验证外部调用者的身份合法性;第二个接口TA_InvokeCommandEntryPoint用来传递调用命令,注意到不同类型的命令都可以通过这个接口从外部传递给TA执行。

这两个接口有什么问题呢?首先它们的共同特定是都接收了paramTypesparamssessCtx这三个参数(TA_InvokeCommandEntryPoint额外需要一个cmdId参数)。在这些参数里面,sessCtx是TA自己来管理的(有时候甚至不需要真的去使用),外部没法控制它的数据,而剩下的paramTypesparams则是外部攻击者可以注入数据的点。实际上,GlobalConfusion的问题出在那个TEE_Param类型定义上:下图展示了TEE_Param的定义,不知道出于什么设计考虑,居然把它定义成了一个union(炫耀一下C语言学得好?现在是21世纪了不需要节约4个字节亲),正是因为这个union惹的祸,导致了后续的一系列攻击。

作者写了一个demo代码来展示GlobalConfusion问题,在下面这个例子中,TA并没有去检查paramTypes的类型是什么(图中13-22行被注释的代码表示的是本来应该严格执行的检查),而只根据cmdId参数就决定了要怎么去使用params数组的值。回到上面的TEE_Param类型定义,在GP TEE Internal Core API标准规定,如果它是所谓的memref类型,那么可以按照union定义里面的前面部分(也就是void *指针加上size长度)来对参数进行解析,可是如果它是value类型,那么就必须要把参数当成两个uint32_t来解析。这种type confusion问题,安全研究人员应该都非常熟悉,也很清楚怎么去利用它进行攻击。不过最重要的一点,是为什么这里会是一个design weakness?

论文作者在这部分讲得有点语焉不详,说什么The GlobalPlatform TEE Internal Core API specification proposes an optional preprocessor macro-based type check, resulting in a weak fail-open design,然后就没了,可什么是an optional preprocessor macro-based type check,作者完全没解释清楚,这种没头没脑的写作水平简直让人抓狂。实际上这个地方需要去看GP TEE Internal Core API标准文档才能搞清楚:在文档里面我们会看到TEE_PARAM_TYPES TEE_PARAM_TYPE_GET两个宏定义

同时文档里面也介绍了怎么使用这两个宏,看完了会忍不住惊叹这个文档的制定者是不是从1970年代穿越而来啊,还在用位操作的 奇技淫巧、鬼斧神工 高效手段,节约这一点点操作效率(这个文档还洋洋得意地宣称“to check the type of all the parameters in one comparison”)
是为了干嘛???这一下子就把代码的可读性搞得一塌糊涂。

虽然但是,上面的代码风格不好,不代表它是错的。在这里我们想要指出,在关于这个design weakness的论述上,完全配得上被拒稿:作者把GlobalConfusion问题的锅甩给了标准,非要说人家没有强制要求开发者去执行上面的检查,然后称之为design weakness,考虑到GP TEE Internal Core API标准文档里面已经明确写了需要进行type check,而且还给了例子,只是没有把刀架到开发者脖子上去,那把这说成是design weakness,彷佛就是说自行车只有轮子和刹车而没有头盔是一种设计缺陷,这种恐怕也是论文自己的confusion本事吧。

总之,论文的核心问题提出来,后续的所有技术内容就是去分析TA在实现上面提到的两类接口时,在没有执行type check就去直接使用参数的情况,如果找到这种情况应该就很容易追踪到可能存在的安全漏洞。在论文中作者设计了名为GPCheck的工具,然后总结一下就是比下表的工具都更适合这种特定的安全问题的检测。

不过GPCheck本身的设计也不难理解,先做一些静态代码分析(基于Ghidra),实现数据流追踪,然后就可以去大规模去扫描现实世界中的TA啦。

作者调查了许多Android固件镜像,收集了14777个不同的TA(都是没有源代码的),它们运行在五家主流的TEE OS,分别是QSEE(高通)、Kinibi(Trustonic)、TEEGris(三星)、OPTEE(Linaro)、BeanPod(小米)。在标准里面规定TA的身份需要由Universally Unique IDentifier(UUID)来标记,于是作者分析了这接近一万五千个TA,发现它们总共涉及到374个UUID,也就是说这14777个不同的TA可以分为374组,每个组里面是同一个TA的不同版本的实现。

GPCheck的大规模分析最终检测到了39个TA的具体实现有问题(如果考虑UUID的一致性,那就是33个TA),这里面有19个是以前就发现的问题,还有24个是新发现的问题。

作者还勾勒了这一类问题在计算机历史长河(好像也不算长)的时间轴上出现的顺序:

最后来看看哪家TEE里面的TA最容易出现问题(当然这个跟TEE OS还有厂商本身应该没啥关系,除非这个TA也是厂商开发的,不过似乎这种情况挺常见?):


论文:http://nebelwelt.net/files/24SEC4.pdf
Artifacts:https://github.com/HexHive/GlobalConfusion


免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。查看原文

为您推荐