在当今的信息交流中,消息传递并不完全是基于文本的,还包括用户交换的图片、短视频、语音以及他们当前的位置。这类型的数据是会话历史的重要组成部分,它们可以像聊天的文本内容一样成为有价值的证据。

苹果生态系统提供了一个内置的消息传递工具——imessage,允许用户在苹果设备之间交换消息。这个内置的imessage在苹果用户中非常流行,早在2016年,苹果公司的高级副总裁就宣布imessage每秒钟发送的消息就达20多万条。

所有当前版本的iOS都为文本数据和非文本数据提供了实时的iCloud同步,从iOS 11.4开始,苹果的所有设备都可以通过iCloud同步消息。目前,imessage和短信都可以存储在用户的iCloud账户中,并在共享相同Apple ID的所有用户设备上同步。另外,通话记录、iCloud照片库或iCloud联系人也可以同步,不过就是同步时间(相较于imessage信息)要靠后一些。然而,在满足LE请求或GDPR请求时,苹果既不会提供消息源,也不提供它们的附件。为什么会发生这种情况,如何从iCloud账户提取消息,我们又可以在消息附件中找到什么样的证据?这就是我们这篇文章要讲的。

欧盟GDPR颁布的一个主要目的即在于对数据的充分保护,主要涉及数据处理程序的前、中、后三个阶段。同时,由于数据类型的纷繁复杂使得数据保护难度颇大,特别是其中相对属于特殊类型的个人数据,欧盟GDPR更是以专门条款对其相关内容进行了明确规定。

iCloud内容的提取

由于imessage采用的是端到端的加密过程,因此消息在传输过程中会受到安全保护。那些同步到iCloud的内容的安全性呢?苹果表示,存储在用户iCloud账户中的数据是安全加密的。另外,苹果还存储加密密钥,这使得该公司有可能向执法机构提供他们所需的数据和GDPR所要求的数据。根据欧盟GDPR规定,在满足特定条件时,个人数据仍能够进行相关操作。首先,数据主体明确同意的情形下,数据控制者可以对特殊类型的个人数据进行相关必要的处理。其次,若基于侦查犯罪的需要,在必须使用的情形下,为了公共利益及国家利益的维护,该特殊类型的个人数据同样需要在未经数据主体同意的情形下被使用。因此,对于特殊类型的个人数据,欧盟GDPR既有原则性的规定以保证数据主体的权益受到最大程度的保护,同时又给予了各成员国一定的自由裁量范围以更加灵活的兼顾数据保护及数据处理二者之间的关系。

不过根据目前的实际情况, iCloud的消息和任何附件内容都是不适用于GDPR规定的,且任何人都无法从技术层面上盗取这些信息,因为苹果使用了额外的AES256加密来保护同步信息。另外,加密密钥会使用用户的设备密码(iOS设备)或系统密码(macOS设备)重新加密,即使用户在多个关联的设备上注册了不同的密码,则还是可以使用同一个加密密钥解密不同的设备。此外,消息将只同步具有双因素身份验证的帐户。

iMessage消息附件的

iMessage实际上是许多iPhone用户选择的即时通讯工具。《商业内参》(Business Insider) 称:

在美国年轻人中,苹果iMessage的使用量已经超过了Facebook Messenger和Snapchat。目前,美国青少年使用iMessage的次数比其他任何社交平台都要多。

另外Hacker Noon网站的Guiseppe Stutto说:

iMessage是一个面向青少年的社交平台,现在已经成了社交的中心。虽然他们仍然会花很多时间在Instagram、Snapchat、Tumblr或其他应用上,但目前iMessage所占的份额却是越来越大,不管是单聊还是群聊。

作为狂热的iPhone用户,研究人员对iMessage的安全性进行了各种测试。在对一个测试的iCloud账户进行取证分析时,研究人员调取了17万条信息,其中包含超过7千兆字节的消息附件,这些信息都是很有价值的。虽然iMessage本身不包含位置信息(除非用户共享他们的位置),但附件通常是在iMessage发送之前用iPhone相机拍下的照片,由于每张照片都带有EXIF标签,因此要分析出用户的位置信息也不是很难。

同步消息和云备份的提取

早在2011年,iCloud备份就是Apple新推出的首批云平台服务中的一个。从那时起,许多事情发生了变化,云备份最多每天创建一次,由于Apple的免费iCloud空间只有5 GB,对于许多用户而言,因此可能根本不会创建它们。 Apple生态系统的增长意味着用户拥有多台Apple设备的概率很高,因此,Apple继续将iCloud备份转移到共享的可同步数据中。例如,一旦用户启用iCloud照片库,他们所有的照片就会自动上传到iCloud中,并与使用同一Apple ID注册的所有设备同步。

根据Apple的说法:

当你启动iCloud照片库时,你的照片和视频会自动上传到iCloud,且iCloud备份不会重复。

消息同步也是如此,根据https://support.apple.com/en-us/HT208532https://support.apple.com/en-ca/HT207428,一旦用户在iCloud中启用消息同步,无论是文本消息还是消息附件都不会存储在他们的iCloud备份中。当你在iCloud […]中使用消息同步时,你的内容将自动存储在iCloud中,这意味着它们就不会包含在你的iCloud备份中。

为什么LE和GDPR请求不适用于iCloud内容的取证

通过LE或GDPR请求获得的信息中,并不包括iCloud内容。具体的原因如下:据苹果公司称,由于加密的原因,他们自己也无法访问用户的信息。苹果表示:

由于用户的信息会在他们的设备上加密,如果没有设备密码,任何人都无法访问用户信息。

如前所述,一旦用户在iCloud中启用消息,消息和附件都不会存储在iCloud备份中。因此,只能使用第三方取证软件从云中提取消息,但提取和解密消息得需要用户的Apple ID登录名、密码、双因素验证码和设备密码(屏幕锁定密码)。

从苹果iCloud下载消息和其他内容

为了从iCloud中提取消息和附件内容,取证人员需要使用Elcomsoft Phone Breaker 8.40或更新的版本。如果你使用的是Windows电脑,你必须安装iCloud。Mac用户必须拥有macOS 10.11或更新的版本。访问消息的步骤如下所示:

设备配置

1.Elcomsoft Phone Breaker

2.适用于Windows的iCloud

3.苹果的登录ID和密码;

4.第二身份验证因素(the second authentication factor)(使用同一苹果账户注册的SIM卡、iPhone或iPad设备),注意:由于GS身份验证,用户只需要提供一次第二身份验证因素即可。然后,计算机就会信任你,在随后的证据提取中,将不会询问第二身份验证因素。

5.需要至少一个注册到与iMessage 同步的设备的密码(iPhone/iPad)或系统密码(Mac);

从iCloud提取消息的步骤

1.启动Elcomsoft Phone Breaker,选择Apple >从iCloud下载 >同步数据;

2.指定用户的Apple ID和密码;

3.提供一次性代码以通过双因素身份验证;

4.选择要从iCloud获取的数据,确保选中了“Messages”选项;

1.jpg

5.Elcomsoft Phone Breaker将登录用户的苹果账户,选择你知道密码或系统密码的受信任设备,并输入登录密码。

2.jpg

6.消息会被下载,下载消息之后,单击“完成”。或者,你也可以设置“在EPV中打开”时钟,以便在Elcomsoft Phone Viewer中自动打开下载的数据。另一种选择是使用“浏览文件”链接,来验证已下载的文件。

3.jpg

7.你现在可以使用Elcomsoft Phone Viewer来分析下载的消息。

4.jpg

8.单击“Messages” 选项打开消息和附件列表。

5.jpg

此时,要提取的媒体文件就会以缩略图的形式呈现出来,你可以预览它们。单击预览旁边的放大就可以访问原始文件,或单击“保存”以保存为文件。你可以应用许多消息选择项,来显示在一定时间范围内发送或接收的消息,或者仅显示具有特定类型附件的消息(例如,仅显示带有照片的消息)。

iMessage是苹果公司推出的即时通信软件,可以发送短信、视频等,其拥有非常高的安全性。不同于运营商短信/彩信业务,用户仅需要通过WiFi或者蜂窝数据网络进行数据支持,就可以完成通信。

毫无疑问,iMessage是最受欢迎的即时通讯平台之一,原因很明显,它内置在iOS系统中,默认情况下,每台iPhone都配有iMessage。由于iMessage不需要复杂的设置,因此iMessage用户的数量与iPhone用户的数量非常接近。苹果每年销售约2亿部iPhone,目前销售的iPhone总数超过10亿部。

但是iMessage真的安全吗? 

让我们从Apple的隐私设置方法来讨论这个问题,苹果的开发人员使用端到端加密来保护用户的所有设备上的iMessage和FaceTime对话。通过watchOS和iOS,用户的消息在用户的设备上被加密,因此没有密码就无法访问。苹果的研究人员设计了iMessage和FaceTime,所以当用户的数据在设备之间传输时,其他人员是无法解密用户的数据。另外,用户可以选择在30天或一年之后自动从用户的设备上删除苹果的研究人员的消息,或者将它们永久保存在用户的设备上。

再谈谈iCloud的安全,iCloud在传输过程中对用户的消息进行加密,以加密的格式存储在iCloud中,并使用安全令牌进行身份验证,从而保护用户的消息。对于某些敏感消息,苹果使用端到端加密。这意味着只有用户才能访问用户的消息,而且只能在用户登录iCloud的设备上访问。没有任何人,可以访问端到端的加密消息。

端到端加密提供了最高水平的数据安全。用户的数据由一个密钥保护,该密钥来自用户的设备特有的消息,并与只有用户知道的设备密码相结合。其他人不能访问或读取这些数据。

iCloud中的消息也使用端到端加密。如果用户打开了iCloud备份,用户的备份包括保护用户消息的密钥副本,这可确保用户在无法访问iCloud钥匙串和可信设备时恢复消息。当用户关闭iCloud备份时,系统会在用户的设备上生成一个新密钥,以保护以后生成的消息,且Apple不会存储该密钥。

如果用户不太相信,可以看看iOS安全指南,安全指南是这样说的:当用户在设备上打开iMessage时,设备会生成两对密钥供该服务使用,这两对密钥分别是用于加密的RSA 1280位密钥和用于签名的NIST P-256曲线上的ECDSA 256位密钥。这两个密钥对的私钥都保存在设备的钥匙串中,而公钥则被发送到Apple身份服务(Apple identity service,IDS),它们会在IDS中,与用户的电话号码或电子邮件地址以及设备的APN地址相关联。

iCloud中的消息还使用CloudKit端到端加密,并使用由iCloud钥匙串同步保护的CloudKit服务密钥。如果用户启用了iCloud备份,则用于iCloud容器中消息的CloudKit服务密钥将被备份到iCloud中,从而允许用户恢复其消息,即使苹果的研究人员已经失去了对iCloud钥匙串和其受信任设备的访问,当用户关闭iCloud备份时,还是会生成此iCloud的服务密钥。

iMessage的安全与隐私

在我们讨论iCloud安全之前,让我们先检查一下没有与iCloud同步的消息。根据我现在所掌握的知识,iMessage协议中没有已知的漏洞可以解密拦截的消息,并且在iPhone和Apple服务器之间嗅探流量并不容易。访问消息的唯一方法是通过iTunes创建本地备份,从设备本身获取消息。问题是,用户必须持有设备,而且用户必须知道它的密码(以便与计算机配对)。如果备份是受密码保护的,那么这就是一个问题,如果手机运行的是iOS 11或12,你可以简单地重置那个密码,那么这就不是一个问题了。

以下是几篇关于iMessage安全的文章:

1.用户的苹果imessage真的安全吗? 

2. 苹果的iMessage是否符合HIPAA标准? 

那么iCloud备份呢?如果备份存在,则消息就会出现。不过需要用户的Apple ID、密码和一次性代码来通过双因素身份验证(或者用户可以使用身份验证令牌)。虽然iCloud备份是加密的,但加密密钥与数据是一起存储的(从技术上讲,存储在不同的服务器上,但任何拥有适当凭证的人都可以访问)。如果用户成功地访问了iCloud备份,那解密消息就不是那么困难了。

正如用户所看到的,没有与iCloud同步的iMessage的安全性,则有些不足。

然而,如果用户启用iCloud消息,则下一个(以及所有后续)iCloud备份将永远不会包含任何消息。而使用额外的AES 256加密,在安全性上,则是一个很大的改进:

1.苹果的iMessage变得比以前更安全了

2.苹果正试图让用户的imessage更加安全

3.iMessage在云端有多安全? 

消息同步

让我们接着谈iCloud备份,如果用户使用云备份,那么此时他们的设备被打开,锁定并连接到电源,则会每天会创建备份。请注意,它只适用于Wi-Fi。只需进入 Settings | [your name] | iCloud | iCloud Backup来打开或关闭该功能,用户还可以手动备份(手动备份不需要连接电源)完成此步骤。

但是数据同步呢?出于各种原因,许多用户不会启用iCloud备份。其中一个原因是空间的大小,一般用户只会获得5 GB的空间,这对于消息备份来说显然是不够的。但是,同步是默认启用的,而且非常非常方便。

大多数数据几乎是实时同步的,其中就包括联系人、通话记录、笔记、Safari浏览历史等,但不包括iMessage的消息。之所以这么肯定,是因为研究人员在各种各样的设备(从iPhone 5S到iPhone Xs Max,还有iPad和一些不同的mac电脑)上进行了调取测试。研究人员所测试的设备分别运行了不同版本的iOS,从iOS 11.4(第一个支持iCloud中消息的iOS版本)到iOS 12.1.1(撰写本文时还只是测试版),通过Wi-Fi和LTE连接,只有苹果公司知道消息何时以及如何与云同步。因为有时即时消息(iMessage和SMS)会被上传到iCloud,然后同步到连接到账户的其他设备上,此过程通常需要5到10分钟,但有时甚至需要几个小时来同步。而在研究人员的一个测试帐户中,同步消息的时间竟然达到了4天。尽管实现这个功能的版本整整测试了一年,但看起来这个实现仍然存在缺陷。

消息附件的安全性分析

消息附件指的是照片、视频、语音消息、笔记、联系人、位置信息等任何非文本内容,如果用户的消息与iCloud同步,那么所有消息附件也会同步。此时,用户发送或接收到的所有东西也会被上传到iCloud上,除非用户禁用消息同步或者完全禁用iCloud,不过我建议最好不要这样做。

