flawopen.com/Teardowns/cve-2024-32896-android-factory-reset-wipe-bypass

● CVE-2024-32896 · CVSS 7.8 · Hoch
Sicherheitsforschung · FlawOpen

CVE-2024-32896: Android-Werksreset ließ sich unterbrechen, bevor die Schlüssel vernichtet waren

CVE-2024-32896 (CVSS 7.8, in begrenzten, gezielten Angriffen ausgenutzt): Ein Werksreset startete das Gerät nur in den Recovery-Modus neu und ließ die Verschlüsselungsschlüssel bis zur Löschung unangetastet. Wer das Telefon in der Hand hatte, konnte den Neustart unterbrechen und die Daten wiederherstellbar halten. Der Fix löscht vor dem Neustart alle Keystore-Schlüssel.

💡 Einfache Erklärung (ELI5)

Die Regel einer Firma für einen verlorenen Laptop lautet: ihm den Befehl „schreddern“ schicken. Der Laptop geht dann in den Schredderraum, wo alle Dateien vernichtet werden. Wer den Laptop festhält, kann aber unterwegs den Flur versperren – die Dateien kommen nirgends an und bleiben unversehrt. Die Lösung: Bevor er losgeht, verbrennt der Laptop die einzigen Schlüssel zu seinem verschlossenen Aktenschrank. Selbst wenn der Weg unterbrochen wird, kann niemand den Schrank je wieder öffnen.

Kernkonzepte & Begriffe

Werksreset (--wipe_data)
Eine Löschung, angestoßen vom Nutzer, einer Geräteadministrator- oder MDM-App oder einem Fernlöschdienst. RecoverySystemService.rebootRecoveryWithCommand() schreibt den Befehl --wipe_data für die Recovery und startet neu.
Bootloader-Steuerblock (BCB)
Eine kleine Partition (misc), in der Android Anweisungen für Bootloader und Recovery hinterlegt; geschrieben von setupOrClearBcb().
FBE und synthetisches Passwort
Dateibasierte Verschlüsselung. Die Schlüssel der Nutzerdaten leiten sich aus einem synthetischen Passwort ab, dessen Schutz-Blobs an KeyMint-Schlüssel gebunden sind; werden diese vernichtet, sind die Daten nicht mehr entschlüsselbar.
KeyMint / Keystore
Der hardwaregestützte Schlüsseldienst. AndroidKeyStoreMaintenance.deleteAllKeys() weist jedes KeyMint-Gerät an, alle seine Schlüssel zu löschen.

Ursachenanalyse

rebootRecoveryWithCommand() in RecoverySystemService.java behandelte --wipe_data, indem es den Befehl in den Bootloader-Steuerblock schrieb und neu startete – im Vertrauen darauf, dass die Recovery /data anschließend löscht. Bis diese Löschung fertig war, blieben die KeyMint-Schlüssel, die das synthetische Passwort sowie die DE- und Metadaten-Verschlüsselungsschlüssel schützen, intakt. Wer den Neustart unterbrach oder die Löschung verhinderte, ließ verschlüsselte Daten und Schlüssel an Ort und Stelle: ein Logikfehler in der Reihenfolge der Schritte. Der Fix (AOSP 8b7b2c66, Bug 324321147) ruft vor dem Neustart deleteSecrets() auf, das AndroidKeyStoreMaintenance.deleteAllKeys() ausführt. Er ist die Android-Framework-Hälfte des Pixel-Firmware-Fixes, der als CVE-2024-29748 geführt wird.

Schritt-für-Schritt Angriffsablauf

Schritt 1

Eine Löschung wird angefordert

Der Besitzer, eine Geräteadministrator- oder MDM-App oder ein Fernlöschdienst fordert den Werksreset an; er endet in rebootRecoveryWithCommand("--wipe_data ...").

Schritt 2

Neustart, ohne etwas zu vernichten

setupOrClearBcb() speichert den Befehl und pm.reboot(REBOOT_RECOVERY) startet das Telefon neu. Die Verschlüsselungsschlüssel sind zu diesem Zeitpunkt unberührt.

Schritt 3

Die Löschung wird unterbrochen

Wer das Gerät physisch besitzt, hält den Neustart vor der Recovery an, etwa durch Gedrückthalten von Leiser, um im Bootloader zu landen – die Löschung läuft nie.

Schritt 4

Die Daten überstehen den Reset

Die verschlüsselten Nutzerdaten und die Schlüssel, die sie schützen, bleiben auf dem Gerät. Es lässt sich später noch mit Forensik-Werkzeugen angreifen, statt leer zu sein.

Quellcode: Verwundbar vs. Sicher

VERWUNDBARE IMPLEMENTIERUNG
// services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@Override // Binder call
public void rebootRecoveryWithCommand(String command) {
    if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
    synchronized (sRequestLock) {
        if (!setupOrClearBcb(true, command)) {
            return;
        }

        // BUG: for "--wipe_data" nothing is destroyed yet. The keys that
        // protect the user's encrypted data survive until recovery runs the
        // wipe. If the reboot is interrupted or the wipe is skipped, the data
        // is still recoverable.
        PowerManager pm = mInjector.getPowerManager();
        pm.reboot(PowerManager.REBOOT_RECOVERY);
    }
}
GEHÄRTETER SICHERHEITS-PATCH
// services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
static final String RECOVERY_WIPE_DATA_COMMAND = "--wipe_data";

@Override // Binder call
public void rebootRecoveryWithCommand(String command) {
    if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");

    boolean isForcedWipe = command != null && command.contains(RECOVERY_WIPE_DATA_COMMAND);
    synchronized (sRequestLock) {
        if (!setupOrClearBcb(true, command)) {
            return;
        }

        // FIX: destroy the keys first. Deleting every KeyMint key (including
        // the synthetic-password protector keys and the keys protecting DE and
        // metadata encryption keys) makes FBE data unrecoverable even if the
        // wipe in recovery is interrupted or skipped.
        if (isForcedWipe) {
            deleteSecrets();
        }

        PowerManager pm = mInjector.getPowerManager();
        pm.reboot(PowerManager.REBOOT_RECOVERY);
    }
}

private static void deleteSecrets() {
    Slogf.w(TAG, "deleteSecrets");
    try {
        AndroidKeyStoreMaintenance.deleteAllKeys();
    } catch (android.security.KeyStoreException e) {
        Log.wtf(TAG, "Failed to delete all keys from keystore.", e);
    }
}

Checkliste für Engineering & Systemsicherheit

Quellen