In order to adapt to the larger and larger device screen, Android introduced the concept of Fragment after 3.X, which can display multiple activities on one screen at the same time, in order to make full use of the screen. For instructions on Fragments, you can read <Android Fragment completely parses everything you need to know about debris. . Among them, Fragment has a very powerful function, that is, it can be loaded dynamically. This makes the development of the whole interface more flexible, and different activities can be loaded dynamically according to different scenarios.
Back to today's topic -- Implementing injection attacks using Fragments. After 3.X, Android engineers reconstruct the implementation of Preference Activity and use Fragment to load the interface. By reading the source code, we can find that in the onCreate of Preference Activity, we need to read multiple extras of Intent. Constants are defined in Preference Activity (that pile of extra_XXXXXX is it). Two constants are EXTRA_SHOW_FRAGMENT=":android:show_fragment" and EXTRA_SHOW_FRAGMENT_ARGUMENTS=":android:show_fragment_args ", these two parameters determine the fragment that the current Preference Activity first displays. The process is relatively simple, that is to get fragment_class and fragment_args first, and then generate a fragment instance by reflection, and load it dynamically. The key source code is as follows:
mSinglePane = hidingHeaders || !onIsMultiPane(); String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT); Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0); int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);
First, two parameters, initalFragment and initial Arguments, are obtained, and then instantiated in switchToHeader Inner:
private void switchToHeaderInner(String fragmentName, Bundle args, int direction) { getFragmentManager().popBackStack(BACK_STACK_PREFS, FragmentManager.POP_BACK_STACK_INCLUSIVE); Fragment f = Fragment.instantiate(this, fragmentName, args); FragmentTransaction transaction = getFragmentManager().beginTransaction(); transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); transaction.replace(com.android.internal.R.id.prefs, f); transaction.commitAllowingStateLoss(); }
So far, we can dynamically modify the initial Fragment displayed by Preference Activity by setting Intent's extral.
We know that in Android systems, App and App are isolated from each other and cannot access each other's private data. Communication between App and App (or more accurately between components) uses Intent in a unified way. Intent can easily arouse other Apps'Activeness and achieve the purpose of functional reuse. For example, when you use ZAKER, you need to share it in the micro-mail circle. In this way, you can jump directly to the micro-mail sharing interface. But the premise for using this approach is that the target Activity is exported .
Combining the above two key points, can we find a subclass of exported Reference Activity and open interfaces without exported by carefully setting the value of Intent's extral? What happens if these interfaces involve security information?
Setting is available on almost every Android device. Setting is signed by system_uid, so it has the power to execute system. Its main interface, com.android.settings.Settings, is inherited from PreferenceActivity and must be exported. As an entry point, we try to find out what important Fragments are in Setting and try to load them. The main purpose is to skip some restrictions that require user interaction. For example, ChooseLockPassword $ChooseLockPassword Fragment, which is mainly responsible for the password setting and modification of the lock screen interface. At the same time, this class will do different logic based on the initial Arguments that were passed in before, and the key code is as follows:
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); } }
If the key is "confirm_credentials" as true in the parameter passed in, the old password verification process will be invoked. If false, you can skip the old password validation and go directly to the password modification process. The test code is as follows:
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);
The normal password modification process is "Settings" - > "Security" - > "Screen Lock" - > "Confirm Your PIN", as shown in the following figure:
If you run DEMO, go directly to the following interface:
This way, you can overwrite the original password by entering the password directly.
This BUG exists in all versions of 3.X to 4.3, and 4.4 is fix ed. 4.4 Forces all PreferenceActivities to implement the isValidFragment method, as detailed in Here
Personal summary:
It should be said that this repair method only serves as a reminder, and the ultimate security is left to the developer. In addition, many applications are currently based on 2.X, so to be compatible with running on 4.4 without crash, as long as the subclasses of PreferenceActivity are supplemented with isValid Fragment method. However, for the version before 4.4, if there is such a leakage of permissions, it needs to be dealt with separately. A code example compatible with 2.X~4.4 fixes is given below:
public final class MyPreferenceActivity extends PreferenceActivity { private boolean doValidcheck(String fragmentName) throws IllegalArgumentException{ //TODO Checks Legitimacy return true; } //Add this method to make 2.x~4.3 code run normally on 4.4 protected boolean isValidFragment(String fragmentName) { return doValidcheck(fragmentName); } @Override protected void onCreate(Bundle savedInstanceState) { //Judging legality before onCreate String fragmentname = getIntent().getStringExtra(":android:show_fragment"); doValidcheck(fragmentname); super.onCreate(savedInstanceState); } }
Reprinted at: https://www.cnblogs.com/riasky/p/3471323.html