什么是意图
Intent(意图)主要是用于激活组件和解决Android应用的各项组件之间的通讯。
意图有分为显式意图和隐式意图。
意图的使用
显式意图使用代码,贴出主要显示意图跳转的代码。
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClicked(View view){
Intent intent = new Intent(this, SecondActivity.class);
//intent.setClassName(this,"cn.pc.activity.SecondActivity"); //非初始化显示调用
//intent.setClassName("cn.pc.activit.FirstActivity","cn.pc.activity.SecondActivity")
startActivity(intent);
}
}
隐式意图
隐式调用代码,隐式意图的调用
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClicked(View view){
Intent intent = new Intent();
intent.setAction("com.pc.testintent.SecondActivity");
intent.addCategory("android.intent.category.DEFAULT");
startActivity(intent);
}
}
意图使用中的风险
0x01 Intent敏感数据泄露风险
首先解释设置了Intent.FLAG_ACTIVITY_NEW_TASK的应用的调用过程。下面这段话比较详细的解释了这个参数工作的过程。参考链接http://www.cnblogs.com/xiaoQLu/archive/2012/07/17/2595294.html
FLAG_ACTIVITY_NEW_TASK: 设置此状态,记住以下原则,首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈(即taskAffinity,注意同一个应用程序中的activity的亲和性一样,所以下面的a情况会在同一个栈中,前面这句话有点拗口,请多读几遍),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的activity
a. 前提: Activity A和Activity B在同一个应用中
操作: Activity A启动开僻Task堆栈(堆栈状态: A), 在Activity A中启动Activity B, 启动Activity B的Intent的Flag设FLAG_ACTIVITY_NEW_TASK, Activity B被压入Activity A所在堆栈(堆栈状态: AB)
原因: 默认情况下同一个应用中的所有Activity拥有相同的关系(taskAffinity).
b. 前提: Activity A在名称为"TaskOne应用"的应用中, Activity C和Activity D在名称为"TaskTwo应用"的应用中.
操作1: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),在Activity A中启动Activity C, 启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK, Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 长按Home键, 选择TaskA,Activity A回到前台, 再次启动Activity C(两种情况1.从桌面启动;2.从Activity A启动,两种情况一样), 这时TaskB回到前台, Activity C显示, 供用户使用, 即:包含FLAG_ACTIVITY_NEW_TASK的Intent启动Activity的Task正在运行, 则不会为该Activity创建新的Task,而是将原有的Task返回到前台显示.
操作2: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),在Activity A中启动Activity C,启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK, Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 在Activity C中启动Activity D(TaskB的状态:CD) 长按Home键, 选择TaskA, Activity A回到前台, 再次启动Activity C(从桌面或者ActivityA启动,也是一样的),这时TaskB回到前台, Activity D显示,供用户使用.说明了在此种情况下设置FLAG_ACTIVITY_NEW_TASK后,会先查找是不是有Activity C存在的栈,根据亲和性(taskAffinity),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的顺序不变。
故利用FLAG_ACTIVITY_NEW_TASK启动意图并传递数据时,会先查找有当前activity存在的栈,如果存在,则会调用这个存在的栈。在这个过程中如果是两个不同的Activity,就会导致最后启动的activity中的intent内容被劫持。
漏洞代码
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
漏洞修复
避免使用包含FLAG_ACTIVITY_NEW_TASK标志的Intent启动Activity
0x02 app存在隐式意图调用
隐式意图调用可能存在数据泄露,拒绝服务,钓鱼攻击等风险。数据泄露和拒绝服务其实我们已经分析过了。接下来我们分析下钓鱼风险。
意图过滤器intent-filter
IntentFilter实际上相当于Intent的过滤器,一个应用程序开发完成后,需要告诉Android系统自己能够处理哪些隐形的Intent请求,这就需要声明IntentFilter。IntentFilter过滤Intent时,一般是通过Action、Data及Category三方面进行监测。
钓鱼风险
移动应用app使用隐式意图,可以被恶意应用通过一个高优先级的intent-filter拦截。
一个恶意app就可以使用同样的intent-filter拦截该意图然后启动钓鱼界面从而诱骗用户输入账号和密码。
安全建议
1.尽量用显示意图的方式调用activity传递敏感信息。
2.在与其它app通信之前,开发者应该检测其它app的签名以证明其调用来源的合法。
0x03 Intent Scheme URL漏洞
基本组成语法
其实intent Scheme URL和利用intent代码启动组件的道理相同。
intent:HOST/URI-path#Intent:package=[string];action=[string];category=[string];component[string];scheme=[string];end;
处理intent scheme url的过程
如果浏览器支持Intent Scheme URI语法,一般会分三个步骤进行处理:
1.利用Intent.parseUri解析uri,获取原始的intent对象;
2.对intent对象设置过滤规则,不同的浏览器有不同的策略,后面会详细介绍;
3.通过Context.startActivityIfNeeded或者Context.startActivity发送intent;
例子
intent:mydata;action=com.myaction;S.url=file:///mnt/sdcard/download/xss.html;SEL;component=com.ex.uritest/com.ex.uritext.Main
Activity;end;
两个启动机制
1. 在intent-filter中定义了category的属性为android.intent.category.BROWSABLE表明这个组件才能利用浏览器启动组件。
2. android 4.0.3引入了Selector intent机制,如果为一个组件设置了一个selector intent,那么android framework就会解析这个
selector intent,即使这个组件没有设置android.intent.category.BROWSABLE这个属性。相当于这个selector intent在没有匹配成功的条件下,默认使用selector intent。
漏洞检测和利用
手机qq浏览器的例子,根据响应的app意图构造响应的测试用例
qq远程拒绝服务
intent:#Intent;component=com.tencent.mtt/com.tencent.mtt.debug.DbgMemWatch;end
重置PIN码,相当于越权
intent:#Intent;action=android.settings.SETTINGS;S.:android:show_fragment=com.android.settings.ChooseLockPassword$ChooseLockPasswordFragment;B.confirm_credentials=false;launchFlags=0x00008000;end
检测是否有命令执行漏洞
intent:http://drops.wooyun.org/webview.html#Intent;component=com.android.browser/com.android.browser.BrowserActivity;end
删除其他应用
intent:package:org.wooyun.hiwooyun#Intent;action=android.intent.action.DELETE;end
漏洞修复
// convert intent scheme URL to intent object
Intent intent = Intent.parseUri(uri);
// forbid launching activities without BROWSABLE category
intent.addCategory("android.intent.category.BROWSABLE");
// forbid explicit call
intent.setComponent(null);
// forbid intent with selector intent
intent.setSelector(null);
// start the activity by the intent
context.startActivityIfNeeded(intent, -1)
参考链接
http://wolfeye.baidu.com/blog/intent-data-leak/
http://blog.csdn.net/l173864930/article/details/36951805
http://blog.csdn.net/jdsjlzx/article/details/37700791
http://wenku.baidu.com/link?url=OmRp-zGdS8Oo16pmMHZC8UxO0LwkeXkXbs1x224v_pny2_sE-j4CbEXUAxVoI4F2_bH6LB2UXFOaEU671ONs9jWOtRFk2c6D-ZqzitqknHq