如上所述,如果消息同步处于打开状态,则文本消息不包括在iCloud备份中。那消息附件呢?它们也不包括在iCloud备份中,消息附件仅在设备本身和云中的某个安全容器中可用(仅用于同步)。

关于消息附件,还有一件至关重要的事情,用户需要知道。在iOS中,当用户发送一个重定向到某个网页或特定文件的链接时,iMessage会生成一个缩略图预览。对于大多数文档来说,它只是一个应用程序图标;对于图像,它是一个缩略图;对于视频,通常会显示第一帧;对于网站来说,它是一个预览,或者是HTML标签中的一个图像,甚至是视频(这同样取决于HTML标签)。此外,预览作为附件保存在设备本身和云上(如果启用了云同步)。顺便说一下,如果用户在Dropbox上发送或接收到一个图片链接,那么图片本身就会被保存。如果用户使用苹果地图共享一个位置,那么地图的实际部分就会作为图像,也被保存下来,而对于所有链接,favicon也会被保存(如果存在的话),Favicon是favorites icon的缩写,亦被称为website icon(网页图标)、page icon(页面图标)或urlicon(URL图标),Favicon是与某个网站或网页相关联的图标。

1.1.png

1.2.png

其他内容(如支持imessage的应用程序)也值得被保存,例如,即使在调查时链接本身不再可用,自动生成的附件也可能包含有价值的内容。

已经删除的数据的安全性

删除邮件时会发生什么(如果该邮件已经与iCloud同步)?在研究人员过去的进行的一项测试中,他们发现苹果并不会删除已经与iCloud同步的照片网页浏览记录笔记的。

所以下面,我会向大家介绍如何从iCloud中正确删除消息(连同附件消息)。目前,虽然苹果已经吸取了研究人员的改进建议,但目前删除消息后仍有一些蛛丝马迹留下,且仍然可以在云中停留一段时间,甚至几天。研究人员分析,很可能是一些连接到该账户的设备可能在用户按下“删除”键时处于离线状态。另外,删除的数据仍然可以从本地设备备份中恢复,因为所有数据都存储在SQLite数据库中,但绝对不能从iCloud中恢复,至少研究人员做不到这些。

这到底是怎么回事?让我们再次回到iMessage隐私和安全的话题,虽然iCloud中的消息是加密的,但并不能完全做到端到端的加密。从技术上讲,它们是使用存储在iCloud钥匙串中的密钥加密的。如果用户能先提取iCloud钥匙串的话,那他们就可以访问包括图片、视频、位置、联系人、笔记等非文本内容的消息。但要访问iCloud 钥匙串并不容易,用户不仅需要用户的凭证,还需要一个受信任设备的密码。

除了以上这些,用户还需要什么才能获取消息(以及消息附件,即非文本内容)?需要Elcomsoft Phone Breaker  (从iCloud下载所有内容)和Elcomsoft Phone Viewer  (浏览数据),还需要知道如何读取iCloud中的消息,比如如何提取完整的内容,包括媒体文件,位置和文件的更多细节。

2.png

总结

通过以上分析,可以知道iMessage并不是百分百安全,无懈可击的。不过与其他即使软件相比,iMessage的消息和附件都具有更好的保护和加密级别。比如,要解密它们,首先需要获取钥匙串,光这个过程,就很复杂。

那有没有一种可能,就是苹果公司自己可以读取用户的消息?通过研究,这个可能是不存在的,苹果的研究人员是真的无法访问用户的iCloud钥匙串和用户的消息,这就是苹果的研究人员为什么不将它们包含在Apple ID数据和隐私中的“获取你的数据副本”所提供的大量数据中的原因(谢谢到GDPR)。那执法部门呢,他们会截获用户的消息吗?答案是,只有当他们使用专门的工具破获用户的登录凭据和密码时才可以进行取证,或者是雇佣专门的取证人员来进行取证,目前,取证人员可以使用Apple ID、登录密码、第二身份(second authentication)验证因子和密码,将取证设备连接到要调查的账户上,然后启用iCloud 钥匙串,等待设备完全同步,设置iTunes备份密码,创建本地备份,最后用取证软件打开备份进行分析。

对于网络安全人员来说,主动防御才是最理想的效果。这意味着,他们处于主动的一方,能够提前做出判断,最大限度的保护设备。无论你的网络安全团队的口号是什么,打击网络犯罪的关键点就是要对威胁做出提前预测,这也是威胁情报的重要意义所在。

在有人恶意利用企业IT基础设施之前,识别并修补企业IT基础设施的漏洞,能够避免很多的损失。随着网络攻击的力度和影响的增大,目前许多企业都以购买了专门的威胁情报服务,据统计,2018年全球范围内的威胁情的收已经超过14亿美元,而2014年,这一收入仅有9.055亿美元,这证明许多组织都在购买它。

问题是,购买了这项服务后,组织和网络安全人员往往不能很好的利用这些情报,比如对威胁情报的理解不到位或者难以将问题落实到位。本文,我就总结了威胁情报不起作用的5个原因,并提出了相应地解决对策。

与特定网络安全需求不匹配

网络安全团队有时会误以为购买的威胁情报服务就等同于杀毒软件之类的保护服务,将它视为保护他们免受黑客攻击的保护捷径。这种对情报服务的预期效果很不现实,事实是,没有所谓的通用的威胁情报,具体的防护措施还得需要安防人员结合组织的实际情况。这意味着,威胁情报解决方案必须根据每个组织、分支组织甚至部门的特定安全需求来实施。例如,一家金融服务公司可能希望密切关注网站伪造和恶意联系表格,这些表格旨在欺骗用户,让他们泄漏自己的信用卡和银行账号。

不过话得分两头讲,威胁服务供应商的一个紧迫问题是,要确保专有信息(如商业机密和研发进展)不会落入攻击者之手,无论是由于电子邮件诈骗、加密不良还是恶意软件,供应商都应改进自己的应对服务。

无法将威胁情报提供的信息落实

假如组织能获得最准确的威胁情报服务,那组织如何打算把这些信息落实,来应对即将到来的威胁?这就是企业自己的实力和资源配置的问题了。根据调查,44%的日常安全警报从未被安防人员实际调查过,并且由于各种原因,威胁情报数据也可能最终未被落实过。

每个组织所拥有的安防资源都不同,比如有些小组织中可能都没有知道如何解释他们所看到的威胁情报,更不用说付诸行动了,或者,安防事业缺乏领导层的支持,或者缺乏相应的预算来提高防御能力。

无论哪种方式,在不了解安全漏洞或有解决问题的方法的情况下,知道出现问题并不能减少网络攻击的普遍程度或强度。

为了解决这个问题,最好是在组织购买威胁情报服务之前,就做好全面的安全规划,包括准备好分配哪些资源?如何培训相关员工?处理漏洞的具体步骤有哪些?尽量让情报落实。

协调威胁服务和其他网络安全措施之间的关系

威胁情报和其他网络安全措施之间有着各种联系,大家负责的环节和所包含的功能也各有不同。威胁情报的作用就是提前对可能的威胁做出预判、提供保护方向、让安防人员加强安全意识做出相应的行动,比如发现服务器的错误配置,密切关注新形式的恶意软件等。

按照这种思路,我们很容易认为任何负责威胁情报的人员都会像事件响应专家一样来处理威胁情报。然而,他们在方向和方法上存在着明显的差异。

最重要的是,威胁情报是安全分析师的工作,他的专业知识是负责对事件做出解释,帮助安全人员理解真相,并为即将到来的威胁制定预防和拦截计划。这与事件响应专家的角色不同,事件响应专家是受过培训的,可以在发生时对威胁做出反应并对其进行响应。

承认这种差异是至关重要的,这意味着安全责任可能需要在网络安全团队中重新分配。 

未能整合威胁情报

如何确保网络安全人员能最高效的使用威胁情报,最快的途径通常是将最新的情报与用户已经知道的信息串联起来。

事实上,将威胁情报及其数据源连接到常用软件(例如安全信息和事件管理应用程序)至关重要。作为综合网络安全计划的一部分,这样做将加快情报的落实速度。

如果缺乏整合,不仅降低了威胁情报的有效性,还增加了网络安全团队的工作量,这些团队需要手工汇总和比较来自另一个来源的数据,以评估基础设施的安全状况。

不了解威胁情报的术语

由于不同的组织有不同的安全需求,威胁情报会有专门的组织语言的方式,在其他组织里的同一术语可能在你这里就有不同的含义。如果没有考虑到这一点,安全人员就会误解所传递的信息。

当高级管理人员谈论威胁情报时,重点很可能是高层决策,比如,本财政年度的安全预算应该花在哪里?哪些技术供应商因满足不了公司的安全政策而被淘汰?但网络安全管理员更关心技术层面,比如我们的SSL证书是最新的吗?我们是否应该更好的连接到恶意软件数据库,以保持对勒索软件攻击的控制?员工每天接触的前100名网站有哪些?

高层决策者和网络安全管理员必须通过内部沟通,才能确保大家所关心的威胁情报的角度是一致的。一般来说,这些角度题可以分为两个层次,一个是关于战略承诺,例如并购和长期合作伙伴关系,另一个是关于运营问题,例如网站、服务器和应用程序的增强、修复和配置。

威胁情报服务和其他任何新出现的安全服务一样,在带来大量的安全承诺和好处时,也必定会引起组织在安全方面的重新管理及资源配置,就像这篇文章中讨论的那些误解一样,只有消除这些误解才能威胁情报的潜力发挥到最大。

前言

本文所分析的CVE-2018-9581漏洞,和前段时间所分析的CVE-2018-9489和CVE-2018-15835属于同一漏洞系列,这三个漏洞具有相同的发生机理。

CVE-2018-9581允许进程间通信,导致信息泄漏。虽然Android系统上的应用程序通常由操作系统彼此隔离,同时各应用与操作系统本身隔离,但在需要时在它们之间仍然存在共享信息的机制,如intent,Android使用两种不同的intent定期广播有关WiFi连接的信息。

而CVE-2018-9489能将有关用户设备的信息暴露给设备上运行的所有应用程序,包括WiFi网络名称、BSSID、本机IP地址、DNS服务器信息和MAC地址。它使恶意应用程序得以绕过权限检查和现有的防护,访问系统广播信息。根据该通报,安全漏洞CVE-2018-9489不太可能得到任何修复。这一漏洞能影响安卓9.0 Pie以前的所有安卓版本。有了这些信息,攻击者可能会带来各种类型的攻击,比如进一步嗅探和攻击本地WiFi网络。此外,由于MAC地址是硬编码的,所以即使使用MAC地址随机化,它们也可用于唯一地识别和跟踪任何Android目标。

至于CVE-2018-15835,来自Android操作系统的intent消息会泄露了有关电池的详细信息,攻击者可在没有特殊权限的情况下,利用这些intent消息识别和跟踪用户。目前可以确定的是,Android 5.0会受到影响,但Google似乎不打算修复将其归类为安全漏洞。

这3个漏洞都是由于在Android操作系统的系统广播暴露了WiFi接收的信号强度指示(RSSI),利用该漏洞,攻击者可以在不需要额外权限的情况下,利用恶意软件获取此信息。它允许与WiFi路由器物理接近的攻击者跟踪路由器范围内用户的位置,从而根据附近的WiFi路由器来定位或跟踪用户(靠近WiFi路由器的手机将接收到更强的信号)。同样的问题也适用于底层Android API,但需要额外的权限。

目前所有的Android版本都受到该漏洞的影响,且Google尚未计划修复此漏洞。但在Android 9.0 Pie或更高版本中,CVE-2018-9489漏洞已经得到了修复,系统广播已经不再显示敏感数据。研究人员表示,他们不确定这种漏洞是否已在野外被开发利用。

CVE-2018-9581的漏洞利用原理

据估计,目前全球有超过20亿台设备在运行Android。 Android上的应用程序通常被操作系统彼此隔离,当然,它们也与操作系统之间相互隔离。但是,仍然存在一些机制(比如Intent),可以实现进程之间的通信,以及进程与操作系统的交互。Intent(Intent)主要是解决Android应用的各项组件之间的通讯。Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将Intent传递给被调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。

虽然存在限制阅读此类消息的权限,但应用程序开发人员通常忽略正确实施这些权限或屏蔽敏感数据。这导致Android应用程序中的常见漏洞,其中在同一设备上运行的恶意应用程序可以监视并捕获由其他应用程序广播的消息。

Android中存在的另一种安全机制是权限的设定,它们都是保护用户隐私的安全措施。应用程序必须通过应用程序列表(“AndroidManifest.xml”)中的特殊“uses-permission”标记明确请求访问某些信息或功能。Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行判断的。根据许可的类型(“正常”、“危险”等),Android系统可以在安装期间向用户显示相应的许可信息,或者可以在运行期间再次提示。不过某些权限只能由系统应用程序使用,并且不能由常规开发人员使用。

Google Play安装期间和应用程序运行期间的权限提示如下所示:

1.png

CVE-2018-9581的漏洞详细信息

Android系统会定期在系统范围内广播WiFi强度值(RSSI),无需特殊权限就可以访问此信息。 RSSI值表示设备接收的信号的相对强度,但不与实际物理信号强度(dBm)直接相关。这是通过两个独立的Intent(Android 9之前的“android.net.wifi.STATE_CHANGE” ;以及所有Android版本中的 “android.net.wifi.RSSI_CHANGED”)发布的。

虽然应用程序也可以通过WifiManager访问此信息,但根据规范,还需要应用程序列表中的“ACCESS_WIFI_STATE”权限。而在Android 9及以上的版本中,新增的WiFi RTT功能还需要“ACCESS_FINE_LOCATION”权限,才能捕获用户的WiFi位置。但是,如果攻击者在监听系统广播时,则不需要这样的权限,恶意应用程序在用户不知情的情况下捕获此信息。

这样,就会产生两个单独的安全漏洞:

1.只要绕过通常所需的权限检查(“ACCESS_WIFI_STATE”),RSSI值就可通过广播信息获得;

2.通过广播或WifiManager所获取的RSSI值,可以用于室内定位,无需特殊位置许可;

漏洞复现

普通用户可以按照如下步骤来复现此漏洞

1.从Google Play中下载“Internal Broadcasts Monitor”(内部广播监控)应用程序(由Vilius Kraujutis开发的);

