Android应用程序中的漏洞是如何演变的

 

Android应用程序的历史经历了几个值得注意的阶段。有本地运行的小程序、客户端-服务器应用程序、应用程序生态系统,以及最后的超级应用程序。这些阶段中的每一个都提高了复杂度,产生了新的漏洞,并使开发者越来越关注应用程序本身和它们所访问的数据的安全。操作系统本身也在不断发展。它给了开发者更多的选择和安全机制。

这篇文章是关于移动应用程序的漏洞是如何演变的,是什么影响了它们,哪些漏洞在今天是相关的,以及未来会发生什么。

安卓应用的主要漏洞

移动应用中的漏洞有相当多的类型,但其中有一些概括性的类型,涵盖了基本情况。最受欢迎的漏洞与用户数据和应用程序数据的不安全存储有关。开发者甚至不需要为它们做任何事情--只要以未加密的形式存储敏感信息就可以了。一些开发者考虑到安全问题,将这些数据存储在应用程序的内部目录中,即所谓的沙盒。但在某些情况下,这是不足够的。

例如,当一个用户的设备被允许以root身份执行命令时。这种能力通常不包括在标准的操作系统中,但高级用户会自行添加:为了使用特定的应用程序或改善操作系统的用户体验。此外,以下情况是可能的:一个有条件的合法应用程序要求提升权限以执行其主要功能,并在得到这些权限后,开始做一些用户不期望它做的事情。例如,从其他应用程序的沙盒中复制数据。

另一个例子是存在漏洞,允许从另一个应用程序读取沙盒内容。在这种情况下,恶意的应用程序不需要提升权限。它将利用这一漏洞,获得目标应用程序内部目录中未加密的数据。这就是为什么需要对数据进行加密。幸运的是,这一点现在非常容易做到,人们不需要成为密码学专家。只要使用供应商的解决方案,并遵循官方文件中描述的做法。

另一个同样有趣的漏洞类型是缺乏可执行的完整性控制和修改保护。在这里,开发者也不需要做任何事情,因此,也不会有任何保护。这使得攻击者可以修改源程序并伪装成原始程序发布。看来,谁会想下载一个非原创的应用程序呢?事实上,很多人都这样做。除了削减广告和付费功能的控制机制等琐碎的需求外,用户可能需要在具有修改过的固件的设备上运行应用程序。这样的固件往往具有作为超级用户执行命令的能力,而含有适当安全机制的银行应用程序拒绝在这种设备上工作。因此,有必要从银行应用程序中删除所有这些检查,以使其能够在这种固件上工作。这种活动通常是由爱好者为了体育兴趣而做的。但攻击者也可以这样做,然后不仅银行应用程序中的检查会消失,而且会出现一个窃取账户登录数据的代码。

防御这种修改是很困难的,通常需要额外购买专门的打包工具,这些工具使逆向工程复杂化,并使攻击者 "浪费"大量的时间来研究安全机制。你可以尝试自己编写所需的安全机制,但这需要高水平的专业知识,超出了一般移动应用开发者的能力范围。

我们还应该提到与网络有关的漏洞。许多开发者只停留在使用安全的HTTPS协议上,没有附加任何额外的保护措施。在某些情况下,这允许控制通信渠道的攻击者对应用程序进行MITM攻击并获得敏感信息。这种攻击的一个基本场景是这样的:当连接到一个不受信任的Wi-Fi网络时,用户会看到一个假的俘虏式门户,并被提示在设备上安装一个SSL证书。然后,攻击者可以拦截用户的智能手机产生的所有流量。为了防御这种攻击,通常会采用一种证书锁定技术。事实上,这是在移动应用程序中硬编码的合法服务器的证书或证书链。这种保护还有其他变化,但所有这些都是为了防止与另一个服务器的数据交换。

此外,Android,特别是早期版本(4.1.1及以下),非常容易出现与进程间通信和不适当使用操作系统和框架功能有关的漏洞。长期以来,关于这些功能的文档还有待改进,有些部分根本就没有文档。再加上缺乏明确的指导方针和最佳实践描述,这就迫使开发者编写特殊的代码,经常重新发明操作系统中已有的机制。

一个非常突出的例子是android:exported标志,它控制一个应用程序组件的可用性,供其他应用程序调用。确切地说,在安卓4.1.1及以下版本中,这个标志默认设置为 "true",这意味着所有没有被开发者设置的组件显然都可以被其他应用程序调用。这可能会导致绕过认证机制,如PIN屏幕,或通过直接与组件通信来利用其他漏洞,而这些组件被开发者设计为内部的,无法从外部进入。这就是安卓应用背后的概念。它们不应该有一个强制性的进入点,可以有几个这样的点。因此,减少外部组件的数量是非常重要的,而在剩下的组件中,要严格控制与 "外部世界 "的任何通信。

