flawopen.com/Teardowns/cve-2024-32896-android-factory-reset-wipe-bypass
CVE-2024-32896: Android Factory Reset Could Be Interrupted Before Keys Were Destroyed
CVE-2024-32896 (CVSS 7.8, exploited in limited, targeted attacks): a factory reset only rebooted into recovery and left the encryption keys in place until the wipe ran, so someone holding the phone could interrupt the reboot and keep the data recoverable. The fix deletes all Keystore keys before rebooting.
A company's rule for a lost laptop is to send it a "shred" order. The laptop then walks to the shredding room, where every file is destroyed. But someone holding the laptop can block the corridor on the way, and the files arrive nowhere and stay intact. The fix is that, before setting off, the laptop burns the only keys to its locked filing cabinet. Even if the walk is interrupted, nobody can ever open the cabinet again.
Core Concepts & Subsystem Terms
Factory reset (--wipe_data)- A wipe requested by the user, a device-admin or MDM app, or a remote-wipe service.
RecoverySystemServicewrites the.rebootRecoveryWithCommand()--wipe_datacommand for recovery and reboots. Bootloader control block (BCB)- A small partition (
misc) where Android leaves instructions for the bootloader and recovery, written bysetupOrClearBcb(). FBE and the synthetic password- File-based encryption. User data keys are derived from a synthetic password whose protector blobs are themselves bound to KeyMint keys, so destroying those keys makes the data undecryptable.
KeyMint / Keystore- The hardware-backed key service.
AndroidKeyStoreMaintenanceasks every KeyMint device to delete all of its keys..deleteAllKeys()
Root Cause Analysis
rebootRecoveryWithCommand() in RecoverySystemService.java handled --wipe_data by writing the command to the bootloader control block and rebooting, trusting recovery to erase /data afterwards. Until that erase finished, the KeyMint keys protecting the synthetic password and the DE and metadata encryption keys were intact. Interrupting the reboot, or preventing the wipe from running, left the encrypted data and its keys in place, a logic error in the order of operations. The fix (AOSP 8b7b2c66, bug 324321147) calls deleteSecrets(), which runs AndroidKeyStoreMaintenance, before the reboot. It is the Android framework half of the Pixel firmware fix tracked as .deleteAllKeys()CVE-2024-29748.
Step-by-Step Attack Flow
A wipe is requested
The owner, a device-admin or MDM app, or a remote-wipe service asks for a factory reset, which ends in rebootRecoveryWithCommand("--wipe_data ...").
Reboot without destroying anything
setupOrClearBcb() stores the command and pm.reboot(REBOOT_RECOVERY) restarts the phone. The encryption keys are untouched at this point.
The wipe is interrupted
Someone with physical possession stops the reboot short of recovery, for example by holding Volume Down to land in the bootloader, so the erase never runs.
Data survives the reset
The encrypted user data and the keys that protect it remain on the device, so it can still be attacked later with forensic tools instead of being gone.
Source Code: Flaw vs. Secure Implementation
// 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);
}
}
// 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);
}
}
Engineering & System Hardening Checklist
- ✓Keep devices at Android security patch level 2024-09-01 or later (Pixel: the June 2024 update or later), which include AOSP 8b7b2c66.
- ✓For any destructive wipe, destroy the key material first (crypto-shredding) and only then start the slow erase, so an interrupted erase leaves nothing usable.
- ✓Test wipe flows under interruption: power loss, forced bootloader entry and a skipped recovery step, and assert the data can no longer be decrypted afterwards.
- ✓In MDM runbooks, treat a wipe as complete only when the device confirms it or re-enrols clean, and alert when a wiped device reappears with its old state.
- ✓For devices holding sensitive data, require a strong lock-screen credential so that surviving encrypted data cannot be brute-forced if a wipe fails.