2.打开应用程序,然后点击“开始”监控广播;

3.观察捕获的系统广播信息,注意Android 9以及之前版本的信息是“android.net.wifi.STATE_CHANGE”,而“android.net.wifi.RSSI_CHANGED” 信息存在于所有Android版本中。

观察的系统广播的截图:

2.png

通过代码的方式实现漏洞复现

要通过代码的方式实现漏洞复现,就需要由专门的软件研发人员来实现。首先是创建一个广播接收器,并将其进行注册,注册完了后,才能接收“android.net.wifi.STATE_CHANGE”(仅限Android v8.1及以下版本)和“android.net.wifi.RSSI_CHANGED”。

示例代码如下所示:

public class MainActivity extends Activity {
@Override
public void onCreate(Bundle state) {
    IntentFilter filter = new IntentFilter();        
    filter.addAction(android.net.wifi.STATE_CHANGE);
    filter.addAction(android.net.wifi.RSSI_CHANGED);
    registerReceiver(receiver, filter);
}
    
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
    Log.d(intent.toString());
    ….
}
};

本文的漏洞测试方法

设备配置

本文的研究人员在测试过程,使用了以下设备:

1.Pixel 2,Android 8.1.0系统,补丁更新至2018年7月;

2.Nexus 6P,Android 8.1.0系统,补丁更新至2018年7月;

3.Moto G4,Android 7.0系统,补丁更新至2018年4月;

4.Kindle Fire HD第八代,Fire OS 5.6.10系统,补丁更新至2018年4月;

5.路由器使用华硕RT-N56U,运行最新版本固件。

经过测试,Kindle Fire所使用的Android版本系统都存在以上漏洞。

测试步骤

测试步骤如下:

1.安装Broadcast Monitor应用程序;

2.将手机置为飞行模式;

3.开始Broadcast Monitor应用程序;

4.关闭飞行模式(触发RSSI广播);

5.从广播中获取的两个RSSI值有:

android.net.wifi.RSSI_CHANGE – newRssi 值和android.net.wifi.STATE_CHANGE – networkInfo / RSSI

6.在每个测试设备上,重复步骤3-4。

测试结果清除显示每个设备都具有独特的RSSI值范围,测试期间收集的RSSI值的列表如下。

4.jpg

Google的反应和缓解措施

Google已经将此漏洞划分在中等危险,并命名为CVE-2018-9581。目前Google尚未修复CVE-2018-9581,但在Android 9/P上,“android.net.wifi.STATE_CHANGE”将不再显示敏感数据,因为该问题已经在CVE-2018-9489中被修复,目前尚不清楚这个漏洞是否在野外利用的情况。

从iPhone 5S开始,生物识别数据就被存储在采用了64位架构的苹果A7处理器的设备上,想登陆你的设备,你可以轻松的使用钥匙串以及人脸ID或触摸ID完成整个验证过程。

本文,我将从静态身份验证一步一步的讲起,讲到如何使用钥匙串来存储和验证登录信息。

在本文中,在大多数情况下,我都是针对触摸ID进行介绍的,不过这个过程也适用于人脸ID,因为其底层的LocalAuthentication框架都是相同的。

测试准备工作

先点此下载一个基本的笔记应用程序的操作模板

操作板上有一个登录视图,用户可以输入用户名和密码,构建并运行当前的应用状态:

iOS-Simulator-Screen-Shot-Dec-21-2014-9.21.34-PM.png

此时,点击“login”按钮将简单的关闭视图并显示Note列表,你也可以从此屏幕创建新记录。点击注销就可以返回到登录视图。如果应用程序在后台使用,它会立即返回到登录视图。

在执行其它操作之前,你应该改变包标识符(bundle identifier)并创建一个组。选择TouchMeIn,创建TouchMeIn目标。在General选项中,将Bundle Identifier更改为使用你自己的域名,进行反向域标记 (reverse-domain-notation),例如com.raywenderich.TouchMeIn。

然后,从创建的组的菜单中,选择与你的开发者帐户关联的组。

002.png

此时,就可以编写登录代码了。

登录代码的编写

此时添加用户提供的凭证进来,以实施硬编码。

打开LoginViewController.swift并在managedObjectContext下方添加以下常量:

let usernameKey = "Batman"
let passwordKey = "Hello Bruce!"

这些只是需要编码的用户名和密码,你还需检查用户提供的凭证。

接下来,在loginAction(_:)中用以下方法进行添加。

func checkLogin(username: String, password: String) -> Bool {
  return username == usernameKey && password == passwordKey
}

此时,你可以根据以前定义的常量检查用户当前提供的凭证。接下来,用以下内容替换loginAction(_:)。

if checkLogin(username: usernameTextField.text!, password: passwordTextField.text!) {
  performSegue(withIdentifier: "dismissLogin", sender: self)
}

只要凭证正确,就可以开始调用checkLogin(username:password:)。

在本文中,我输入的用户名和密码分别是Batman 和Hello Bruce!,登陆后的状态如下所示。

003.png

这种简单的身份验证方法虽然可行,但它并不安全,因为存储为字符串的凭证很容易被黑客攻破。最安全的策略是,密码不应直接存储在应用程序中。此时,就要用到钥匙串来存储密码了。

目前,大多数应用程序的密码只是简单的字符串,以bullet的形式隐藏。在应用程序中处理密码的最佳方式进行SALT或SHA-2方式的加密。

钥匙串的构建过程

接下来要做的就是在应用程序中添加一个钥匙串封装器,如上所述,我会下载一个模板,下载时还会带一个有用的资源文件夹。找到并打开Finder中的资源文件夹,你会看到KeychainPasswordItem.swift文件,这个类来自苹果的样本代码GenericKeychain。拉进来,如下所示。

004.png

确保Copy items if needed和TouchMeIn选项都被选中:

005.png

如果一切顺利,现在你就可以利用你的应用程序中的钥匙串了。

钥匙串的使用

要使用钥匙串,你首先要在其中存储用户名和密码。接下来,你将检查用户提供的凭证,以查看它们是否与钥匙串中存储的用户名和密码匹配。

你需要跟踪用户创建的凭证,以便你可以将“登录”按钮上的文本从“创建”更改为“登录”。你还会将用户名存储在用户默认值中,这样你就可以在每次执行此检查时自动执行该过程。

钥匙串需要一些配置才能正确存储你的应用程序的信息,你将以serviceName和可选的accessGroup的形式提供该配置。最终,你会使用一个结构来存储这些值。

打开LoginViewController.swift,在导入语句下方添加以下内容。

// Keychain Configuration
struct KeychainConfiguration {
  static let serviceName = "TouchMeIn"
  static let accessGroup: String? = nil
}

接下来,添加下面的managedObjectContext:

var passwordItems: [KeychainPasswordItem] = []
let createLoginButtonTag = 0
let loginButtonTag = 1
@IBOutlet weak var loginButton: UIButton!

passwordItems是你将传入钥匙串的KeychainPasswordItem类型的空数组,这样你将使用两个常量来确定登录按钮是否被用来创建一些凭证,以便你使用loginButton输出口来根据其创建状态来更新登录按钮的标题。

接下来,会出现两种情况:如果点击按钮时,如果用户还没有创建凭证,按钮文本将显示“创建”;否则按钮将显示“登录”。

如果登录失败,你需要是在checkLogin(username:password:)后添加以下内容:

private func showLoginFailedAlert() {
  let alertView = UIAlertController(title: "Login Problem",
                                    message: "Wrong username or password.",
                                    preferredStyle:. alert)
  let okAction = UIAlertAction(title: "Foiled Again!", style: .default)
  alertView.addAction(okAction)
  present(alertView, animated: true)
}

现在,将loginAction(sender:)替换为以下内容:

@IBAction func loginAction(sender: UIButton) {
  // 1
  // Check that text has been entered into both the username and password fields.
  guard let newAccountName = usernameTextField.text,
    let newPassword = passwordTextField.text,
    !newAccountName.isEmpty,
    !newPassword.isEmpty else {
      showLoginFailedAlert()
      return
  }
    
  // 2
  usernameTextField.resignFirstResponder()
  passwordTextField.resignFirstResponder()
    
  // 3
  if sender.tag == createLoginButtonTag {
    // 4
    let hasLoginKey = UserDefaults.standard.bool(forKey: "hasLoginKey")
    if !hasLoginKey && usernameTextField.hasText {
      UserDefaults.standard.setValue(usernameTextField.text, forKey: "username")
    }
      
    // 5
    do {
      // This is a new account, create a new keychain item with the account name.
      let passwordItem = KeychainPasswordItem(service: KeychainConfiguration.serviceName,
                                              account: newAccountName,
                                              accessGroup: KeychainConfiguration.accessGroup)
        
      // Save the password for the new item.
      try passwordItem.savePassword(newPassword)
    } catch {
      fatalError("Error updating keychain - (error)")
    }
      
    // 6
    UserDefaults.standard.set(true, forKey: "hasLoginKey")
    loginButton.tag = loginButtonTag
    performSegue(withIdentifier: "dismissLogin", sender: self)
  } else if sender.tag == loginButtonTag {
     // 7
    if checkLogin(username: newAccountName, password: newPassword) {
      performSegue(withIdentifier: "dismissLogin", sender: self)
    } else {
      // 8
      showLoginFailedAlert()
    }
  }
}

那为什么不把用户名密码和UserDefaults一起存储呢?因为存储在UserDefaults中的值是使用plist文件保存的。它本质上是一个驻留在应用程序库文件夹中的XML文件,因此任何人都可以读取设备的物理访问。另一方面,钥匙串使用三重数字加密标准(3DES)来加密其数据。即使有人获得这些数据,他们也将无法读取。

接下来,用以下内容替换checkLogin(username:password:)。

let usernameKey = "Batman"
let passwordKey = "Hello Bruce!"

此时,需要检查输入的用户名是否与UserDefaults中存储的用户名相匹配,并且密码与钥匙串中存储的密码是否也相匹配。

删除以下几行内容:

// 1
let hasLogin = UserDefaults.standard.bool(forKey: "hasLoginKey")
    
// 2
if hasLogin {
  loginButton.setTitle("Login", for: .normal)
  loginButton.tag = loginButtonTag
  createInfoLabel.isHidden = true
} else {
  loginButton.setTitle("Create", for: .normal)
  loginButton.tag = createLoginButtonTag
  createInfoLabel.isHidden = false
}
    
// 3
if let storedUsername = UserDefaults.standard.value(forKey: "username") as? String {
  usernameTextField.text = storedUsername
}

根据hasLoginKey的状态,适当地设置按钮标题和标签。将下面的代码添加到viewDidLoad()中,然后调用super:。

006.png

在弹出窗口中,选择loginButton:

007.png

运行时,输入你自己选择的用户名和密码,进行创建。

请注意,如果你忘记连接loginButton 输出口,那么你可能会看到错误的Fatal error: unexpectedly found nil while unwrapping an Optional value。

现在,点击注销并尝试使用相同的用户名和密码登录 ,此时你应该会看到出现的注释列表。

点击注销并尝试重新登录,不过这次使用的是不同的密码,然后点击登录。此时,你应该会看到以下警告:

008.png

现在你已经可以使用钥匙串添加身份验证了。接下来,就要创建触摸ID了。

触摸ID

人脸ID要求你在物理设备(如iPhone X)上进行测试,触摸ID现在可以在模拟器中的Xcode 9中模拟。你可以在任何使用A7芯片或更新的设备和人脸ID / 触摸ID硬件的设备上测试生物识别ID。

除了使用钥匙串之外,你还需要将生物识别ID添加到你的项目中。

打开Assets.xcassets

接下来,从Finder中先前下载的项目中打开Resources文件夹。找到FaceIcon和Touch-icon-lg.png图像,并将它们拖到Images.xcassets中,它们唯一的差别就是分辨率。

009.png

打开Main.storyboard并把对象库中的按钮拖动到堆栈视图中的“创建信息标签”下方的Login View Controller Scene中。你可以打开Document Outline,打开开合三角标识,并确保Button在堆栈视图内。如下所示:

010.png

在“属性”检查器中,调整按钮的属性:

1.将类型设置为自定义;

2.将标题设置为空;

3.将图像设置为Touch-icon-lg;

完成后,属性应如下所示。

011.png

选中新的按钮,然后选择 “添加新约束”按钮,将约束条件设置如下。

012.png

操作视图现在应该如下所示:

013.png

现在,你仍然在Main.storyboard中,打开辅助编辑器并确保显示LoginViewController.swift。接下来,就像在其它输出口一样,从你刚添加到LoginViewController.swift的按钮中选择控制标记(Control-drag)。

014.png

在弹出框中输入touchIDButton,然后单击连接。

015.png

这样,你会创建一个输出口,用于隐藏没有生物识别ID的设备上的按钮。

接下来,为该按钮添加一个操作过程。把来自同一个按钮的控制标记拖动到LoginViewController.swift,也就是 checkLogin(username:password:)的上面。

016.png

在弹出窗口中,将Connection更改为Action,将Name设置为touchIDLoginAction,现在将Arguments设置为none,然后点击连接,运行以检查是否有任何错误。

017.png

添加本地认证

本地身份验证框架提供了用于请求用户使用指定的安全策略进行身份验证的工具,而本文所介绍的安全策略就是用户的生物识别技术 。

iOS 11的新功能支持人脸ID,LocalAuthentication添加了一些新的功能:所需的FaceIDUsageDescription和LABiometryType是用来确定设备是否支持人脸ID或触摸ID。

在Xcode的项目导航器中选择项目并单击Info选项,然后单击+。开始输入“隐私”,然后在出现的弹出列表中选择“隐私 – 脸部ID使用说明”,不过你也可以输入“NSFaceIDUsageDescription”。

这是字符串,在value字段中,你可以使用Face ID来解锁这些注释。

018.png018.png

在项目导航器中,右键单击TouchMeIn组文件夹并选择New File,直到找到iOS \ Swift文件,然后点击下一步。将TouchMeIn目标文件保存为TouchIDAuthentication.swift,点击创建。

打开TouchIDAuthentication.swift并在import Foundation添加以下导入内容:

import LocalAuthentication

接下来,添加以下内容来创建一个新的类:

class BiometricIDAuth {
  
}

现在你需要引用LAContext类,在花括号之间添加以下代码。

let context = LAContext()

