Unsachgemäße Verifizierung von Intents durch Broadcast Receiver
Beschreibung
Unsachgemäße Verifizierung von Intents durch Broadcast Receiver ist eine Android-spezifische Schwachstelle, bei der Anwendungen, die Broadcast Receiver verwenden, nicht verifizieren, dass empfangene Intents von autorisierten Quellen stammen. Während das Android-Betriebssystem bestimmte implizite System-Intents (wie ACTION_BOOT_COMPLETED) darauf beschränkt, nur vom Betriebssystem selbst gesendet zu werden, können bösartige Anwendungen explizite Intents direkt an den Broadcast Receiver einer anfälligen Anwendung senden. Selbst Receiver, die für implizite System-Intents registriert sind, erhalten auch explizite Intents, was möglicherweise unbeabsichtigtes Verhalten verursacht, wenn der Receiver die Quelle des Intents nicht validiert.
Risiko
Diese Schwachstelle ermöglicht es bösartigen Anwendungen, Aktionen in anfälligen Anwendungen auszulösen, indem sie manipulierte Intents senden. Angreifer können Denial-of-Service verursachen, indem sie Shutdown- oder Cleanup-Prozeduren auslösen. Sensible Operationen, die nur für System-Events bestimmt sind, können beliebig ausgelöst werden. Daten können exfiltriert werden, wenn Receiver bösartige Intents verarbeiten und darauf reagieren. Der Anwendungsstatus kann durch unerwartete Intent-Verarbeitung beschädigt werden. In schweren Fällen könnten Angreifer privilegierte Operationen auslösen, die nur als Reaktion auf legitime System-Events auftreten sollten.
Lösung
Verifizieren Sie immer die Quelle empfangener Intents in Broadcast Receivern. Für Receiver, die nur auf System-Intents reagieren sollten, prüfen Sie, ob der Intent implizit ist (keine explizite Komponente gesetzt). Verwenden Sie Berechtigungen auf Signaturebene, um einzuschränken, wer Intents an Ihre Receiver senden kann. Erwägen Sie die Verwendung von LocalBroadcastManager für interne Anwendungs-Broadcasts. Setzen Sie android:exported="false" für Receiver, die keine externen Intents empfangen müssen. Validieren Sie alle Intent-Extras vor der Verarbeitung. Für sensible Operationen implementieren Sie zusätzliche Autorisierungsprüfungen über das bloße Empfangen des Intents hinaus.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Bereich: Zugriffskontrolle Privilegien erlangen oder Identität annehmen - Bösartige Anwendungen können das Betriebssystem imitieren und Aktionen auslösen, die nur für System-Events bestimmt sind. |
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Absturz/Beenden/Neustart - Angreifer können Shutdown- oder Cleanup-Prozeduren auslösen und Denial-of-Service verursachen. |
| Integrität | Bereich: Integrität Anwendungsdaten modifizieren - Unerwartete Intent-Verarbeitung kann den Anwendungsstatus oder Daten beschädigen. |
Beispielcode
Anfälliger Code
// Anfällig: BroadcastReceiver ohne Intent-Verifizierung
public class VulnerableShutdownReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// Anfällig: Keine Verifizierung, dass dies vom System kommt
if (Intent.ACTION_SHUTDOWN.equals(action)) {
// Angreifer kann dies mit explizitem Intent auslösen!
performShutdownCleanup(context);
deleteTemporaryFiles(context);
saveStateAndClose(context);
}
}
private void performShutdownCleanup(Context context) {
// Caches leeren, Daten speichern, etc.
}
}
// AndroidManifest.xml
// <receiver android:name=".VulnerableShutdownReceiver"
// android:exported="true">
// <intent-filter>
// <action android:name="android.intent.action.ACTION_SHUTDOWN"/>
// </intent-filter>
// </receiver>
// Bösartige App des Angreifers
public class AttackerApp {
public void triggerShutdown(Context context) {
// Expliziten Intent an anfälligen Receiver senden
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SHUTDOWN);
intent.setComponent(new ComponentName(
"com.vulnerable.app",
"com.vulnerable.app.VulnerableShutdownReceiver"
));
context.sendBroadcast(intent);
// Anfällige App führt Shutdown-Cleanup durch!
}
}
// Anfällig: Batterie-Überwachungs-Receiver
public class VulnerableBatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// Anfällig: Batterie-Level von jedem Intent vertrauen
if (Intent.ACTION_BATTERY_LOW.equals(action)) {
// Angreifer kann Niedrigbatterie-Modus auslösen
enablePowerSavingMode(context);
disableBackgroundSync(context);
notifyUser("Batterie niedrig!");
}
if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
// Angreifer kann Energiesparmodus deaktivieren
disablePowerSavingMode(context);
}
}
}
Korrigierter Code
// Korrigiert: BroadcastReceiver mit Intent-Quellenverifizierung
public class FixedShutdownReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Korrigiert: Verifizieren, dass dies ein System-Broadcast ist, kein expliziter Intent
if (!isSystemBroadcast(intent)) {
Log.w(TAG, "Ablehnung expliziten Intents, der versucht Shutdown auszulösen");
return;
}
String action = intent.getAction();
if (Intent.ACTION_SHUTDOWN.equals(action)) {
performShutdownCleanup(context);
deleteTemporaryFiles(context);
saveStateAndClose(context);
}
}
private boolean isSystemBroadcast(Intent intent) {
// Korrigiert: Prüfen, ob dies ein impliziter Broadcast ist (kein explizites Ziel)
// Explizite Intents haben Component gesetzt
return intent.getComponent() == null;
}
private void performShutdownCleanup(Context context) {
// Sicher fortzufahren
}
}
// AndroidManifest.xml - Berechtigungsanforderung hinzufügen
// <receiver android:name=".FixedShutdownReceiver"
// android:exported="true"
// android:permission="android.permission.SHUTDOWN">
// <intent-filter>
// <action android:name="android.intent.action.ACTION_SHUTDOWN"/>
// </intent-filter>
// </receiver>
// Korrigiert: Verwendung von Signatur-Berechtigung für sensible Receiver
// In AndroidManifest.xml:
// <permission
// android:name="com.myapp.permission.SENSITIVE_ACTION"
// android:protectionLevel="signature"/>
//
// <receiver android:name=".SensitiveReceiver"
// android:exported="true"
// android:permission="com.myapp.permission.SENSITIVE_ACTION">
public class FixedSensitiveReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Korrigiert: Selbst mit explizitem Intent können nur Apps, die mit
// unserem Schlüssel signiert sind, diese Berechtigung haben
// Zusätzliche Verifizierung für System-Intents
if (isSystemAction(intent.getAction())) {
if (!isFromSystem(context, intent)) {
Log.w(TAG, "Ignoriere Nicht-System-Intent für System-Aktion");
return;
}
}
handleIntent(context, intent);
}
private boolean isSystemAction(String action) {
return Intent.ACTION_SHUTDOWN.equals(action) ||
Intent.ACTION_BOOT_COMPLETED.equals(action) ||
Intent.ACTION_BATTERY_LOW.equals(action);
}
private boolean isFromSystem(Context context, Intent intent) {
// Implizite Broadcasts haben keine Component gesetzt
return intent.getComponent() == null;
}
}
// Korrigiert: LocalBroadcastManager für interne Broadcasts verwenden
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class FixedInternalCommunication {
private LocalBroadcastManager localBroadcastManager;
private BroadcastReceiver receiver;
public void setup(Context context) {
// Korrigiert: Lokale Broadcasts können nicht von anderen Apps empfangen werden
localBroadcastManager = LocalBroadcastManager.getInstance(context);
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Korrigiert: Empfängt nur Intents von innerhalb unserer App
handleInternalMessage(intent);
}
};
IntentFilter filter = new IntentFilter("com.myapp.INTERNAL_MESSAGE");
localBroadcastManager.registerReceiver(receiver, filter);
}
public void sendInternalBroadcast(Intent intent) {
// Korrigiert: Dieser Broadcast bleibt innerhalb der App
localBroadcastManager.sendBroadcast(intent);
}
public void cleanup() {
if (receiver != null) {
localBroadcastManager.unregisterReceiver(receiver);
}
}
}
// Korrigiert: Umfassende Intent-Validierung
public class FixedBatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Korrigiert: Mehrere Validierungsprüfungen
if (!validateIntent(context, intent)) {
Log.w(TAG, "Ungültiger Intent abgelehnt");
return;
}
String action = intent.getAction();
if (Intent.ACTION_BATTERY_LOW.equals(action)) {
// Zusätzliche Prüfung: Verifizieren, dass Batterie tatsächlich niedrig ist
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, filter);
if (batteryStatus != null) {
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level * 100 / (float) scale;
// Korrigiert: Nur reagieren, wenn Batterie tatsächlich niedrig ist
if (batteryPct < 15) {
enablePowerSavingMode(context);
}
}
}
}
private boolean validateIntent(Context context, Intent intent) {
// Prüfung 1: Muss impliziter Broadcast sein
if (intent.getComponent() != null) {
Log.w(TAG, "Ablehnung expliziten Intents");
return false;
}
// Prüfung 2: Verifizieren, dass Aktion erwartet wird
String action = intent.getAction();
if (!Intent.ACTION_BATTERY_LOW.equals(action) &&
!Intent.ACTION_BATTERY_OKAY.equals(action)) {
return false;
}
return true;
}
}
Verwandte CWEs
- CWE-940: Improper Verification of Source of a Communication Channel (Eltern)
- CWE-926: Improper Export of Android Application Components (verwandt)
- CWE-927: Use of Implicit Intent for Sensitive Communication (verwandt)
Referenzen
- MITRE Corporation. "CWE-925: Improper Verification of Intent by Broadcast Receiver." https://cwe.mitre.org/data/definitions/925.html
- Android Developers. "Broadcasts overview." https://developer.android.com/guide/components/broadcasts
- Android Developers. "Security tips." https://developer.android.com/training/articles/security-tips