Exported-component audit of a consumer Android app
Multiple exported activities and one exported service without caller verification. Cross-app UI hijack demonstrable via a small zero-permission PoC APK that reproduces every finding vector.
Kontext / Context
Eine Consumer-Android-App mit hoher Install-Base wollte ihre externe IPC-Oberfläche kritisch bewerten lassen, nachdem ein internes Security-Team ein Risiko in ihren Pairing-Flows (zweites Device oder Wearable) markiert hatte.
Finding-Muster (abstrahiert)
- Exportierte Onboarding-Activity ohne Caller-Check. Externe Apps konnten einen authentisch aussehenden Sign-in-Dialog der Ziel-App rendern, ohne dass der Nutzer den Flow je in der App selbst angestoßen hatte.
- Exportierte Settings-Activity pre-login aufrufbar. Eine Settings-Oberfläche war aus externen Apps startbar. Teile davon mutierten App-State auch ohne Login.
- Exportierte Content-Activity akzeptiert attacker-controlled IDs. Eine Activity übernahm externe Intent-Extras ungeprüft und navigierte in eine interne Content-View. Server-seitige Ownership-Checks auf älteren Endpunkten waren unvollständig.
- Exportierter Messaging-Service ohne Permission. Ein Listener-Service war ohne
android:permissionexportiert. Service-Start aus einer unprivileged uid war dynamisch verifizierbar. - Zero-Permission PoC-APK. Eine kleine APK mit einer Handvoll Buttons reproduzierte jeden Vektor sauber, inklusive Task-Affinity-Hijack-Variante für ältere Android-Versionen.
Methodik
- Manifest-Extract und Diff gegen verfügbare Debug-Referenzen
- smali-Level-Review der
onCreate-Pfade aller exportierten Komponenten - PoC-APK-Bau ohne Gradle (minimaler Build-Pfad über aapt2, javac, d8, apksigner), damit das Artefakt als Evidence klein und lesbar bleibt
- Dynamische Verifikation per
adb shell am startmit Screenshot-Evidence pro Komponente - Video-Walkthrough auf einem gerooteten Test-Device
Deliverable
Report mit CVSS pro Finding, annotierten Smali-Snippets, PoC-APK-Source inkl. Build-Script, Video-Walkthrough und konkreter Manifest-Audit-Regel für den CI-Pipeline-Gate (block exported ohne android:permission bei allowlist-Verletzung).
Learnings
Das Exported-Component-Pattern ist in grossen Android-Codebases chronisch. Legacy-Code erbt exported=true aus Alt-Intent-Filter-Konfigurationen; neue Android-Versionen zwingen zu expliziter Deklaration, aber die Default-Auswahl wird unter Zeitdruck oft auf “true” gesetzt. Ein Manifest-Audit als CI-Gate mit Opt-in-Allowlist ist die einzige skalierende Kontrolle.