用上下文引用认证上下文,这是本地认证的主要特点。如果BiometricIDAuth内部支持生物特征ID,则添加以下方法以返回Bool:

func canEvaluatePolicy() -> Bool {
  return context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
}

打开LoginViewController.swift并添加以下属性以创建对BiometricIDAuth的引用:

let touchMe = BiometricIDAuth()

在viewDidLoad()底部添加如下内容:

touchIDButton.isHidden = !touchMe.canEvaluatePolicy()

在本文,你可以使用canEvaluatePolicy(_:)来检查设备是否可以实现生物认证。

面部ID或触摸ID

如果你使用的是iPhone X或更高版本的人脸ID设备,那就要注意了。因为此时,触摸ID图标 已经被删除了。不过,你可以使用biometryType枚举类来解决这个问题,打开TouchIDAuthentication.swift并在类的上方添加BiometricType枚举。

enum BiometricType {
  case none
  case touchID
  case faceID
}

接下来,添加以下函数以使用canEvaluatePolicy返回来选择支持的生物特征类型。

func biometricType() -> BiometricType {
  let _ = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
  switch context.biometryType {
  case .none:
    return .none
  case .touchID:
    return .touchID
  case .faceID:
    return .faceID
  }
}

打开LoginViewController并将以下内容添加到viewDidLoad()的底部,修复按钮的图标:

switch touchMe.biometricType() {
case .faceID:
  touchIDButton.setImage(UIImage(named: "FaceIcon"),  for: .normal)
default:
  touchIDButton.setImage(UIImage(named: "Touch-icon-lg"),  for: .normal)
}

在触摸ID注册的模拟器上构建并运行,查看触摸ID图标,此时你会看到脸部ID图标显示在iPhone X上。

打开TouchIDAuthentication.swift并在上下文中添加以下变量:

var loginReason = "Logging in with Touch ID"

接下来,将下面的方法添加到BiometricIDAuth的底部以对用户进行身份验证。

func authenticateUser(completion: @escaping () -> Void) { // 1
  // 2
  guard canEvaluatePolicy() else {
    return
  }
  // 3
  context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
    localizedReason: loginReason) { (success, evaluateError) in
      // 4
      if success {
        DispatchQueue.main.async {
          // User authenticated successfully, take appropriate action
          completion()
        }
      } else {
        // TODO: deal with LAError cases
      }
  }
}

如果用户通过身份验证,则可以关闭登录视图。

错误响应

如果你没有在你的设备上设置生物识别ID,那该怎么办?本地身份验证的一个重要部分是错误响应,所以框架中会包含一个LAError类,不过也有可能是从第二次使用canEvaluatePolicy获得的一个错误。

此时,你会收到一个警告,告诉你问题所在。你需要将TouchIDAuth类的消息传递给LoginViewController。幸运的是,你可以使用完成处理程序来传递可选消息。打开TouchIDAuthentication.swift并更新authenticateUser方法。更改签名以包含一个可选的消息,即遇到错误时的提示消息。

func authenticateUser(completion: @escaping (String?) -> Void) {

接下来,查找// TODO:并将其替换为以下内容。

// 1
let message: String
            
// 2
switch evaluateError {
// 3
case LAError.authenticationFailed?:
  message = "There was a problem verifying your identity."
case LAError.userCancel?:
  message = "You pressed cancel."
case LAError.userFallback?:
  message = "You pressed password."
case LAError.biometryNotAvailable?:
  message = "Face ID/Touch ID is not available."
case LAError.biometryNotEnrolled?:
  message = "Face ID/Touch ID is not set up."
case LAError.biometryLockout?:
  message = "Face ID/Touch ID is locked."
default:
  message = "Face ID/Touch ID may not be configured"
}
// 4
completion(message)

完成这些更改后,完成的方法应该如下所示:

func authenticateUser(completion: @escaping (String?) -> Void) {
    
  guard canEvaluatePolicy() else {
    completion("Touch ID not available")
    return
  }
    
  context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
    localizedReason: loginReason) { (success, evaluateError) in
      if success {
        DispatchQueue.main.async {
          completion(nil)
        }
      } else {
                              
        let message: String
                              
        switch evaluateError {
        case LAError.authenticationFailed?:
          message = "There was a problem verifying your identity."
        case LAError.userCancel?:
          message = "You pressed cancel."
        case LAError.userFallback?:
          message = "You pressed password."
        case LAError.biometryNotAvailable?:
          message = "Face ID/Touch ID is not available."
        case LAError.biometryNotEnrolled?:
          message = "Face ID/Touch ID is not set up."
        case LAError.biometryLockout?:
          message = "Face ID/Touch ID is locked."
        default:
          message = "Face ID/Touch ID may not be configured"
        }
          
        completion(message)
      }
  }
}

编译错误响应时,你会看到三条警告,都是关于常量的。这是由于苹果增加了对人脸ID的支持,以及Swift导入Objective-C头文件的方式。

人脸ID 

关于iPhone X的最酷的事情之一是使用脸部识别而不用触摸屏幕。你可以通过添加了一个可用于触发人脸ID的按钮,但也可以自动触发人脸ID。

打开LoginViewController.swift并在viewDidLoad()下面添加如下代码:

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  let touchBool = touchMe.canEvaluatePolicy()
  if touchBool {
   touchIDLoginAction()
  }
}

这将验证你的设备是否支持生物识别ID,如果支持,则设备将尝试验证用户。在装有iPhone X或人脸ID的设备上构建并运行,以测试运行是否正常。你可以从这里下载完整的示例应用程序。

你在本文中创建的LoginViewController可以为任何需要管理用户凭证的应用程序提供参考。你还可以添加一个新的视图控制器,或修改现有的LoginViewController,以允许用户随时更改密码。不过,这对于生物识别ID来说是不必要的,但是,你可以创建一个更新钥匙串的方法,以提示用户在修改密码时输入当前的密码。你可以在苹果的官方iOS安全指南中了解更多有关保护你的iOS应用程序的信息。

之前的文章中,我们讨论了内核池溢出漏洞,并提出了一种新的缓解措施,旨在阻止在Windows 7和8系统上使用特定的漏洞利用技术。此缓解措施后来被纳入我们的开源内核模式漏洞利用缓解工具包,称为SKREAM

尽管我们在Windows 8.1中缓解了某些恶意利用(在0xbad0b0b0中构建恶意OBJECT_TYPE结构),但是池溢出漏洞仍然是现代系统中普遍存在的问题,并且正在通过不同的、更复杂的方法积极加以利用。考虑到这一点,我们希望SKREAM的环境技术能更进一步,以一种更通用的方式缓解池溢出漏洞,这种方式可以缓解针对开源的Windows内核模式漏洞利用的攻击。

成功利用池溢出有几个关键前提,最关键的是,攻击者必须能够非常仔细的制作溢出的缓冲区,准确的知道他们计划写入哪些数据,并保持其余数据不变。这意味着任何放错位置的字节都可能以一种意想不到的方式破坏下一个池分配,从而导致可能出现蓝屏死机。

1.png

池溢出示意图,例如,在TypeIndex覆盖攻击中,漏洞会尝试将下一个池块的ObjectHeader.TypeIndex设置为0或1

为此,它必须计算ObjectHeader与溢出缓冲区开头的确切距离,以及TypeIndex成员在其中的偏移量。

考虑到代表攻击者所需的字节级精度,我们可以通过向池分配引入一定程度的随机化来打破此类的大多数漏洞。在随机化池分配时,我们有两种可能的操作方法 ,可以选择转移(或滑动)分配,也可以简单的增大池的容量。这两种方法的最终目标都是使攻击者不知道必要的溢出的大小,每种方法都有其相对的优点和缺点。

PoolSlider方案

正如WDK文档所介绍的那样,x64上内核池分配工具的一个关键属性是所有分配必须对齐并四舍五入为16个字节(或x86上的8个字节)。这意味着任何请求大小,只要不是16的整倍数的分配,将接收额外的几个字节的填充,以便将其大小进行整倍数的匹配。

2.png

请求大小(rdx)为0x68字节的池分配,最终块大小为0x80字节:池头(0x10)+请求大小(0x68)+填充(0x8)

显然,试图溢出这种分配的攻击者必须考虑到池管理器添加的额外填充字节。例如,在图2中所示的分配中,有0x70字节在到达下一个池分配之前必须被覆盖,即使调用者仅请求了0x68。

在PoolSlider缓解方案中,我们利用这个填充和“slide”(即前进),指针以随机数返回给调用者。这样,我们就会很隐蔽的在池块的开头创建一些填充,同时减少在末尾找到的填充量。这就有效的破坏了池溢出攻击的可预测性,攻击者会尝试考虑填充字节,但由于整个分配被移位,因此攻击者不会将预期的数据写入计划位置,漏洞将不会按着预期利用。

3.png

右边的是具有PoolSlider的池分配,而左边是没有PoolSlider的池分配

可以通过扩展SKREAM来监控图像加载事件并在每个新加载的驱动程序上为ExAllocatePoolWithTag放置一个IAT挂钩来实现此缓解。无论何时进行池分配,我们的钩子都会计算添加到它的填充字节数。然后它生成一个介于1和可用填充量之间的随机数,并将返回给调用者的指针向前推进。

4.png

释放处理

当然,通过推进返回给调用者的指针,我们打破了池的可预测性,但这不仅仅是针对潜在的攻击者。池管理工具做出的一个关键假设是,返回给调用者的指针紧跟在描述分配的POOL_HEADER结构之后。这意味着当尝试释放由'P'表示的池块时(例如,通过调用nt!ExFreePoolWithTag),池管理工具将在<P-sizeof(POOL_HEADER)>处搜索相关的池头。毋庸置疑,当启用PoolSlider时,此假设会完全中断,并且系统将因错误检查0x19(BAD_POOL_HEADER)而崩溃。

为了正确处理释放,我们不得不在ExFreePoolWithTag上放置一个额外的IAT钩子,并在实际释放它之前将指针重新对齐成16个字节。

5.png

其他问题

在测试PoolSlider方案时,我们遇到了一些问题。有些相对容易解决,而其他一些则面临重大挑战:

1.使用ExAllocatePoolWithTag进行分配并使用ExFreePool进行释放(反之亦然):只需挂钩ExAllocatePool和ExFreePool并进行与Ex {Allocate,Free} PoolWithTag相同的随机化或重新对齐操作即可解决此问题。

2.使用ExAllocatePool(WithTag)分配字符串并使用RtlFree{Ansi, Unicode}释放它:这是一种糟糕的编程习惯,因为字符串应使用匹配的分配例程进行分配。在内部,这些释放函数将字符串对象的“缓冲区”成员转发到ExFreePool(WithTag),如果指针未正确对齐成16个字节,则会导致系统崩溃。这可以通过简单地在RtlFree{Ansi, Unicode}字符串上放置额外的IAT钩子,并像ExFreePool(WithTag)中那样重新对齐指针来修复。

3. 在池中分配的Lookaside列表头:些驱动程序在使用nt!ExInitializeLookasideListEx进行初始化时初始化了Lookaside列表。这个函数接收的第一个参数是“PLOOKASIDE_LIST_EX Lookaside”。

SKREAM6-1.png

大多数驱动程序将此结构保留为驱动程序数据部分中的全局变量,但有些驱动程序选择在池中动态分配它。由于我们将返回给调用者的指针地址“随机化”,在这种情况下,这个结构的开始地址不是16字节对齐的,导致在调用nt!ExInitializeLookasideListEx时引发错误0x80000002(STATUS_DATATYPE_MISALIGNMENT)。

4.由一个驱动分配内存,另一个驱动释放内存:我们遇到的最复杂的情况是一个驱动程序分配池内存,而另一个驱动程序(通常是NTOS)释放它。在这种情况下,当释放驱动程序未被挂钩时,我们无法在调用ExFreePool之前重新对齐指针,从而导致BSOD出现错误检查0xC2(BAD_POOL_CALLER)。

6.png

由Blbdrive.sys分配的带有标签“Blbp”的池分配,稍后由NTOS直接释放。请注意,池块的地址未对齐到0x10,导致错误检查0xC2

到目前为止,我们还没有解决的另一个问题是池分配的情况,其请求的大小是16的倍数。由于在这些情况下没有额外的填充,因此PoolSlider无法使返回给调用者的指针向前推进。

但是,可以通过在对齐的池块的末尾,进行人为填充来解决此问题。简单的将1个字节添加到所请求的分配大小将导致池管理工具添加另外15个字节的填充,以便将块大小重新对齐成16个字节。然后,我们可以使用一些填充。

7.png

PoolSlider与HEVD的比较

我们对PoolSlider进行了测试,它利用了HEVD中一个未分页池溢出漏洞。

8.png

稍后将被利用的池分配,请注意,返回给调用者(保存在rax寄存工具中)的指针移位了5个字节

9.png

溢出前后的池块标头的比较,可以看到,这个漏洞没有保留原来的池头,在这种特殊情况下,由于PoolSlider移动了指针,溢出会被5个字节阻止

10.png

漏洞利用损坏了下一个标头,但未能保持池的完整性,这最终将导致错误检查

PoolBloater方案

减少池溢出的第二种方法简单得多,其原理就是根本不改变分配的基本地址,而是通过随机的字节量增加所请求的池分配的大小,从而破坏潜在利用的字节精度。

11.png

右边是具有PoolBloater的池分配,而左边是没有PoolBloater的池分配

与PoolSlider相比,PoolBloater的实现方式非常简单。我们用与在PoolSlider中相同的方式挂钩ExAllocatePool(WithTag),并且只更改钩子内部执行的操作过程。

12.png

这种方法的主要优点是它能避免我们在尝试PoolSlider时遇到的大多数问题,由于我们只改变了池块的大小,因此我们不必面对因指针未对齐而导致的问题。该方法的另一个明显优点是,它可以使池的喷涂技术(spray)无用,因为溢出块的大小是随机的。

13.png

13.2.png

可以看到启用PoolBloater后,分配池大小将变得更大,因此它适合于分配,这意味着攻击者无法对分配进行控制

但是,这种方法的缺点也很明显,池内存利用率可能会比平常高得多,具体取决于添加到每个分配的字节数。一般而言,这种缓解方式会表现出固有的权衡机制,为我们的随机化选择一个较高的上限将导致更强的缓解能力,代价是资源更密集。另一方面,为我们的随机化选择一个较低的下线将导致池的利用率保持相当正常,但使缓解变弱。