另一种类型的漏洞可以被定义为在代码中存储技术服务的各种API访问密钥。例如,分析和错误收集系统,云数据库和其他外部服务。通常这些服务提供不同类型的访问密钥,因为它们的开发者明白它们将在一个不受信任的环境中使用。但是,应用程序开发人员,由于各种原因,仍然在代码中留下具有 "多余 "权限的密钥。这类密钥的泄露风险取决于具体的情况,但是,例如,获得Firebase Cloud Messaging 服务的服务器密钥,可以让攻击者向该应用程序的所有注册用户发送任意的推送信息。

漏洞的濒危物种

操作系统在不断发展 - 漏洞也在不断发展。有些漏洞完全消失了,而对其他漏洞的利用变得更加困难,但仍有可能。另外,随着新的操作系统机制的出现,新的漏洞也会出现,或者旧的漏洞会重生,并通过这些机制的实现中的缺陷而再次运作。CVE-2020-0188就是这样一个漏洞。它允许从标准设置应用程序的内部目录中读取文件,该应用程序使用Android 11中引入的Slices机制。

至于消失的漏洞类型,在应用程序中越来越少,值得再次提及的是通过直接调用主屏幕绕过PIN屏。为什么这成为可能?

有几个因素:

1. 在某些时候,Google 改变了android:exported标志的默认值,所有的组件在默认情况下对其他应用程序都是不可用的,除非开发者明确设置了这个标志。后来,它把这个标志变成了强制性的。

2. 官方文档中出现了关于应用程序安全的章节,描述了正确使用这种重要机制的做法。

3. 应用程序开发中单一活动架构的普及。

这个架构值得多说几句,因为它的影响不仅仅是这个漏洞。我们在上面提到,Android应用程序通常没有单一的入口点,可以通过几种不同的方式触发。这是因为一个应用程序可以有多个 "屏幕"(用框架术语说是活动),如果这样的屏幕被导出,它可以独立于其他屏幕运行。一个单一的活动架构正是决定了拒绝多个活动而支持一个屏幕,所有其他的屏幕(片段,在框架术语中)都在其中生存。除了纯粹的技术上的便利外,这还减少了进入应用程序的入口数量,并允许在一个点上组织输入控制,而不是在每个单独的屏幕上。伴随着这样一个架构的其他架构原则也减少了所使用的Android组件的数量。所以,开发者通常不需要像以前那样需要实现额外的服务、广播接收器和内容提供者。然而,对于不同的特定任务,他们仍然需要,有时根本离不开他们。在这些情况下,供应商对特定组件的安全最佳实践的文件有帮助。而且,随着时间的推移,操作系统本身也越来越不能容忍各种滥用。

不太琐碎的濒危漏洞的例子包括不安全的广播信息处理。我们已经三年没有在客户的应用程序中遇到这种漏洞了。大多数情况下,这是由于应用程序不需要处理任何特定类型的消息。他们所拥有的都是标准的机制,这些机制通常来自于标准库,并且在大多数情况下都能正常工作,不会出现错误。同样的命运降临在与推送通知欺骗有关的漏洞上。开发人员只剩下根据文档创建的标准机制,而供应商方面则只剩下处理推送通知的API访问密钥的受限权利。

另外,开发人员终于意识到,任何进入应用程序的东西都可能被攻击者利用,他们几乎不再在发布版本中留下调试功能。

目前的漏洞类型

尽管Google和安全社区做出了最大的努力,但应用程序中的漏洞仍在不断被发现。除了上面已经描述过的漏洞(这些漏洞可以被传统地称为 "简单",因为它们似乎是独立存在的),"复杂 "的漏洞现在也变得越来越普遍。这些不再是漏洞本身,而是将多个漏洞和/或安卓应用和框架的功能连在一起的全面攻击。这有几个原因。除了提高平台本身的安全性外,应用程序的复杂性也在增加,从外部进入的数据往往要经过相当长的转换链。这可能会导致在链中的某个点上被利用,仅仅是因为开发者改变了数据以适应他们的需要,使得漏洞无法被利用。他可能根本就没有考虑过安全问题。

一个很好的例子是攻击一个应用程序中OAuth的不安全实现。开发人员已经学会了在不被信任的环境中使用PCKE扩展,但由于实现的复杂性,错误仍然发生。该协议涉及三方:移动应用、移动应用服务器和OAuth提供商服务器,这三个地方都可能出错。例如,如果OAuth提供商的服务器错误地检查了redirect_url(将用户重定向到移动应用的参数),攻击者就可以用自己的值代替,并拦截从移动应用服务器获得授权令牌所需的代码。或者移动应用程序可能对发送到OAuth提供商服务器的数据没有足够的控制,在这种情况下,攻击者可以切入并强迫用户在假网站上输入他们的详细信息。攻击这种实现方式有很多选择,而且有些情况相当复杂。从我今年在bugbounty项目中遇到的情况来看:涉及与三方互动的十步攻击,最终导致完全接管用户在目标服务上的账户,以及通过操纵认证时要求的数据列表,从OAuth提供商那里获得额外的用户信息。

