Note: This is part of my @vr_progress journal. Also, subscribe to my new @SideQuest_256 channel and I might post videos about the Android journey too :D
This is a story about how I wasted my weekend over a bug that was categorized as a High/EoP but then couldn’t find a clever way to elevate privileges with it.
It all started when I decided to revisit an old testing device - my trusty OnePlus phone that had been sitting in a drawer, untouched and unpatched for years. Since I hadn’t updated it in ages, I thought it would be fun to try exploiting a 1-day vulnerability that affected the device.
Scrolling through the Android advisories, CVE-2020-0238 caught my attention, and I thought, “Why not?” After all, the bug was labeled as High severity, with the potential for Elevation of Privilege (EoP). Also, it’s a logic bug so I might even get a quick win(unlike memory corruptions that usually take more time and special engineering to exploit)
What followed was a weekend full of debugging, writing PoC code, and realizing that, while the bug seemed interesting on the surface, its real-world exploitability has more pre-requisites than I thought.
- What I expected: Direct EoP from a
untrusted_app
to a privilegedsettings.apk
. - What I got: Potential/Indirect EoP from attacker apk to a victim apk.
Here’s what I learned about CVE-2020-0238, its fix, and its impact.
The Fix
Below is the fix:
- Advisory: https://source.android.com/docs/security/bulletin/2020-08-01
- Commit: 33dd3187d0246a0425a41f76888a369c16dc9379 :
Analysis
The issue revolves around the AccountTypePreferenceLoader
class in Android’s Settings app, specifically in how it resolved and validated activities associated with an account type. The problem is triggered from the AccountDetailDashboardFragment
class(in com.android.settings.accounts
), where user accounts are managed.
AbstractAccountAuthenticator
: This is a base class that app developers use to create custom authenticators for managing accounts on Android. It defines methods likeaddAccount()
orgetAuthToken()
.AccountTypePreferenceLoader
: This class is responsible for loading UI elements (preferences) for account types in the Settings app. It would erroneously allow launching activities from other apps if certain conditions were met.- The Bug: The check for
resolvedActivityInfo.exported
allowed activities not owned by the authenticator to be launched if they were exported and did not require specific permissions.
The fix ensures that only activities belonging to the same uid
as the authenticator’s app can be launched, reducing the risk of privilege escalation.
Re-produce
To exploit this bug, a malicious app needs to manipulate the account_preferences.xml
file and register a custom service that interacts with the vulnerable component.
- Create a Service: Define a malicious service in the app’s manifest to mimic an authenticator:
- Implement
addAccount
: Implement a basicaddAccount()
method in your malicious authenticator service to register an account. - Craft
account_preferences.xml
: Create a customaccount_preferences.xml
file with entries designed to trigger the vulnerable code path.
When the Settings app attempts to load preferences for this malicious account type, the bug allows launching unauthorized activities.
When clicking on the account, the AccountDetailDashboardFragment
is loaded, together with our xml:
Then, a click on the “Trigger bug :D” button, triggers updatePreferenceIntents()
, which is calling the isSafeIntent()
function(the one that the commit patched)
Impact
I’m not really sure how exploitable this is, because the attacker APK needs to have the same permission as the victim APK(at least on my testing device).
Also, if the activity is already exported, why would the attacker app need to use the Settings app to trigger the exported activity? It’s already exported.
The only scenario I could think of is one where the victim app has an exported activity but it verifies which app has triggered the activity (using stuff like getCallingUid()
and getCallingPackage()
), allowing only the Settings app to trigger it.
The fix mitigates these risks by enforcing that only activities owned by the authenticator can be launched. This change effectively ties activity execution to the authenticator’s uid
, preventing unauthorized apps from exploiting this pathway.
Conclusion
In the end, CVE-2020-0238 demonstrates the subtlety of Android security issues - how seemingly innocuous permissions or checks can open doors for unintended behavior. This particular bug was a little bit disappointing, but, whatever. I hope I missed something and find out that it’s more exploitable than I initially thought.
Either way, I learned some new things, which is nice :^)
Thanks for tuning in, and see you in the next attempt.