总结

这两种缓解方式都存在一些固有的缺点,这些缺点主要是由其他系统机制(如PatchGuard)引起的,这些机制限制了我们监视系统中每个驱动程序的能力,尤其是内核可执行文件本身(NTOSKRNL)。因此,我们目前只尝试处理池溢出攻击的场景。

目前,我们的缓解措施都受到以下限制:

1.我们只保护不属于Windows操作系统的驱动程序;

2.我们只保护在安装了SKREAM之后加载的驱动程序;

3.我们只保护由故障驱动程序通过ExAllocatePool(WithTag)直接执行的分配,系统所做的任何分配都是不受保护的,即使它稍后被转发给第三方驱动程序进行进一步处理(例如,IOCTLs的SystemBuffer),也是不可以的;

4.我们只保护与页面非常匹配的分配,跨越一个页面或更多页面的更大的分配由nt!ExpAllocateBigPool以不同的方式处理;

5.我们仍然没有实现取消挂钩,如果在启用PoolSlider的情况下编译SKREAM,则无法将其服务配置为以“system”身份启动,而只能将其设置为“auto”(否则操作系统可能会崩溃),这意味着卸载SKREAM会有系统崩溃的风险。

媒体框架是安卓系统组件中经常被发现安全漏洞的组件,所以每次谷歌发布月度例行更新时经常会有它的身影。Google最近发现的媒体框架的漏洞是远程代码执行漏洞,攻击者可以制作特定的文件利用特权进程执行任意代码。目前Google已将其命名为CVE-2018-9411,危险等级定位危急,并在7月安全更新(2018-07-01补丁)中对其进行了修补,包括9月安全更新(2018-09-01补丁)中的一些附加补丁。

我还为此漏洞编写了一个概念验证利用,演示了如何使用它来从常规非特权应用程序的上下文中提升权限。

本文,我将介绍该漏洞和利用此漏洞的技术细节。首先我将介绍与漏洞相关的一些背景信息,然后再详细介绍漏洞本身。在介绍如何利用此漏洞的过程中,我将选择一个特定服务作为攻击目标,而不是受漏洞影响的其他服务。另外,我还将分析与漏洞相关的一些服务。最后,我将介绍我编写的概念验证漏洞利用的详细信息。

Project Treble

什么是Project Treble?简单的说就是谷歌为了整理安卓的碎片化,为了让手机厂商适配安卓版本更轻松,推出的新架构。

Project Treble对Android内部运作方式进行了大量更改,其中的一个巨大的变化是许多系统服务的分离。以前,Android服务包含AOSP(Android开源项目)和供应商代码。在Project Treble出现之后,这些服务会被分为一个AOSP服务和一个或多个供应商服务,称为HAL服务。更多背景信息,请点此

HIDL

Project Treble的服务的分离增加了IPC(进程间通信)的量,以前在AOSP和供应商代码之间的同一进程中传递的数据,现在必须通过AOSP和HAL服务之间通过IPC。由于Android中的大多数IPC都要经过Binder,谷歌决定新的IPC也应该这样做。

但仅仅使用现有的Binder代码是满足不了新的IPC的,Google决定对其进行一些修改。首先,Google引入了多个Binder域,以便将这种新型IPC与其他域分开。更重要的是,他们引入了HIDL,这是一种通过Binder IPC传递的数据的全新格式。这种新格式由一组新的库支持,专用于AOSP和HAL服务之间的IPC新Binder域,其他Binder域仍使用旧格式。

与旧的HIDL格式相比,新HIDL格式的操作有点像层,新旧两种情况下的底层都是Binder内核驱动程序,但顶层是不同的。对于HAL和AOSP服务之间的通信,使用新的库;对于其他类型的通信,使用旧的库。这两种库包含的代码都非常相似,以至于新的HIDL库中某些原始代码会直接从旧库中复制到。虽然每个库的用法并不完全相同(你不能简单地用一个替换另一个),但它们仍然非常相似。

这两组库都以c++对象的形式表示Binder事务中传输的数据,从相对简单的对象(比如表示字符串的对象)到更复杂的实现(比如文件描述符或对其他服务的引用),这意味着HIDL为许多类型的对象引入了新的实现方式。

共享内存

Binder IPC的一个重要功能就是可以共享内存,为了保持简单性和良好性能,Binder将每个事务限制为最大1MB。对于进程希望通过Binder在彼此之间共享大量数据的情况,使用共享内存。

为了通过Binder共享内存,进程利用Binder的共享文件描述符的功能。使用mmap可以将文件描述符映射到内存,这允许多个进程通过共享一个文件描述符来共享同一个内存区域,常规Linux(非Android)的一个问题是,文件描述符通常由文件支持,如果进程想要共享匿名内存区域怎么办?出于这个原因,Android采用了Ashmem匿名共享内存机制,它允许进程在没有涉及实际文件的情况下分配内存,来备份文件描述符。

是否是通过Binder共享内存处理对象,是HIDL和旧库之间的一个区别。在这两种情况下,最终操作都是相同的,一个进程将ashmem文件描述符映射到其内存空间,通过Binder将该文件描述符传输到另一个进程,而另一个进程将其映射到自己的内存空间。不过,在处理对象的实现方式上是不同的。

在HIDL的情况下,共享内存的一个重要对象是hidl_memory,如源代码中所述:“hidl_memory是一种结构,可以用于在进程之间传输共享内存”。

漏洞介绍

让我们来看看hidl_memory的组成内容:

1.png

其中mHandle是一个句柄,它是一个HIDL对象,它包含文件描述符(在本文所举的样本中只有一个文件描述符)。mSize 表示要共享的内存大小,mName应该代表内存的类型,但是只有ashmem类型与此相关。

当通过HIDL中的Binder传输这样的结构时,复杂对象(比如hidl_handle或hidl_string)有自己的用于写入和读取数据的自定义代码,而简单类型(比如整数)则没有自定义代码。这意味着代码大小会被转换为64位整数,而在旧的库中,则使用32位整数。

这看起来很奇怪,为什么内存的大小应该是64位?为什么不像旧的库那样,用32位进程处理这个问题呢?让我们看一下映射hidl_memory对象(用于ashmem类型)的代码:

2.png

其中,没有任何关于32位进程的内容,甚至没有提到64位进程。

那其中到底发生了什么?mmap签名中的length字段的类型是size_t,这意味着它的位数与进程的位数相匹配。在64位进程中没有问题,一切都只是64位。另一方面,在32位进程中,大小被截断为32位,因此仅使用较低的32位。

这意味着,如果32位进程接收到大小大于UINT32_MAX(0xFFFFFFFF)的hidl_memory,则实际的映射内存区域将不够用。例如,对于大小为0x100001000的hidl_memory,内存区域的大小将仅为0x1000。在这种情况下,如果32位进程是基于hidl_memory大小执行边界检查,它们将会失败,因为它们将错误地表明内存区域跨越的范围超过整个内存空间,这就是漏洞。

寻找攻击目标

现在我们试着找到一个攻击目标,寻找符合以下标准的HAL服务:

1.编译为32位;

2.把对共享内存的接收作为输入;

3.在共享内存上执行边界检查时,不会截断大小。例如,以下代码不容易受到攻击,因为它对截断的size_t执行边界检查:

3.png

以上都是此漏洞的基本要求,但我认为还有一些更重要的要求:

4.在AOSP中有默认实现,虽然供应商最终会负责所有HAL服务,但AOSP确实包含某些供应商可以使用的默认实现。我发现在许多情况下,当存在这样的实现时,供应商不愿意修改它,只是按原样使用它。这使得这样的目标更有趣,因为它可能与多个供应商相关,而不是特定于某个供应商的服务。

你应该注意的一件事是,尽管HAL服务应该只能由其他系统服务访问,但事实并非如此。有一些精选的HAL服务实际上可以由常规的非特权应用程序访问。因此,最后一个要求是:

5.可以从无特权的应用程序直接访问,否则漏洞利用将实现不了,下面我们将讨论的一个漏洞,只有在你已经破坏了另一个服务的情况下才能访问它。

幸运的是,我找到了一个满足所有这些要求的HAL服务:android.hardware.cas,又称为MediaCasService。

CAS

CAS代表条件访问系统,简单来说它与DRM类似。简单地说,它的功能与DRM相同,有需要解密的加密数据。

MediaCasService

首先,MediaCasService确实允许应用程序解密加密数据。如果你阅读我以前的文章,就会知道我是如何利用名为MediaDrmServer的服务中的漏洞。你可能会奇怪,我为什么要与DRM进行比较?因为MediaCasService与MediaDrmServer(负责解密DRM媒体的服务)从其API到内部运行方式都非常相似。

需要注意的是,MediaDrmServer这个API被称为descramble,而不是decrypt(尽管它们最终也会在内部对其进行解密)。

让我们看看descramble是如何运作的:

4.png

不出所料,数据通过共享内存共享,有一个缓冲区指示共享内存的相关部分(称为srcBuffer,但是对于源和目标都是相关的)。在此缓冲区上,服务从其中读取源数据以及将目标数据写入的位置都存在偏移量。此时,源数据不是加密的,在这种情况下,服务只需将数据从源复制到目标,而无需修改它。

这看起来很脆弱,至少,如果服务仅使用hidl_memory大小来验证它是否完全适合共享内存,而不是其他参数,则会如此。在这种情况下,通过让服务相信我们的小内存区域跨越了它的整个内存空间,我们就可以绕过边界检查,并将源和目标偏移量放在我们喜欢的任何地方。这将使我们能够对服务内存进行完整的读写访问,因为我们可以从任何地方读取到共享内存,从共享内存写入任何地方。注意,负偏移量也应利用此漏洞,因为即使是0xFFFFFFFF(-1)也会小于hidl_memory大小。

让我们通过查看descramble的代码来验证这一点,请注意,函数validateRangeForSize只检查“first_param + second_param <= third_param”,而忽略可能的溢出。

5.png

可以看到,代码根据hidl_memory大小检查srcBuffer是否位于共享内存中。在此之后,不再使用hidl_memory,其余的检查将针对srcBuffer本身执行。至此,为了实现完整的读写访问,我们需要做的就是使用这个漏洞,然后将srcBuffer的大小设置为大于0xFFFFFFFF。这样,源和目标偏移量的任何值都是有效的。

6.png

使用漏洞进行越界读取

7.png

使用漏洞进行越界写入

TEE设备

在使用这个原语编写漏洞之前,让我们先想好这个漏洞要实现的目标。查看此服务的SELinux规则,就可以看到它实际上受到严格限制,并且没有很多权限。不过,它还有一个普通的非特权应用程序没有的有趣权限,就是对TEE(可信执行环境)设备的访问。

此权限非常有趣,因为它允许攻击者访问各种各样的内容,比如不同供应商的不同设备驱动程序、不同的信任区域操作系统和大量信任。在我之前的文章中,我已经讨论过这个权限有多危险了。

虽然访问TEE设备确实可以验证很多事情,但我只想证明我可以获得此访问权限。因此,我的目标是执行一个需要访问TEE设备的简单操作。在Qualcomm TEE设备驱动程序中,有一个相当简单的ioctl,用于查询设备上运行的QSEOS版本。因此,构建MediaCasService漏洞时的目标是运行此ioctl并获取其结果。

漏洞利用

到目前为止,我们对目标进程内存进行了完全读取和写入。虽然这是一个很好的开始,但有两个问题需要解决:

1.ASLR:虽然我们有完全的读访问权限,但它只与共享内存映射的位置相关。我们并不知道它与内存中的哪些数据进行比较。理想情况下,我们希望找到共享内存的地址以及其他有趣数据的地址。

2.漏洞在每次执行时,共享内存都会被映射,然后在操作后取消映射。不能保证每次都将共享内存映射到同一个位置,在执行期间完全有可能会有另一个内存区域取代原来的映射位置。

让我们看一下这个特定构建的服务内存空间中链接器的一些内存映射:

8.png

如上说示,链接器恰好在linker_alloc_small_objects和linker_alloc之间创建了2个内存页(0x2000)的小差距。这些存储器映射的地址相对较高,此进程加载的所有库都映射到较低的地址。这意味着这个差距是内存中最高的差距。由于mmap的行为是尝试将低地址映射到高地址,因此任何映射2页或更少内存区域的尝试都应映射到此差距中。幸运的是,该服务通常不会映射这么小的内容,这意味着这个差距应该留在那里。这就解决了我们的第二个问题,因为这是内存中的确定性位置,我们的共享内存将始终映射在这个位置。

让我们直接查看差距之后的linker_alloc中的数据:

9.png

这里的链接器数据恰好对我们有用,它包含的地址可以很容易的指示linker_alloc内存区域的地址。由于漏洞提供了相对读取,并且我们已经得出结论,共享内存将在linker_alloc之前被直接映射,因此我们可以使用它来确定共享内存的地址。如果我们取偏移量为0x40的地址并将其减少0x10,就将得到linker_alloc地址,减少共享内存本身的大小将导致共享内存地址。

到目前为止,我们解决了第二个问题,但第一个问题只是部分解决了。虽然我们确实有共享内存的地址,但没有其他有趣数据的地址,我们感兴趣的其他数据还有哪些呢?

劫持一个线程

MediaCasService API的一部分功能是客户端为事件提供监测的能力,如果客户端提供侦听器,则会在发生不同CAS事件时通知它。客户端也可以自己触发事件,然后将其发送回侦听器。Binder和HIDL的工作方式是,当服务向侦听器发送事件时,它将等待侦听器完成对事件的处理,等待侦听器的线程将被阻塞。

10.png

触发事件的流程

此时,我们可以在已知的预定线程中阻止服务中的线程发生阻塞。一旦我们有一个处于这种状态的线程,就可以修改它的堆栈来劫持它,只有在我们完成后,才能通过完成处理事件来恢复线程。不过,我们如何在内存中找到线程堆栈?

由于我们的确定性共享内存地址很高,该地址与阻塞线程堆栈的可能位置之间的距离很大。由于ASLR的影响,试图从确定性地址相对地查找线程堆栈太不可靠,所以我们使用了另一种方法,即尝试使用更大的共享内存,并在阻塞的线程堆栈之前映射它,这样我们就能够通过漏洞访问它。