应用程序的复杂性不断增加,也导致了与此类应用程序的生态系统有关的漏洞。当你把数据传输到另一个团队编写的应用程序时,为什么要仔细检查,而且肯定知道那里一切正常?问题是,这个应用程序可能是错误的--出于各种原因。例如,一个恶意的应用程序与一个合法的应用程序有相同的标识符,例如com.news.app。如果该生态系统中的另一个应用程序没有做进一步的检查,而只是依赖于系统中该标识符的存在,并向其发送一些敏感数据,我们就面临着一个生态系统的漏洞。这也是反过来的。从受信任的应用程序接收数据而不进行额外的检查,会给用户带来致命的后果。从我个人的例子来看:一个应用程序检查系统中是否存在某个标识符,如果发现它,就要求进行配置。这允许在第一个应用程序上设置调试标志,并迫使它将用户数据保存在一个所有应用程序都可以访问的地方。

与本地认证有关的漏洞仍然相关:PIN、生物识别、第二因素。这些保护措施可以被绕过,原因是实施中的错误或由于开发人员对框架中的概念缺乏了解。在基于PIN的本地登录实现的情况下,开发者有时会忘记保存登录的尝试次数。在这种情况下,只需重新启动应用程序,就可以重置尝试次数。这种情况比最初想象的更常见。在一个稍微复杂的变体中,系统时间转换,也可以被应用程序逻辑检测得很差,这有助于;它重置了登录尝试次数。生物识别绕过稍微复杂一些,但仍然有可能,如果应用程序显示一个生物识别对话框,只是为了验证提交的数据。在某些条件下,有可能隐藏这样的窗口并进入应用程序。这是可能的,因为展示生物识别技术并不涉及对应用程序数据的任何加密操作,而且取消对话框并不影响任何内部认证过程。而绕过第二个认证因素的能力在很大程度上取决于应用程序的逻辑。最近的一个例子是TikTok绕过了第二个因素,因为当在某个序列中进行了几次错误的登录尝试时,服务器上会出现随机超时。

事情的发展方向

Android 系统不会停滞不前,其安全机制也在不断改进。但并不是所有的问题都能在技术上得到解决,有时不得不通过 "行政手段 "来解决。例如,从Android14开始,针对Android SDK版本低于23(Android 6.0)的应用程序无法安装。问题是,攻击者故意低估了恶意应用程序的SDK版本,以便通过向后兼容机制利用系统的众所周知的缺陷。

应用程序也在发生变化。越来越多的跨平台应用程序出现了,同时为多个操作系统开发应用程序的过程也变得更加容易。但是,任何事情都是有代价的,跨平台的应用程序,除了平台特有的bug之外,还增加了自己的特殊行为,这些行为也可以被攻击者利用。另一个问题是,开发此类应用程序的工具和库远非完美,如果有的话。这就是为什么开发人员必须自己实现一些功能,这也充满了错误,特别是在实现加密操作或一些协议时。

这类应用程序的开发总是在某个抽象层进行的,此时具体平台的机制对开发者来说是隐藏的。当然,如果需要的话,他可以接触到这些机制并直接与之互动。但另一个问题来了:一个好的 Android 应用开发者不太可能对iOS平台的安全机制有深刻的理解。相反的情况也是如此。所有这些事实加上在安全的跨平台应用开发中缺乏有据可查的最佳实践,导致了相当简单和明显的漏洞。例如,在一个这样的跨平台应用程序中,我设法找到了几个根本就不应该存在的外部系统的API访问密钥。如果使用原生方法开发的话,他们根本不可能像这样进入应用程序。

这些工具不成熟的一个例子是支持React Native应用程序的Hermes格式。这是一种二进制格式,包含应用逻辑的最终JavaScript代码被转换为这种格式。由于缺乏良好的工具来反编译这种格式,使得探索移动应用变得非常困难。但是对这种格式的支持只在安卓应用中存在过一段时间,标准的技巧是,如果Android 版本突然用Hermes编译,那么从iOS应用中获得所产生的JavaScript代码,这种技巧至今仍然有效。

新的操作系统功能出现了,其中的漏洞被发现了,这些漏洞被关闭了,但绕过防御的方法被发现了。这一切就像一个不断进化的生物体。我只描述了正在发生的事情的一小部分,以说明安卓应用中的漏洞是如何发展的,以及它们对操作系统的演变产生了什么影响。

应用程序开发人员最好密切关注安卓系统中出现的新安全机制,并尽快开始实施,以保护用户。反过来,用户需要批判性地看待他们设备中发生的事情,并记住,如果你有一秒钟认为有问题,那就真的有问题了。这都是一个非常多维的故事,所以作为移动应用安全分析师,我们能做的最好的事情就是不断寻找移动应用和操作系统中的漏洞,改进保护它们的方法,并教育开发者使这部分世界变得更安全一些。

猜你喜欢

转载自blog.csdn.net/ptsecurity/article/details/131406469
今日推荐