Bypassing Intent Destination Checks, LaunchAnyWhere Privilege Escalation
Qidan He (Center Director and Chief Security Researcher · gd.com)
DEF CON 33 · Day 1 · Main Stage
Overview
In this DEF CON talk, Qidan He, a distinguished security researcher, unveils "Bad Resolve," a novel class of LaunchAnywhere privilege escalation vulnerabilities impacting modern Android systems. The presentation details a sophisticated Time-of-Check-Time-of-Use (ToCToU) attack that bypasses existing intent destination checks, allowing a low-privileged attacker application to launch protected or unexported activities within privileged system applications like Settings. This research challenges the long-standing security model of Android's inter-process communication (IPC) via Intents, demonstrating how subtle race conditions in the intent resolution process can lead to severe privilege escalations, enabling actions like modifying PINs or making phone calls without explicit user permissions.

Key moments
- 0:00 Talk introduction and agenda overview
- 1:50 Core Android IPC: Intents explained
- 4:40 Deep dive into intent resolution logic
- 6:30 Recap of historical LaunchAnywhere vulnerabilities
- 7:00 Intent redirection using nested intents
- 7:40 Targeting privileged system bridge applications
Bypassing Intent Destination Checks, LaunchAnywhere Privilege Escalation
Speakers: Qidan He, Center Director and Chief Security Researcher, gd.com
Conference: DEF CON
YouTube: https://www.youtube.com/watch?v=kSJBEZkJ4vM
Overview
In this DEF CON talk, Qidan He, a distinguished security researcher, unveils "Bad Resolve," a novel class of LaunchAnywhere privilege escalation vulnerabilities impacting modern Android systems. The presentation details a sophisticated Time-of-Check-Time-of-Use (ToCToU) attack that bypasses existing intent destination checks, allowing a low-privileged attacker application to launch protected or unexported activities within privileged system applications like Settings. This research challenges the long-standing security model of Android's inter-process communication (IPC) via Intents, demonstrating how subtle race conditions in the intent resolution process can lead to severe privilege escalations, enabling actions like modifying PINs or making phone calls without explicit user permissions.
He's work revives the "LaunchAnywhere" threat model, which Google had largely mitigated through various fixes over the years, including addressing Parcel mismatch vulnerabilities. The "Bad Resolve" series of vulnerabilities (for which two CVEs have already been assigned) highlights a new attack vector that doesn't rely on manipulating the intent object itself, but rather on manipulating the outcome of its resolution during a critical time window. This article will deep dive into the technical intricacies of this vulnerability, the sophisticated exploitation techniques, and the defensive implications for the Android ecosystem.
Background
▶ Watch: Talk introduction and agenda overview (0:00)
Android's architecture relies heavily on Intents for inter-process communication (IPC) between applications and system components. Intents act as abstract messages, encapsulating data and specifying actions, enabling components like Activities, Services, and Broadcast Receivers to communicate. Components can declare intent filters in their AndroidManifest.xml to specify what types of intents they are capable of handling. Intents can be explicit, directly targeting a specific component, or implicit, where the Android system resolves the intent to a suitable component based on its action, category, data, and type.
Security restrictions are paramount in intent resolution. Normal applications are prevented from directly starting protected activities (requiring specific permissions) or unexported activities (not declared for external access) of other applications. This protection is fundamental to Android's sandboxing model. However, the inherent flexibility of Intents, particularly their ability to contain nested Intents (as Parcelable objects within a Bundle), has historically led to a class of vulnerabilities known as "LaunchAnywhere."
A classic example of LaunchAnywhere emerged in 2014 within the Android Account Manager service. A privileged system application, like Settings, might process a bundle from a less-privileged application, extract an intent from it, and then blindly call startActivity on that intent. If the privileged application possesses the necessary permissions (e.g., system UID), it could be coerced into launching arbitrary protected activities on behalf of an attacker. The initial fix for such vulnerabilities involved adding a checkIntent function within the AccountManagerService. This function would perform resolveActivity on the incoming implicit intent and verify that the resolved target activity belonged to the calling application (i.e., the attacker's own app, ensuring no privilege escalation to other apps).
Despite these mitigations, new attack vectors emerged. The most prominent were Parcel mismatch vulnerabilities. These exploited discrepancies between how an object was serialized (writeToParcel) and deserialized (readFromParcel). A maliciously crafted Parcelable object containing an intent could appear benign to the checkIntent function (after one round of serialization/deserialization) but transform into a privileged intent when deserialized again by the target application (e.g., Settings). This meant the system server and the Settings app would "see" different intents, bypassing the check. Parcel mismatch vulnerabilities were widely exploited, affecting billions of devices and leading to over 100 CVEs before Google rolled out comprehensive mitigations. "Bad Resolve" picks up where Parcel mismatch left off, introducing a new paradigm for bypassing intent destination checks.
Key Findings
▶ Watch: Deep dive into intent resolution logic (4:40)
The core finding of this research is the "Bad Resolve" vulnerability, a novel Time-of-Check-Time-of-Use (ToCToU) race condition that re-enables LaunchAnywhere attacks on Android. Unlike previous Parcel mismatch vulnerabilities that aimed to make the checking component and the executing component "see" different intent objects, Bad Resolve forces them to see different resolution outcomes for the same intent object.
The central idea is as follows:
- Check Phase: A privileged system service (e.g.,
AccountManagerService) performs a security check on an incoming implicit intent. During this check, the intent resolves to a benign activity controlled by the attacker's application. The check passes because the resolved target's signature matches the attacker's application, satisfying the security policy (attacker can only launch their own activities). - Race Window: Immediately after the check passes, but before the intent is actually launched by the privileged application (e.g., Settings), the attacker rapidly disables their benign activity using
setComponentEnabledSetting. - Use Phase: When the privileged application attempts to launch the same intent, the original benign target is now disabled. The Android system re-resolves the implicit intent. With the attacker's benign activity removed from the candidate list, the intent now resolves to a privileged, protected activity of a system application, which the attacker originally intended to target. The privileged application then launches this protected activity, resulting in a privilege escalation.
This ToCToU attack leverages a critical insight: the intent resolution process is dynamic and depends on the current state of components. By precisely manipulating the enabled/disabled state of their own component during a minuscule time window, the attacker can hijack the resolution outcome, turning a seemingly legitimate intent into a vector for launching sensitive system functionalities. This bypasses the intent destination checks that were designed to prevent such redirections, demonstrating a fundamental flaw in how intent resolution state is handled across security boundaries.
Technical Deep Dive
▶ Watch: Recap of historical LaunchAnywhere vulnerabilities (6:30)
The "Bad Resolve" vulnerability hinges on exploiting a race condition within Android's intent resolution and execution flow. The primary primitive for this attack is the setComponentEnabledSetting API, which allows an application to dynamically enable or disable its own components (activities, services, broadcast receivers). A disabled component is treated as if it never existed by the system's component resolver.
Let's break down the technical process:
1. The ToCToU Window:
The attack targets the time window between when a privileged service (AccountManagerService in the classic LaunchAnywhere scenario) performs checkIntent and when the target application (Settings) actually calls startActivity on the received intent. Both checkIntent and startActivity internally invoke resolveActivity (or similar resolution logic) to determine the target component. The goal is to make these two resolution calls yield different results.
- Initial Challenge (Single Target): If an implicit intent resolves to only one candidate (e.g., the attacker's benign activity), disabling that activity would cause
startActivityto fail with an exception. The attack requires the implicit intent to initially resolve to multiple candidates, with the attacker's activity being the preferred one during the check phase, and a privileged target becoming the sole candidate (or the next preferred) after the attacker's activity is disabled.
- Intent Resolution Logic: The Android system's
resolveInternalfunction (withinResolveIntentHelperand ultimatelyPackageManagerService) follows a specific hierarchy to find a target for an implicit intent:
- Exclude Disabled: Disabled components are immediately filtered out.
- Priority Matching: Components declaring higher
android:priorityin their intent filters are preferred. However, normal applications can only declare priority 0 or less; higher priorities are reserved for platform/system applications. This means an attacker cannot simply use priority to force their activity to be chosen over a system activity. - Preferred Activities: If no priority difference, the system checks for a preferred activity. This is an activity a user has previously selected and marked as "Always" when prompted by a chooser dialog. This user preference persists across application updates and even re-installations. This is the crucial element for the "Bad Resolve" attack.
- Chooser Dialog: If multiple candidates remain and no preferred activity is found, a chooser dialog is presented to the user. This is not viable for the attack, as the
checkIntentfunction would likely detect the system'sChooserActivity(which has a different signature than the attacker's app) and fail the security check.
Therefore, the attacker's strategy is to ensure their benign activity is designated as the preferred activity for the malicious implicit intent.
2. The Initial Time Window Problem:
Using profetto, a performance analysis tool in AOSP, the speaker initially observed that the entire checkIntent process, including resolveActivity, takes only about 1 millisecond. The resolveIntent call itself takes approximately 0.5 milliseconds. This extremely short time window makes a traditional ToCToU race condition (where the attacker disables a component mid-execution) practically impossible for an unprivileged application.
3. The Snapshot Mechanism - A Crucial Discovery:
The breakthrough came from understanding how PackageManagerService handles component information. When resolveIntent is called, the ComponentResolver inside PackageManagerService creates a snapshot of the current state of all component mappings (activities, services, etc., and their intent filters). All subsequent queries during that specific resolveIntent call are performed on this frozen snapshot. This means any changes to component states (like enabling/disabling an activity) that occur after the snapshot is taken but before the resolveIntent call returns will not be reflected in that particular resolution result. This mechanism effectively extends the usable time window for the attacker. The attacker can disable their component during the resolveIntent call, and this change won't affect the current resolution (which will still see the component as enabled via the snapshot), but it will affect the next resolution call (when startActivity is invoked by Settings).
4. Extending the Time Window:
Even with the snapshot mechanism, the resolveIntent call itself is fast. To make the race feasible, the attacker needs to artificially slow down the resolveIntent process. This is achieved by:
- Malicious
AndroidManifest.xml: The attacker declares anintent-filterfor their benign activity with an extremely large number of categories (e.g., 10,000 to 40,000). WhenPackageManagerServiceperforms a linear search or iterates through these categories during resolution, it significantly increases the processing time. FLAG_DEBUG_LOG_RESOLUTION: Passing this flag in the intent forces verbose logging during the resolution process withinActivityManagerServiceandPackageManagerService. This involves printing all intent filters and their elements, further dramatically slowing down the resolution.
These techniques combined can extend the resolveIntent duration from 0.5ms to 50-400ms (on high-end devices like Pixel 7 Pro/8 Pro) or even up to 1 second (on older devices like Galaxy S21). This extended time window is sufficient for the attacker to execute the setComponentEnabledSetting call.
5. The Final Attack Flow:
- Setup (Preferred Activity): The attacker first installs a benign version of their application. They then trick the user into triggering an implicit intent that resolves to both the attacker's activity and a target privileged activity. The user is prompted with a chooser dialog and selects the attacker's activity, clicking "Always" to mark it as preferred.
- Update (Malicious Manifest): The attacker updates their application with a new version containing the malformed
AndroidManifest.xml(many categories). The "preferred activity" state persists across updates. (Alternatively, the attacker can use 10,000 categories directly, which typically doesn't crash the chooser dialog, avoiding the update step). - Initiate Attack: The attacker application triggers the
addAccountfunctionality inAccountManagerService, initiating the LaunchAnywhere flow. checkIntent(System Server): The system server callscheckIntent.resolveActivityis invoked. Due to the malformed manifest, this call takes hundreds of milliseconds. During this call, a snapshot is taken. The attacker's activity is still enabled and marked as preferred, so the resolution points to it. ThecheckIntentpasses.- Race (Attacker): Immediately after the
checkIntentreturns, the attacker's background thread (which was started concurrently) callssetComponentEnabledSettingto disable their benign activity. This happens before theSettingsapplication receives the intent. startActivity(Settings): TheSettingsapplication receives the bundle and extracts the intent. It callsstartActivity. This triggers anotherresolveActivityinternally. Now, the attacker's benign activity is disabled and excluded from candidates. The intent resolves to the actual privileged target activity (e.g., a protected settings activity).- Privilege Escalation: The
Settingsapplication, a system UID process, launches the privileged activity, granting the attacker unauthorized access.
Limitations and Gadgets:
The "Bad Resolve" vulnerability, being an implicit intent resolution attack, requires the target privileged component to have an intent-filter with a data element and CATEGORY_DEFAULT declared. This limits the direct targets. To overcome this, the speaker demonstrates chaining with gadgets:
SearchTrampolineActivity: This activity, present in AOSP, retrieves a string from an incoming intent and callsparseUrion it, which then creates and launches a new intent. Crucially, it performs a caller package check, but with "Bad Resolve," the caller is "Settings," bypassing this check. This gadget extends the attack to any activity that can be launched via a URI.- Custom
ChooserActivityimplementations: Many Android vendors (e.g., Xiaomi, Honor, Huawei) implement their ownChooserActivityversions. Unlike the AOSPChooserActivity(which has a high priority of 500, making it hard to target with Bad Resolve), these custom versions often lack explicit priority declarations, making them vulnerable Bad Resolve targets. These custom choosers can then be coerced into launching arbitrary intents passed to them, often with insufficient caller verification. For instance, on Honor/Huawei devices, the attack chainsBad Resolve->HWChooserActivity-> AOSPChooserActivity-> Victim Privileged Activity.
Demo / Proof of Concept
▶ Watch: Intent redirection using nested intents (7:00)
Qidan He presented several compelling demonstrations of the "Bad Resolve" vulnerability:
- Log Password Modify: A straightforward demonstration on a stock Android device where the attacker used "Bad Resolve" to directly launch the
log_password_modifyprotected activity within the Settings application. This allowed the attacker to modify the device's PIN without requiring any prior authorization, showcasing a critical privilege escalation.
- Phone Call without Privilege: On Android 16 Beta 3 (the latest version at the time of the talk), a script was used to exploit a similar "Bad Resolve" vulnerability found in the
AppRestrictionFragment. This exploit successfully initiated a phone call without the attacker application holding theCALL_PHONEpermission. The speaker humorously noted that during vulnerability disclosure, the Android security team requested they stop using 911 for testing.
- Chaining with
SearchTrampolineActivity: This demo illustrated how theSearchTrampolineActivitygadget could expand the attack surface. By using "Bad Resolve" to launchSearchTrampolineActivitywith a controlledintentparameter (encoded as a string URI), the attacker could then launch arbitrary activities that might not have met the direct implicit intent requirements of "Bad Resolve." The key was thatSearchTrampolineActivity's caller package check would pass because the calling application was the privileged "Settings" app.
- Vendor-Specific
ChooserActivityExploitation (Xiaomi, Honor/Huawei): This advanced demo showcased platform-specific exploitation.
- On Xiaomi devices, the "Bad Resolve" vulnerability was used to target the MIUI Chooser Activity. This custom chooser, unlike its AOSP counterpart, lacked a high priority, making it a viable target. The MIUI Chooser Activity would then accept an arbitrary intent from the attacker and launch it with system privileges because the caller (Settings) was trusted.
- On Honor and Huawei devices, a more complex chaining was required. The "Bad Resolve" vulnerability first targeted the HW Chooser Activity. This activity, while exported and vulnerable, had checks that ensured its next target was also exported and that the caller had permission. By targeting the AOSP
ChooserActivity(which is exported and considered trusted by HW Chooser), the attacker could then leverage the AOSP Chooser to launch the final victim privileged activity. This demonstrated the versatility of chaining multiple trusted components to achieve the ultimate goal.
The use of profetto was critical throughout the research, enabling precise measurement of the time windows involved in intent resolution and execution, which was essential for designing and verifying the ToCToU attack.
Defensive Implications
▶ Watch: Targeting privileged system bridge applications (7:40)
The "Bad Resolve" series of vulnerabilities highlights a fundamental weakness in relying on dynamic intent resolution for security checks, particularly when a time-of-check-time-of-use scenario can be engineered. Google's fix for the specific AccountManagerService vulnerability discussed in the talk was elegant and effective: after the checkIntent function passes, the system now explicitly sets the component or package of the intent using setComponent or setPackage. This transforms the implicit intent into an explicit intent before it is passed to the Settings application for execution. By making the intent explicit, the subsequent startActivity call no longer triggers a dynamic resolution process, thereby eliminating the ToCToU race window. The intent's target is now fixed based on the outcome of the security check, preventing any last-minute manipulation of the resolution path.
For developers and security engineers, the broader defensive implications are significant:
- Explicit Intent After Check: Any code that performs a security check on an implicit intent's resolution result and then subsequently uses that intent for
startActivity(or similar launch operations) should ideally convert the intent into an explicit one usingsetComponentorsetPackagebased on the checked resolution outcome. This hardens the intent's destination, preventing further dynamic resolution. - Avoid Dynamic Resolution for Sensitive Operations: Where possible, avoid using implicit intents for launching highly sensitive or protected activities, especially when the intent's contents or target can be influenced by external, less-privileged applications.
- Review
resolveActivity+startActivityPatterns: Android application developers and AOSP contributors should carefully audit code patterns whereresolveActivity(or similar resolution logic) is followed bystartActivityon the same intent, particularly when the intent originates from an untrusted source or when an implicit intent is used. Such patterns are prime candidates for ToCToU vulnerabilities. - Component State Changes: Be mindful of how dynamic changes to component states (like enabled/disabled settings) can interact with cached or snapshotted resolution results across different execution contexts or timeframes.
- Vendor Customizations: The reliance on vendor-specific
ChooserActivityimplementations as gadgets underscores the ongoing challenge of maintaining consistent security across the fragmented Android ecosystem. Vendors must ensure their custom components adhere to the same stringent security standards as AOSP components, especially regarding intent handling and caller verification. - AI/ML for Vulnerability Detection: While still nascent, the speaker's exploration of using ARM (AI-powered Reverse Engineering and Malware analysis) with MCP (Multi-Agent Communication Protocol) agents to search for similar vulnerabilities suggests a future direction for proactive defense. Such tools, despite current limitations like false negatives and hallucinations, could eventually assist in identifying problematic code patterns at scale.
In essence, the "Bad Resolve" vulnerability serves as a critical reminder that even seemingly robust security checks can be undermined by subtle race conditions and the dynamic nature of system components if the checked state is not durably enforced.
Key Takeaways
- "Bad Resolve" is a novel ToCToU vulnerability: It bypasses Android's intent destination checks by manipulating the resolution outcome of an implicit intent during a time-of-check-time-of-use race condition, rather than altering the intent object itself.
- Component state manipulation is key: The attacker uses
setComponentEnabledSettingto dynamically disable their own benign activity, changing the intent's resolution target between the security check and the actual launch. - Snapshot mechanism is crucial for the race:
PackageManagerServiceuses a snapshot of component information duringresolveIntent, providing the necessary time window for the attacker to disable their component without immediately affecting the current resolution result. - Time window extension via malformed manifest: Declaring an
intent-filterwith tens of thousands of categories and usingFLAG_DEBUG_LOG_RESOLUTIONcan extend theresolveIntentduration to hundreds of milliseconds or even a second, making the ToCToU attack feasible. - Chaining with gadgets expands attack surface: While direct targets for "Bad Resolve" may be limited, chaining with components like
SearchTrampolineActivityor vulnerable vendor-specificChooserActivityimplementations significantly broadens the scope of privilege escalation. - Google's fix involves explicit intent conversion: The vulnerability is mitigated by converting the implicit intent to an explicit one (using
setComponentorsetPackage) immediately after the security check, thereby eliminating the dynamic resolution race.
About the Speaker(s)
Qidan He is a highly accomplished security researcher, currently serving as the Center Director and Chief Security Researcher at gd.com, where he leads the Dawn Security Lab. His lab focuses on a range of security aspects, including anti-fraud, client security, and security research. He is a recognized figure in the cybersecurity community, having been a winner of both the Pwn2Own and Mobile Pwn2Own competitions. In 2022, he received a prestigious Pony Award for Best Privilege Escalation. Qidan He is also a frequent speaker at major security conferences worldwide, including Black Hat, DEF CON, POC (Power of Community), and Hack In The Box, sharing his expertise on advanced vulnerability research, particularly in the Android ecosystem.
Reviews
Dr. Zero (Offensive Security Researcher) — MUST SEE
Qidan He drops a genuinely novel ToCToU attack class against Android's intent resolution pipeline — not a rehash of Parcel mismatch, not a vendor CVE write-up, but a new primitive with a full exploitation chain, live demos on Android 16 Beta, and vendor-specific gadget chains. This is the kind of research that forces a platform team to rethink a security model, not just patch a single bug.
Heather Calloway (CISO) — WEAK
Technically rigorous exploit research with real CVEs and a clean fix narrative, but it never climbs out of the vulnerability rabbit hole long enough to mean anything to a security leader or Android ecosystem decision-maker. The defensive section exists but reads like developer documentation, not institutional guidance.