此时,我们得到多个(5)线程,而不是只有一个线程处于阻塞状态。这会导致创建更多线程,并分配更多线程堆栈。通过执行此操作,如果内存中存在少量线程堆栈大小的空白,则应填充它们,并且阻塞线程中的至少一个线程堆栈应映射到低地址,而不在其之前映射到任何库。 mmap是在低地址之前映射高地址的区域,然后,理想情况下,如果我们使用大型共享内存,则应在此之前进行映射。

11.png

填充差距并映射共享内存后的MediaCasService内存映射

不过缺点是,有可能其他意想不到的内容(比如jemalloc heap)可能会被映射到其中,因此被阻塞的线程堆栈将不会是我们期望的。可能有多种方法可以解决这个问题。我决定简单地利用服务崩溃(使用漏洞来写入未映射的地址)再试一次,因为每次服务崩溃时它都会重新启动。无论如何,这种情况通常不会发生,即使发生了,一次重试通常就足够了。

一旦我们的共享内存在被阻塞的线程堆栈之前被映射,我们就可以使用该漏洞从线程堆栈中读取两种地址:

1.线程堆栈地址,使用pthread元数据,它位于堆栈本身之后的同一内存区域中。

2.libc映射到的地址,以便稍后使用libc中的gadget 框架和符号构建ROP链(libc具有足够的gadget 框架)。我们通过读取libc中特定位置的返回地址来实现这一点,libc位于线程堆栈中。

12.png

从线程堆栈读取的数据

至此,我们就可以使用漏洞读取和写入线程堆栈。由于我们既有确定性共享内存位置的地址,也有线程堆栈的地址,因此通过使用地址之间的差异,我们可以从共享内存(具有确定性位置的小内存)到达线程堆栈。

ROP链

我们可以完全访问我们可以恢复的被阻塞的线程堆栈,因此下一步是执行ROP链。由于我们要准确知道ROP链覆盖堆栈的哪个部分,因此必须时刻关注线程被阻塞的确切状态。覆盖部分堆栈后,我们可以恢复线程,从而执行ROP链。

遗憾的是,SELinux对此过程的限制使我们无法将此ROP链完全转换为任意代码来执行。没有execmem权限,因此无法将匿名内存映射为可执行文件,并且我们无法控制可以映射为可执行文件的文件类型。在本文的示例中,目标非常简单(运行单个ioctl),所以我只是编写了一个ROP链来执行此操作。从理论上讲,如果你想要执行更复杂的操作,那仍然可以利用这个原语。例如,如果你想根据函数的结果执行复杂的逻辑,你可以执行多阶段ROP:执行一个运行该函数的ROP链并将其结果写入某处,读取结果,执行复杂的逻辑,然后基于此运行另一个ROP链。

如上所述,由于目标是获得QSEOS版本,下面是ROP链执行的代码。

13.png

stack_addr是堆栈内存区域的地址,它只是一个我们知道的可写的地址,不会被覆盖(堆栈从底部开始,不靠近顶部),所以我们可以将结果写入该地址然后使用此漏洞读取它。在最后的休眠时,线程不会在运行ROP链后立即崩溃,所以我们可以读取结果。

构建ROP链本身非常简单, libc中有足够的gadget来执行它,所有的符号也都在libc中,且我们已经拥有了libc的地址。

完成漏洞利用后,我们就完成了劫持一个线程来执行ROP链,因此进程处于一个不稳定的状态。为了使所有内容都处于不被感染的状态,我们只是使用漏洞(通过写入未映射的地址)使服务崩溃,以便让它重新启动。

总结

正如我之前的文章所讲的那样,虽然谷歌宣称Project Treble有利于Android的安全性,但我们在本文中所找到的这个漏洞,就可以说明Project Treble并不是无懈可击的。这个漏洞本身就是Project Treble的一个组成部分,且它不存在于以前的源代码库中,仅仅出现在新库中。由于这个漏洞会出现在一个常用的库中,因此它影响了许多高权限服务。

GitHub上提供了完整的漏洞利用代码,注意:本文所讲的漏洞仅用于教育或防御目的,它不适用于任何恶意或攻击性用途。

漏洞发现的时间脉络

2018.5.3:发现漏洞;

2018.5.7:我们将漏洞详情及 PoC反馈给Google;

2018.7.2:Google发布了一组补丁

2018.7.13:谷歌要求我们推迟发布此文章;

2018.9.4:Google发布了一组额外的补丁

如何在Web服务器上配置HTTP标头,也是提高其安全性的重要一环。在本文中,我们将详细介绍每个标头所起的作用,以及攻击者可以利用哪些错误配置实施哪些攻击。

以下是我们本文将讨论的一些HTTP标头的类型(总共两大类):

防止攻击的服务器标头

1.HTTP严格安全传输(HTTP Strict Transport Security,通常简称为HSTS),它是一个安全功能,它告诉浏览器只能通过HTTPS访问当前资源,而不是HTTP。

2.网页安全政策(Content Security Policy,缩写 CSP),CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。它的实现和执行全部由浏览器完成,开发者只需提供配置。CSP大大增强了网页的安全性。攻击者即使发现了漏洞,也没法注入脚本,除非还控制了一台列入了白名单的可信主机。两种方法可以启用CSP,一种是通过 HTTP头信息的Content-Security-Policy的字段,另一种是通过网页的<meta>标签。

3.Access-Control-Allow-Origin,当两个域具有相同的协议(如http), 相同的端口(如80),相同的host(如www.google.com),那么我们就可以认为它们是相同的域(协议,域名,端口都必须相同)。跨域就指着协议,域名,端口不一致,出于安全考虑,跨域的资源之间是无法交互的。Access-Control-Allow-Origin是HTML5中定义的一种解决资源跨域的政策。他是通过服务器端返回带有Access-Control-Allow-Origin标识的Response header,用来解决资源的跨域权限问题。

4.X-FrameOptions,X-FrameOptions  HTTP响应头是用来确认是否浏览器可以在frame或iframe标签中渲染一个页面,网站可以使用此功能,来确保自己网站的内容没有被嵌到别人的网站中去,也从而避免了点击劫持 (clickjacking) 的攻击。

5.X-XSS-Protection ,HTTP X-XSS-Protection 响应头是Internet Explorer,Chrome和Safari的一个功能,当检测到跨站脚本攻击 (XSS)时,浏览器将停止加载页面。虽然这些保护在现代浏览器中基本上是不必要的,当网站实施一个强大的Content-Security-Policy来禁用内联的JavaScript ('unsafe-inline')时, 他们仍然可以为尚不支持CSP的旧版浏览器的用户提供保护。

6.X-Content-Type-Options,X-Content-Type-Options响应首部相当于一个提示标志,被服务器用来提示客户端一定要遵循在 Content-Type首部中对 MIME类型的设定,而不能对其进行修改。这就禁用了客户端的MIME类型嗅探行为,换句话说,也就是意味着网站管理员确定自己的设置没有问题。

泄漏信息的服务器标头

· Server标头

· X-Powered-By

· X-AspNet-Version

HTTP标头的背景知识

客户端和Web服务器使用HTTP标头作为HTTP协议的一部分来共享信息,当我们在浏览器的地址栏中输入URL或单击任何链接时,Web浏览器会发送包含客户端标头的HTTP请求,而HTTP响应就包含服务器标头。

以下是调用Google的web页面时的HTTP请求-响应:

1.png

其中有几十个HTTP标头,虽然本文的目的不是解释它们,但是,你可以在Mozilla的HTTP标头页面上找到每个标头的参考和详细信息。

我们只在本文中,讨论对安全性有影响的HTTP服务器头。

防止攻击的服务器标头

1.HTTP严格安全传输(HSTS)

HTTP严格安全传输性意味着浏览器仅通过HTTPS访问Web服务器。在服务器上配置完成后,服务器将响应中的标头作为Strict-Transport-Security发送。收到此标头后,浏览器将仅通过HTTPS将所有请求发送到该服务器。 HSTS标头有3个指令:

Max-age:这定义了仅通过HTTPS访问Web服务器的时间,此标头的默认值为31536000秒。这是HSTS有效的最长时间。服务器会在每次新响应时更新此时间,从而防止其过期。

2.png

IncludeSubDomains:这也适用于网站子域名的控制。

Preload:Preload list是硬编码到Google Chrome浏览器中的网站列表,只能通过HTTPS进行通信。网站的所有者可以提交其URL以将其包含在预加载列表中。此列表由Google维护,但其他浏览器也可以使用它。你可以在此处找到Preload list的完整信息。

攻击场景

如果未启用HSTS,攻击者可以执行中间人攻击并从用户的Web会话中窃取敏感信息。设想一个场景,受害者连接到一个开放的Wi-Fi,而这个Wi-Fi实际上是由攻击者控制的。通过HTTP访问网站将允许攻击者拦截请求并读取敏感信息。假如该站点使用的是HTTPS,但用户使用HTTP访问该站点,HTTP随后就会被重定向到HTTPS。如果同一用户早些时候访问过该网站,那么浏览器中记录的HSTS详细信息将导致自动通过HTTPS进行连接。

2.网页安全政策(Content Security Policy)

网页安全政策表示的是浏览器仅加载政策中定义的允许内容,这等于是使用白名单方法,告诉浏览器从哪里加载图像、脚本、CSS、小程序等。如果正确实施,此政策可防止利用跨站点脚本(XSS),ClickJacking和HTML注入攻击。

如果标头的名称是Content-Security-Policy,其值可以使用以下指令定义:default-src,script-src,media-src,img-src,它们会指定浏览器应该从何处加载这些类型的资源(脚本、媒体等)。

以下是一个示例设置:

Content-Security-Policy: default-src 'self'; media-src media123.com media321.com; script-src script.com; img-src *;

这被浏览器解释为:

default-src'self':从当前域加载所有内容

media-src media123.com media321.com:媒体只能从media1.com和media2.com加载

script-src script.com:脚本只能从script.com加载

img-src *:可以从Web中的任何位置加载图像

示例

为dropbox.com正确设置Content-Security-Policy标头:

4.png

没有为apple.com设置Content-Security-Policy标头:

5.png

有关网页安全政策的更多信息,请访问Mozilla网站

3.Access-Control-Allow-Origin

Access-Control-Allow-Origin是CORS(跨源资源共享)标头,此标头允许定义的第三方访问给定资源,它是对同源策略的限制的一个变通方法,该策略不允许两个不同的源读取彼此的数据。

例如,如果站点ABC想要访问站点XYZ的资源,那么站点XYZ将使用站点ABC的地址响应Access-Control-Allow-Origin标头。通过这种方式,站点XYZ告诉浏览器谁将被允许访问其内容。

Access-Control-Allow-Origin: SiteABC.com

攻击场景

如果Access-Control-Allow-Origin配置不当,攻击者可以使用其他第三方网站从目标网站读取数据。许多开发人员使用通配符访问Access-Control-Allow-Origin标头,这就允许任何网站从他们的网站读取数据。

4.Set-Cookie响应头

只有客户端才能设置Cookie,服务端若想让客户端增加一个Cookie项,需要在应答时,在Http头部中,通过使用Set-Cookie,将要设置的Cookie项发送给客户端。这样客户端,在下次访问时,会带上该Cookie项。

应用程序设置的cookie值由服务器在Set-Cookie标头中发送。在接收到此标头之后,浏览器将在Cookie标头中的每个HTTP请求中发送Cookie。

HTTP cookie通常包含许多敏感信息(尤其是会话cookie),需要对其进行保护以防止未经授权的访问。

可以设置以下属性来保护cookie:

Secure:使用此属性设置的cookie只会通过HTTPS发送,而不是通过明文HTTP协议发送(容易被窃听)。

HTTPOnly:浏览器将不允许JavaScript代码访问使用此属性设置的cookie的内容,这有助于缓解通过XSS攻击劫持会话的问题。

示例

为dropbox.com正确设置了Cookie属性HTTPOnly和Secure:

7.png

没有为boeing.com设置Cookie安全属性的示例:

8.png

5. X-FrameOptions

通过禁止浏览器在iframe元素中加载页面,此标头可用于保护用户不受ClickJacking攻击。X-FrameOptions包含3个指令:

X-Frame-Options: DENY——这个指令将不允许在任何网站的框架中加载页面:

9.png

X-Frame-Options: sameorigin ——这个指令将允许页面在一个框架中加载,前提是源框架是相同的,也就是说,在www.site.com上的一个页面在一个框架中加载,前提是该框架的父页面有相同的来源(www.site.com)。

10.png

X-Frame-Options: allow-from uri——框架只能显示在指定域/源(domain/origin)的框架中,那什么是源的呢?源其实是是个域名(domain),一般请求网页的那个url的域名就会被制定为源。

攻击场景

攻击者可以通过钓鱼的方式,让用户访问恶意网站,此时恶意网站会将目标应用程序加载到不可见的iframe中。当用户点击恶意应用程序(例如基于网络的游戏)时,就会产生所谓的Clickjacking攻击,此时,攻击者将在未经用户同意的情况下点击合法应用程序,这可能导致执行一些不需要的操作(例如删除帐户等)。

示例

正确实现X-Frame-Options标头以拒绝dropbox.com的框架加载:

11.png

在ibm.com上未实现X-Frame-Options标头:

12.png

6.X-XSS-Protection

此标头旨在防止跨站点脚本攻击,它适用于现代浏览器使用的XSS过滤器,目前包含3种模式:

X-XSS-Protection: 0 ——0代表的是禁用XSS过滤器;

X-XSS-Protection: 1——1代表将启用过滤器,如果检测到XSS攻击,浏览器将清理页面内容以阻止脚本执行。

X-XSS-Protection: 1; mode=block——如果检测到XSS攻击,则使用了块模式(block mode)的值(1)将阻止页面呈现。

示例

在linkedin.com上正确实现了X-XSS-Protection标头:

13.png

instagram.com上缺少X-XSS-Protection标头:

14.png

7.X-Content-Type-Options

此响应标头用于防止MIME嗅探漏洞。什么是MIME嗅探?IE从SP2开始进行了MIME嗅探的功能,MIME嗅探是Web浏览器的一项功能,用于检查所服务文件的内容。它的工作原理如下:

1.Web浏览器请求文件,服务器发送一个带有HTTP标头Content-Type集的文件。以前的浏览器都是通过Content-Type来判断Resoponse流是何种类型的内容,进而调用不用的处理程序进行处理,如text/html表明接受的html代码,需要做html页面渲染,text/jpeg表明接受的图片文件,需要对接受到的数据流调用处理jpeg格式流的处理程序。IE则在此基础上增加了对MIME的嗅探功能,不仅仅根据Content-Type来判断,而且会根据Response流的内容来进行判断。

