-
-
[讨论]浅谈Strandhogg v1.0漏洞修复和防御检测
-
发表于: 2024-12-31 14:59 1293
-
前言:
因为工作原因,最近注意到了 Strandhogg 漏洞,虽然这个漏洞自2019年以来就已存在,且安卓11开始就不再受到此漏洞的影响,但它依然在国内安卓漏洞统计中占据着显著的位置。根据2024年10月的数据,Android漏洞总数约为7.9万,其中 StrandHogg 漏洞占比高达约95%(数据来源:爱加密)。尽管CNVD漏洞库目前已将 Strandhogg v1.0 视为非漏洞类事件,但由于行业合规检查等各类需求,修复这一漏洞仍然是很多公司的不得不做的工作。目前,网络上关于 Strandhogg 的文章主要集中在原理分析和漏洞复现,而对于如何修复和防御的详细介绍却相对较少,本篇文章希望能给大家提供一些帮助。
两种修复方法:
目前主流的修复方法主要有两种:一是将 taskAffinity 属性设为空,二是调整活动的 launchMode 。
首先,关于将 taskAffinity 属性设为空,需要注意的是, taskAffinity 设置为“.”等同于设置为“默认包名”。如果选择清空这一属性,那么相关的设置也应当一并删除。
其次,关于修改 launchMode ,有文章说将 launchMode 值设为 singleTask和singleInstance 都能有效,但我在pixel 1代安卓10系统上面,经过反复测试发现只有singleInstance才有效,其他三个选项均不可行。而singleInstance启动模式意味着如果当前存在该活动的实例,它将始终是其专属任务中的唯一活动。
例如,假设我的应用程序当前有一个包含两个活动的任务:
现在,我声明了一个活动C,并将其配置为singleInstance启动模式。如果启动这个活动C,此应用程序将有两个任务:
如果活动 C 启动另一个活动 D,它将出现在任务 1 的顶部:
如果所有导出的活动都声明为 singleInstance,那么 StrandHogg 确实无法在顶部插入恶意活动。不过官方文档指出,这种模式不适用于大多数应用程序。在这个例子中,如果用户当前在任务1并弹出活动 D,我们将看到的是活动 B 而不是活动 C。因此, singleInstance 模式并不适用于所有的业务场景。
某些应用限于业务需要,不希望修改上面两个配置,那下面介绍一种基于维尔茨堡大学的研究人员撰写的一篇论文,标题为《RIP StrandHogg: A Practical Detection Method on Android》的Strandhogg的检测方法。
一种检测方法:
下面的内容来自Protecting Against StrandHogg,欢迎大家查看原文
保护机制
1.最小化活动启动:
通过使用 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 标志并在 onCreate() 方法中调用 moveTaskToBack(true) ,以此来启动一个用户察觉不到的最小化活动。Android 随后会将该活动所属的任务移动到后台。由于指定了该标志,Android 也会销毁该活动,但保留对它的引用。
2.任务恢复:
当应用程序随后启动时,Android 将恢复已存在的任务,并将其移动到前台。随后再次调用已存在的最小化活动的 onCreate() 方法。这种行为不仅适用于用户启动应用程序时,也适用于任一 StrandHogg 变种启动应用程序时。
3.前台行为:
如果用户将应用程序移动到后台,然后稍后再次将其移到前台,Android 不会调用最小化活动的 onCreate() 方法。因此,我们在应用程序中有两个地方需要尝试进行StrandHogg检测:
最小化活动的 onCreate() 方法以覆盖用户之前未启动应用的情况。
作为前台服务的一部分以覆盖用户之前启动了应用但随后将其移到后台的情况。
架构
下图展示了构成应用程序的所有组件及其交互方式:
这个应用程序由以下活动组成:
1 2 3 | MinimizedActivity:应用程序的入口点。这个活动只是一个空白屏幕。 MainActivity:用户看到的第一个有意义的内容。 SecondActivity、ThirdActivity 和 FourthActivity:当用户按下“ Next screen”按钮时导航到的活动。 |
当用户启动应用程序时,MinimizedActivity 会立即启动 MainActivity 并随后关闭自己。
应用程序包括一个 MyBootReceiver,它接收 BOOT_COMPLETED 动作。这意味着它在设备完全启动后运行。它只是启动 MinimizedActivity 并立即将其移到后台。
应用程序还有一个 RestartMinimizedActivityService。如果应用程序被关闭,这个服务会再次启动 MinimizedActivity 并将其移到后台。
通过这个receiver和service来确保在用户尚未启动应用程序时或在用户关闭应用程序后,系统中会保留一个 MinimizedActivity 引用。
最后,应用程序包含一个 ForegroundDetectionService。每当 MainActivity 停止时,我们就启动 ForegroundDetectionService。每当恢复 MainActivity 时,我们就停止ForegroundDetectionService。该service可以每两秒执行一次检测程序。
攻击检测过程
我们首先使用 ActivityManager::getRunningTasks() 检索所有为此应用程序运行的任务。然后检查每个任务的 numActivities 值。这个数字绝不能大于通过常规使用应用程序合法创建的活动数量,否则就强制结束该应用程序的所有任务。这时,RestartMinimizedActivityService 将立即启动一个新的 MinimizedActivity 。
当应用程序完全初始化并达到初始屏幕时,允许的 numActivities 是 1。每当你导航到下一个活动时,允许的限制增加 1,导航回上一个活动时,允许的限制减少 1。
PS:具体使用时KENENG 会遇到一些细节上的问题,比如:
1.应用启动时的重复实例问题。当用户最初启动应用时,Android 可能会为应用创建包含两个可启动活动实例的任务。因此,当我们检测到基础活动和顶部活动都是 MinimizedActivity 实例时,我们将允许的 numActivities 设置为 2 而不是 1。否则,合法的应用启动会被误认为是 StrandHogg 攻击,用户点击图标后应用会立即崩溃。
2.从 Android 9 开始,如果为应用创建的任务没有 MinimizedActivity 作为其根活动,Android 将丢弃已存在的包含MinimizedActivity 引用的任务。这就意味着当 StrandHogg 攻击它时,MinimizedActivity 的 onCreate() 不会被调用。这使得应用容易受到 StrandHogg v1 的攻击,如果 v2 攻击应用针对的是一个不同于 MinimizedActivity 且 android:exported 设置为 true 的活动,也容易受到 StrandHogg v2 的攻击。
我们可以通过让MinimizedActivity 在其 onDestroy() 中设置排除最近任务标志并启动其自身的新实例来解决这个问题。