2.Web浏览器“嗅探”此文件的内容以确定文件格式。

3.完成分析后,浏览器会将其结果与服务器发送的结果进行比较。如果不匹配,浏览器将使用已标识的格式。

这些过程里,就有可能导致安全的漏洞。

攻击场景

1.应用程序允许用户上传图像文件并验证其扩展名;

2.用户上传带有jpg或png扩展名的图像文件,但此文件也包含恶意HTML代码;

3.浏览器使用包含代码的HTML呈现文件并在浏览器中执行;

通过将标头X-Content-Type-Options设置为nosniff,浏览器将不再“嗅探”所接收文件的内容,而是使用Content-Type标头中的值,此标头专用于IE和Chrome浏览器。

此标头可以与另外两个标头一起使用,以增强安全性,它们是:

Content-Disposition:Content-Disposition是作为对下载文件的一个标识字段,它强制浏览器显示下载pentest.html文件的弹出窗口。

Content-Disposition: attachment; filename=pentest.html

X-Download-Options:当此标头设置为noopen时,用户被迫在打开之前首先在本地保存文件,而不是直接在浏览器中打开文件

示例

正确呈现了linkedin.com 的X-Content-Type-Options标头:

16.png

呈现了错误的instagram.com的X-Content-Type-Options标头:

17.png

泄漏信息的服务器标头

1.Server标头:

此标头包含有关后端服务器(类型和版本)的信息,例如,下面的屏幕截图显示运行Nike网页的Web服务器是Jetty,版本为9.4.8.v20171121。

18.png

如果攻击者能获取此信息,就会查找特定于Jetty 9.4.8版本的漏洞,此信息可在以下公共数据库中找到,例如:

https://nvd.nist.gov

https://cve.circl.lu

https://www.securityfocus.com/bid

你只需要在其中搜索特定的产品和版本既可,影响Jetty Web服务器的漏洞信息的详细介绍如下:

https://nvd.nist.gov/vuln/search/results?form_type=Basic&results_type=overview&query=jetty&search_type=all

示例

通过重新配置web服务器,可以屏蔽服务器信息。例如,在Linkedin的网站上有一个很好的配置示例(服务器名被修改为“Play”):

19.png

2.X-Powered-By:

包含Web应用程序中使用的Web框架或编程语言的详细信息。例如,https://msc.mercedes-benz.com上的Web应用程序是使用PHP 7.1.22构建的,并由Plesk托管。

20.png

3.X-AspNet-Version:

顾名思义,它会显示ASP .NET框架的版本细节。这些信息可以帮助攻击者根据框架及其版本调整攻击策略。

以下是来自http://demo.testfire.net服务器的标头示例:

21.png

总结

可以在服务器上配置HTTP标头,以增强Web应用程序的整体安全性。这些标头虽然不会使应用程序更安全,但它们会阻止攻击者利用应用程序的潜在漏洞。

近日,趋势科技根据所捕获的Smart Protection Network(SPN)数据和来自北美地区的Managed Detection and Response(MDR)的数据,发现老式攻击一直持续存在着,且生命力旺盛,比如垃圾邮件等传播方式依然强劲,而勒索软件攻击又焕发出新的活力,另外2018年第三季度的监测数据也显示,挖掘加密货币的恶意软件的新式攻击的数量也急剧增加。

然而,研究人员却发现,这些旧威胁一直持续存在着,且生命力旺盛,安防人员不要误解为幕后开发者或攻击者有满足于现状的迹象。事实上,这是他们在不断改进已被证明有效的工具和技术,以便在网络罪犯和安全提供商之间无休止的获取主动攻击权的征兆。

其中垃圾邮件是传播恶意软件的首选方法

1.jpg

2018年第三季度北美地区排名前15位的恶意软件

基于云安全智能防护网络(SPN)的监测数据,本季度北美地区排名前15位的恶意软件非常多元化。可以看到排名第一的是EMOTET恶意软件,其次是挖掘加密货币的恶意软件COINHIVE。木马POWLOAD和被称为AMCleaner的潜在不受欢迎的应用程序(potentially unwanted application ,PUA)分别排在第三和第四位。

利用欺诈性垃圾邮件实施钓鱼攻击,可以将许多攻击力很大的恶意软件的效用发挥大最大。另外,之所以钓鱼攻击很普遍,是因为它们很少需要复杂的工具才能进行攻击,而且它们之所以有效,是因为攻击者只需要了解人类的行为以及诱使毫无戒心的用户点击链接或下载恶意附件即可。

研究人员在第三季度发现的垃圾邮件攻击活动表明,攻击者已经在慢慢的改进钓鱼软件的传播方法。下面的三个示例显示了攻击者是如何以不同方式使用单个攻击向量。一种是典型的网络钓鱼尝试,所有的攻击元素都在这些类型的攻击中被发现;而另一种则使用仍然证明有效的旧恶意软件;最后一个示例涉及一种新的,巧妙的技术,利用电子邮件劫持和现有对话来攻击用户。

发生在加拿大的网络钓鱼活动

以发生在加拿大的网络钓鱼活动为例,看看攻击者是如何使用与税收相关的PDF文件作为诱饵的。与大多数网络钓鱼攻击一样,电子邮件是钓鱼攻击情形中使用的主要攻击入口。乍一看,该电子邮件来自似乎是合法的政府机构:“加拿大税务局(CRA)”,甚至还有一个PDF文档附件,文件名为CRA-ACCESS-INFO.pdf。此电子邮件包含一条伪造的虚假消息,通知收件人CRA已向他们发送了INTERAC电子转帐,可通过其中的说明转账或点击PDF中嵌入的链接来存入资金。

2.jpg

伪装成来自CRA的电子邮件的网络钓鱼攻击

如上图所示,PDF邮件正文包含一个“请存入资金”的标签,该标签链接到一个将受害者重定向到网络钓鱼页面的恶意URL。然后,网络钓鱼页面会检查受害者的有关IP地址的地理位置的信息。如果发现IP地址的地理位置与计划中的目标区域(比如本文中为北美)匹配,则会重定向到要求用户输入个人详细信息和财务凭据的页面,否则,它将重定向到YouTube。研究人员在北美地区看到的所有这类钓鱼攻击都有着非常一致的模式,所有攻击样本的电子邮件和附件都是相同的。

在电子邮件中找到的Interac公司是一个合法的加拿大借记卡公司,它将金融机构和其他企业联系起来,以便交换进行电子金融交易。Interac作为加拿大借记卡系统,具有广泛的可接受性,可靠性,安全性和效率。该组织是加拿大领先的支付品牌之一,平均每天使用它进行支付和兑换货币的次数达到1600万次,攻击者使用这样一个受大家信任的金融机构就增加了网络钓鱼邮件得“合法性”。

使用EMOTET有效载荷的垃圾邮件

EMOTET是随着时间的推移而发展的恶意软件的完美示例。

趋势科技的安全团队早在2014年首次发现EMOTET木马使用网络嗅探技术窃取数据,最初是一种银行木马,但在之后的几年里EMOTET表现得并不活跃且慢慢开始淡出人们的视线。

但在2017年8月份,趋势科技又发现了EMOTET,并详细介绍了EMOTET的四个完全不同类型的变种TSPY_EMOTET.AUSJLA、TSPY_EMOTET.SMD3、TSPY_EMOTET.AUSJKW、TSPY_EMOTET.AUSJKV,这些变种的攻击目标分别是美国、英国和加拿大。自2018年2月以来,Emotet一直在使用其加载程序功能来传播Quakbot系列恶意软件,该系列的行为模式类似于网络蠕虫。此外,Emotet还在传播Ransom.UmbreCrypt勒索软件和其他恶意软件(如DRIDEX)。Emotet还加强了其功能和策略,包括使用第三方开源组件。比如,Emotet在Google的原型程序上构建了一个通信协议,该协议使用Lempel-Ziv-Markov(LZMA)压缩,LZMA是一种用于执行无损数据压缩的链算法。

最近,研究人员又发现了大量的EMOTET垃圾邮件活动,使用各种社交工程方法来诱使用户下载和启动其恶意载荷,通常采用恶意MS Word或PDF文档的形式。

多态性和类蠕虫功能的结合使其能够快速传播到网络中,而无需任何其他用户交互。EMOTET的顽强生命力让任何专业的安全保护组织都感到棘手,特别是在考虑它可能对组织产生的影响时。除了信息窃取之外,EMOTET还可以对网络基础设施造成严重破坏并引发账户冻结,让企业蒙受金钱和声誉损失。

利用被劫持的电子邮件传播URSNIF

URSNIF是一种银行木马,会窃取敏感资料并在受影响的主机上收集数据,包括电子邮件凭证、证书、浏览器cookie和来自webinjects的财务信息。研究人员最近发现了一个新的攻击系列,该攻击系列利用被劫持的合法电子邮件来发送URSNIF。在今年9月监测到的恶意邮件活动却表明,攻击者正在采取更为复杂的网络钓鱼形式。该恶意活动会劫持电子邮件账户,并对邮箱中已有的邮件内容进行回复,在回复的内容中附带恶意软件。对已有邮件的回复,实际上是连续通信中的一部分,因此这种特殊的钓鱼方式难以被用户发现,也难以检测。通常,受害者都没有意识到他们正在遭受钓鱼邮件的威胁。这些攻击与今年早些时候Talos发现的URSNIF/GOZI恶意邮件活动非常相似,该恶意活动使用暗云僵尸网络中部分被劫持的计算机向已有邮件发送回信,很可能是URSNIF/GOZI恶意邮件活动的升级版本或演变版本。根据迄今为止收集到的数据,我们发现该恶意活动主要影响北美和欧洲地区,同时在亚洲和拉丁美洲地区也发现了类似的攻击。本次恶意活动的主要目标是教育、金融和能源行业。然而,此次恶意活动还影响到了其他行业,包括房地产、交通运输、制造业和政府。值得注意的是,恶意垃圾邮件是作为正在进行的对话的一部分发送的,这使得目标用户更难以检测到。此攻击系列与商业电子邮件攻击(BEC)有一些相似之处,但没有电汇欺诈。

勒索软件仍然生命力旺盛

3.jpg

2018年第三季度北美地区的勒索软件发展趋势

GandCrab勒索病毒是2018年所发现的最流行的一种病毒,它于2018年01月面世,短短几个月的时间,就迭代了3次。第一次是因为其C&C被安全公司控制而被大众所知,两个月后新版的GandCrab勒索病毒又出现,在这个版本中,开发者使用极具挑衅意味的C&C地址(C&C地址中包含针对警方和安全公司的字符内容)。而在今年的5月份, GandCrab又进行了第3次迭代,该版本结合了第一次版本与第二次版本的代码隐藏技术,更加隐蔽。第三版借助CVE-2017-8570漏洞进行传播,漏洞触发后会释放包含韩语“你好”字样的诱饵文档。与以往版本相比,该版本并没有直接指明赎金金额,而是要求用户使用Tor网络或者Jabber即时通讯软件与他们联系。

可以看出,它的加密和解密程序以及它在系统中的持久攻击性都得到了改进。勒索软件代码的更新和改进使其变得难以检测。GANDCRAB之所以能有效迭代,是因为它有各式各样的攻击入口,包括EMOTET钓鱼电子邮件、漏洞利用工具包,虚假应用程序和远程访问工具。

除了GANDCRAB,研究人员还在前五名中找到了其他熟悉的软件,包括BLOCKER,NEMUCOD,LOCKY和WCRY。与2018年第二季度相比,北美勒索软件的总体数量有所增加。

挖掘加密货币的恶意软件也日趋流行

4.jpg

2018年第三季度的挖掘加密货币的恶意软件,其中COINHIVE占了大部分

挖掘加密货币的恶意软件(cryptominer),已经成为2018年的最大威胁,在今年第一季度和第二季度这种攻击的趋势就有了明显增长,特别是在第三季度这种增长趋势更明显了,这是因为加密货币已被大众接受且其市场价值也在增加,这使其攻击价值进一步得到提升。

挖掘加密货币的恶意软件是将加密挖掘代码加载到受害者的计算机上,通常使用伪装的网络钓鱼电子邮件或将恶意代码注入网站和浏览器。一旦被感染,计算机就会大幅减速并出现性能问题,从而导致运行效率和硬件性能降低。

将勒索软件与挖掘加密货币的恶意软件进行比较

5.jpg

2018年勒索软件和挖掘加密货币的恶意软件之间的月度比较,请注意2018年8月勒索软件的开始大幅增长的趋势

在以前的文章中,研究人员曾讨论了勒索软件与其他威胁相比如何下降的问题,尤其是与挖掘加密货币的恶意软件和信息窃取程序相比。但奇怪的是,研究人员观察到2018年第三季度挖掘加密货币的恶意软件增速却下降了,而勒索软件再次出现大幅增长,特别是在8月份,它的政府竟然高于挖掘加密货币的恶意软件。

经过分析,这个趋势主要得益于某些勒索软件的变异使用,特别是GANDCRAB的变异再使用,这可以解释勒索软件在此期间的上升趋势。特别是Fallout漏洞利用工具包的使用,它提供了额外的传播方法,扩大了勒索软件的攻击范围。在2018年8月底,Fallout漏洞利用工具包首次被发现,它被安装在被黑客攻击的网站上,并试图利用访问者计算机上的漏洞,这些可被利用的漏洞是Adobe Flash Player(CVE-2018-4878)和Windows VBScript引擎(CVE-2018-8174),它被用于传播GandCrab勒索软件以及其他恶意软件,下载木马程序以及其他用户可能不需要的程序(PUP)。该工具包将首先尝试利用VBScript,如果禁用脚本,则会尝试利用Flash Player漏洞。

文件漏洞:EternalBlue和MS Office漏洞利用

严重的漏洞会给组织带来了无法计量的损失,它们不仅会让设备对隐蔽的攻击毫无防范能力,而且检测和更新设备的漏洞通常会分散有限的安全资源,并将IT管理员的注意力发生转移。

根据研究人员捕获的数据,2018年的前10个文件漏洞如下所示。

6.jpg

2018年检测到的最流行的10个漏洞

大多数漏洞(包括2018年观察到的一半以上)和CVE-2017-0147有关,该漏洞便是“永恒之蓝”漏洞,它是2017年泄露的NSA网络武器库中的一款攻击程序,其中利用了多个Windows SMB服务的零日漏洞。这是与EternalBlue漏洞相关的漏洞,并在WannaCry勒索软件出现期间成为最重要的被利用的漏洞。另外是两个相对较新的漏洞:潜伏17年之久的Office远程代码执行漏洞(CVE-2017-11882)以及CVE-2017-0199漏洞。这两个漏洞都是利用的MS Office产品,通常涉及垃圾邮件,其中CVE-2017-11882漏洞为Office内存破坏漏洞,影响目前流行的所有Office版本。

不出所料,由于CVE-2017-0147在各种Windows版本中滥用SMB漏洞,微软Windows成为最具针对性的应用程序,与第二和第三大流行漏洞也与Windows有关。

7.jpg

受漏洞影响最严重的行业,除了前六名,还包括材料、餐饮、电信和房地产等行业

根据研究人员的监测数据,2018年前三个季度受影响最大的行业是医疗保健、制造和技术开发行业。这个趋势在第一季度特别高,但从第二季度开始下降。虽然医疗保健在最初几个月的漏洞检测方面高居榜首,但在第二季度明显下降,并在第三季度略有回升。

虽然大多数漏洞都是过去四年发现的,但研究人员也可以观察到追溯到2003年的旧漏洞,可见及时升级漏洞是多么的重要。

缓解措施

为了实现最高级别的保护,企业组织及其安全团队必须始终主动保护其网络和终端,不仅要预防新的攻击威胁,还要保护使用改进攻击方法的老式攻击。

对于拥有较小安全团队且可能无法处理更高级威胁的企业而言,这可能是个难题。通常,一个企业的内部IT部门也是他们的安全团队,然而这意味着IT部门在日常任务完成之后,还要进行安防这样的额外工作,所以建议没有专业安全团队的公司使用外包安全服务。

越来越多的用户将服务转移到云服务中,这其中就包括许多大型企业。随着云端提供服务的基础设施越来越好、成熟度越来越高,许多大型企业已开始将核心业务功能转移给下一代IT托管和应用交付,“应用交付”实际上就是指应用交付网络(Application Delivery Networking,简称ADN),它利用相应的网络优化/加速设备,确保用户的业务应用能够快速、安全、可靠地交付给内部员工和外部服务群。不过这对信息安全具有重大影响。如果不加以控制,此举可能会给企业带来无法想象的安全灾难。

本文是思科安全团队进行的一次云端安全研究,重点在于如何改进他们的渗透测试技术来使用混合云解决方案,另外就是解决一些经常碰到混合云相关漏洞。

为什么要使用混合云

混合云(Hybrid Cloud)是近年来云计算的主要模式和发展方向。由于安全和控制原因,企业更愿意将数据存放在私有云中,但是同时又希望可以获得公有云的计算资源,在这种情况下混合云被越来越多的采用,它将公有云和私有云进行混合和匹配,以获得最佳的效果,这种个性化的解决方案,达到了既省钱又安全的目的。

云端托管的功能非常强大,仅举几例:

· 符合SOC2, PCI-DSS Level 1, HIPAA和ISO27001;

· 快速部署(快速部署(CloudFormation,Terraform);

· 降低成本;

· 增大了可扩展性;

对于信息控制、可扩展性、突发需求,以及故障转移需求来说,混合和匹配私有云和公有云是一件好事情。 最近几年,云计算的发展计划开始围绕整个架构支持方面,围绕混合云,或者是混合、匹配各种云计算模式来展开。有趣的是,并不是说私有云和公有云各自为政,而是私有云和公有云同时协调工作。目前,已经有很多企业都朝着这种集中云(Cloud-Bursting)的架构发展,同时这也是实现利益最大化的关键。

所有这些强大的因素叠加在一起,现在看来已经足够将一般的网站整个转移到云计算,而且还可以将核心系统进行转化。

安全方面有什么安全隐患?

当应用程序部署到云中时,在一个将云基础设施与部署的应用程序分开管理的组织中,开发人员或程序的运维人员通常无法看到底层操作系统的配置。

目前许多组织已经采用了“DevOps”方法和工具集来管理云IT基础设施。DevOps(Development和Operations的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。DevOps最有趣的地方莫过于它是一种思想上的"反模式"。一般我们认为,一个行业发展越成熟,它的工种划分会越细致。因此在软件业,开发者Dev和运维人员Ops自然而然的被分成两个独立的部门。而DevOps则反其道而行之,它鼓励开发者和运维人员坐在同一间办公室里,并对彼此充分了解。现在存在大量的DevOps工具:CloudFoundry,Docker Swarm或Kubernetes等,这些工具带来了极大的灵活性和快速操作性,但这些工具也被攻击者也广泛了解。

基本的安全前提

云端的每个节点的配置通常是根据相应的标准构建或基于所有可用节点使用的预先存在的配置来定义的。在某些情况下,这种节点的配置可能导致实际中的安全漏洞,其中应用程序组件依赖于未在标准的构建中实现的操作系统级安全控制。不过,云管理工具和内部网络服务的出现也增加了攻击面(本地环回接口,覆盖网络和内部云网络)。

如何进行渗透测试?

进行渗透测试的标准方法和手段是不断在更新的。传统上,渗透测试的评估系统是以IP地址、DNS或NetBIOS名称来命名的。在云环境中,瞬态主机(transient host)可能只存在几周,因此在发布测试报告时,已识别出的漏洞已移至其他的系统。

当然仍然需要漏洞扫描和应用层渗透测试,但是,如果要确定根本原因,必须确定负责的组件,无论是部署的应用程序、共享服务还是云管理工具。例如,在应用程序渗透测试期间, TestContext测试框架可以识别可访问公有云的Kubernetes API服务,该服务可以通过修改对应用程序的请求中的HTTP“主机”头来访问。Kubernetes API是集群系统中的重要组成部分,Kubernetes中各种资源(对象)的数据通过该API接口被提交到后端的持久化存储(etcd)中,Kubernetes集群中的各部件之间通过该API接口实现解耦合,同时Kubernetes集群中一个重要且便捷的管理工具kubectl也是通过访问该API接口实现其强大的管理功能的。

此特定漏洞利用已部署的反向代理中的漏洞,为了解决该问题,必须对部署脚本而不是应用程序代码库进行更改,以确保在未来的迭代中部署反向代理而不存在漏洞。这将要求负责管理云基础架构的人员与应用程序团队密切合作。

如果不考虑完整的渗透测试生命周期,那企业的云端则很容易受到攻击,包括传统的托管或应用交付中没有考虑到的威胁。

因此,全面的渗透测试计划不仅可以提供安全状况的时间点评估,还可以帮助解决以下问题:

1.对于我的云服务提供商,我到底能否100%信任。

2.如何保护我的代码和数据免受来自托管提供商、容器溢出(container breakout)或同一云环境的其他租户的攻击?

3.如果我的某个应用程序受到攻击,攻击者是否能够遍历云并访问云中的其他计算节点、应用程序、资源?

4.攻击者是否能够遍历我企业的内部基础设施?

对于涉及多个利益相关方和第三方而言,定义端到端渗透测试的范围可能很困难。 当网络隔离以及访问或自动化控制阻止对底层系统的实际访问时,就会迫使测试者使用诸如web shell之类的替代通信流来获得对组件的访问。

由于本文旨在强调对混合云和容器部署维护的渗透测试。因此在下文,研究人员将深入探讨企业网络和云之间连接的潜在漏洞。

混合云中的安全性:集成内部系统

上面讲述了环境混合云环境中托管可能出现的一些普遍问题,下文,研究人员将更深入的研究如何将内部系统与混合云集成。

根据混合云的定义,它可以连接组织的内部网络和一个或多个云提供商之间的通信通道。虽然每个云提供商都采用不同的方式提供管理访问,通常通过web管理控制台和API,但本文主要关注Amazon AWS。

对混合云进行渗透测试时要考虑的第一点便是它的网络系统:

1.如何连接企业环境和云环境,以允许企业内部服务和云托管服务之间的双向通信?

2.混合云对可用性和安全性有什么影响?

解决这些问题的通常的方法是用一个IPsec VPN隧道,在企业端有一个硬件VPN集中器,在AWS VPC(虚拟私有云)中有一个Amazon“虚拟私有网关”。然后,两端的IP地址范围都将被明确地用于路由,以便两端的系统不必知道用于发送和接收来自另一方的流量的VPN隧道。

一旦确定并理解了VPN配置,就可以以类似于普通VPN配置检查的方式检查两端的配置。一些企业可能会在VPN上添加另一层,以便在隧道的两边都有一个子网,这会使得两边主机之间的区别更加透明 (单纯的IP地址并不意味着主机所在的位置)。这有时被称为“底层和覆盖(underlay and overlay)”模型,其中每个主机需要一个客户机和一个配置文件来加入覆盖网络。这将为每个主机添加额外的网络接口,这可能会使事情变得复杂并导致漏洞,如果服务在两个接口上意外暴露,只应在一个接口上公开,或者防火墙规则仅针对其中一个接口实现。underlay是传统单层网络,是当前数据中心网络基础转发架构的网络,而overlay是一层逻辑网络,指通过控制协议对边缘的网络设备进行网络构建和扩展。总的来说,underlay网络与overlay网络相互独立而又相互联系。

公有云和私有云之间最安全的链接

除了VPN隧道外,企业可能还希望为混合云使用不同的网络路由。AWS Direct Connect就是一个例子,它允许流量通过专用的Amazon链接从企业的数据中心流向AWS,绕过公有云路由。这通常会减少网络跳数和网络延迟,因此主要是性能优化,但如果不允许数据流过公有云(但在AWS中允许),则可用于满足监管要求。

为了实现这一点,企业必须使用非Amazon数据中心作为其企业主机,而Amazon有直接连接链接。然后,在企业的路由器和亚马逊的路由器之间连接一条直接的光缆,每个设备通过BGP通告其相关的IP地址空间。应检查此BGP配置以确定企业内部网络的哪些部分正在向AWS进行通告,因为这将确定AWS云主机和服务可以访问的内部网络的范围。

如何在公有云中保护内部网络

必须仔细考虑VPN和Direct Connect选项的网络配置,因为它们为第三方云提供商(在本文中是Amazon和VPC中的服务)提供了到企业内部网络的直接链接,无论是虚拟的还是物理的。因此,企业的VPN集中器或直接连接路由器应被视为进入内部网络的入口点,除了路由通告外,还应安装适当的防火墙来控制传入和传出流量。

不应从企业网络(特定管理源除外)或Amazon VPC内访问管理服务,例如启用Direct Connect链接的交换机,路由器和防火墙的管理接口。如果VPC主机遭到攻击,攻击者可能能够访问这些管理服务,对直接连接链路执行中间人攻击或拒绝服务攻击,从而允许他们拦截或阻止双方的所有流量。

来自互联网(公有云)的攻击

许多使用混合云模型的企业正在考虑将公有云作为其私有内部网络的扩展,但同时又不使用它的任何面向互联网的公共组件,例如使用私有云计算资源的同时,不涉及到公有云。但是,由于公共云提供商必须连接到互联网,以支持其他需要面向互联网服务的用户,因此在配置时应该需要小心。VPC不应具有直接入站或出站的互联网访问(例如通过互联网网关),并且EC2实例不应附加公共IP地址。Amazon EC2提供不同的实例类型,以便您可以选择需要的CPU、内存、存储和网络容量来运行您的应用程序。有关更多信息,请参阅实例类型。然而,通过在公有云和企业内部网络之间进行的双向通信,云资源可能会绕过这一限制,通过VPN隧道使用企业端的网关或web代理访问互联网。如果不需要,则应注意限制云资源可访问的企业系统权限。

在不允许互联网接入的云设置中,还需要考虑其他用于渗透和过滤数据的渠道。云DNS设置可能允许DNS隧道,或者如果云DNS请求通过VPN隧道转发到企业DNS服务器,则可以使用企业DNS服务器进行DNS隧道连接。

S3 bucket

目前任何AWS环境都可能会使用S3bucket,它们可以用于存储与应用程序相关的静态内容,或者作为云部署的一部分来存储配置文件、映像和日志。与EC2实例不同,S3 bucket本身可以被外部访问。必须设置限制性的IAM策略,以确保内容不会无意中在公有网上被共享。近年来发生了许多令人震惊的攻击,攻击者利用S3 IAM的弱策略来访问客户数据。在混合云中,如果存储在存储桶中的内容被企业导入并信任,攻击还可能导致企业网络的整体瘫痪。其他类似的非VPC服务包括RDS和公共AMI。依靠第三方AMI构成企业EC2实例的基础,成了另一个必须进行安全评估的威胁向量。

证书

管理AWS资源的入口点的是web控制台,如果不能正确保护web控制台或API凭证和权限,攻击者就可能获得AWS帐户内所有资源和数据的控制权,包括设置进一步访问权限,如果是这样,则最初受损的凭据就会被更改并且权限被锁定。这些凭证和权限如果没有得到适当的审查和删除,则离职员工就可以在离开企业后通过互联网对内部服务的命令和控制进行维护。

共享租赁

最后,默认情况下,使用共享的公有云,则意味要与供应商里的其他客户共享此云端资源。但对于许多企业来说,这是不可取的,但并不是每个企业的云端管理者都知道这是默认配置。他们会误认为拥有自己的VPC,则意味着不会与其他客户共享硬件。这种错误的认知,会让攻击者通过虚拟机监控程序或支持云的虚拟机之间共享的硬件发起攻击,通过共享CPU缓存(Meltdown和Spectre)发起的攻击已被证明是行之有效的了。虽然这些漏洞已经得到了大范围的修补,但鉴于现代cpu提供的功能范围越来越广,存在进一步的漏洞是很有可能的。为了缓解这种未知的风险,可以使用专用的EC2实例,这些实例不与其他AWS客户共享一个虚拟机监控程序,但这需要明确配置,以及额外成本。

即使考虑到以上所有这些威胁,云提供商本身仍然拥有对资源的最终控制权。客户需要意识到这一点,并采取尽可能多的预防措施,以防止云提供商的恶意员工访问自己的数据。这包括尽可能使用加密,特别是对于数据存储(如Amazon EBS块存储和snapshots)和S3 BUCKET。