flawopen.com/Teardowns/cve-2024-32896-android-factory-reset-wipe-bypass
CVE-2024-32896: Android 초기화를 키가 파기되기 전에 중단할 수 있었던 문제
CVE-2024-32896(CVSS 7.8, 제한적 표적 공격에 악용): 초기화는 recovery로 재부팅만 하고 삭제가 실행될 때까지 암호화 키를 그대로 두었기 때문에, 휴대폰을 손에 쥔 사람이 재부팅을 중단해 데이터를 복구 가능한 상태로 남길 수 있었습니다. 수정본은 재부팅 전에 Keystore 키를 모두 삭제합니다.
어떤 회사는 분실한 노트북에 "파쇄" 명령을 보내는 것이 규칙입니다. 그러면 노트북은 파쇄실로 걸어가고, 그곳에서 모든 파일이 폐기됩니다. 하지만 노트북을 붙잡고 있는 사람이 가는 길에 복도를 막아 버리면 파일은 어디에도 도착하지 못하고 그대로 남습니다. 해결책은 출발하기 전에 노트북이 잠긴 서류함의 하나뿐인 열쇠를 태워 버리는 것입니다. 도중에 막히더라도 그 서류함은 누구도 다시 열 수 없습니다.
핵심 개념 및 용어
초기화(--wipe_data)- 사용자, 기기 관리자 앱이나 MDM 앱, 원격 삭제 서비스가 요청하는 삭제입니다.
RecoverySystemService가 recovery용.rebootRecoveryWithCommand()--wipe_data명령을 쓰고 재부팅합니다. 부트로더 제어 블록(BCB)- Android가 부트로더와 recovery에게 지시를 남기는 작은 파티션(
misc)으로,setupOrClearBcb()가 기록합니다. FBE와 합성 비밀번호- 파일 기반 암호화입니다. 사용자 데이터 키는 합성 비밀번호에서 파생되고, 그 보호 블롭은 KeyMint 키에 묶여 있으므로 그 키를 파기하면 데이터를 복호화할 수 없습니다.
KeyMint / Keystore- 하드웨어 기반 키 서비스입니다.
AndroidKeyStoreMaintenance는 모든 KeyMint 기기에 모든 키를 삭제하라고 요청합니다..deleteAllKeys()
근본 원인 분석 (Root Cause)
RecoverySystemService.java의 rebootRecoveryWithCommand()는 --wipe_data를 처리할 때 명령을 부트로더 제어 블록에 쓰고 재부팅만 한 뒤, 이후 recovery가 /data를 지워 줄 것이라고 믿었습니다. 삭제가 끝날 때까지 합성 비밀번호를 보호하는 KeyMint 키와 DE·메타데이터 암호화 키는 멀쩡했습니다. 재부팅을 중단하거나 삭제가 실행되지 못하게 하면 암호화된 데이터와 키가 모두 그대로 남았습니다. 작업 순서의 논리 오류입니다. 수정본(AOSP 8b7b2c66, 버그 324321147)은 재부팅 전에 deleteSecrets()를 호출해 AndroidKeyStoreMaintenance를 실행합니다. 이는 CVE-2024-29748로 추적되는 Pixel 펌웨어 수정의 Android 프레임워크 쪽 절반입니다..deleteAllKeys()
단계별 공격 실행 흐름
삭제 요청
소유자, 기기 관리자 앱이나 MDM 앱, 원격 삭제 서비스가 초기화를 요청하고, 이는 결국 rebootRecoveryWithCommand("--wipe_data ...") 호출로 이어집니다.
아무것도 파기하지 않고 재부팅
setupOrClearBcb()가 명령을 저장하고 pm.reboot(REBOOT_RECOVERY)가 휴대폰을 재부팅합니다. 이 시점에 암호화 키는 손대지 않은 상태입니다.
삭제가 중단됨
기기를 물리적으로 가진 사람이 recovery에 들어가기 전에 재부팅을 멈춥니다. 예를 들어 볼륨 낮추기 버튼을 누른 채로 부트로더에 들어가면 삭제는 한 번도 실행되지 않습니다.
데이터가 초기화를 견딤
암호화된 사용자 데이터와 이를 보호하는 키가 기기에 남아 있어, 깨끗해지는 대신 나중에도 포렌식 도구로 공격할 수 있는 상태가 됩니다.
소스 코드 비교: 취약한 구현 vs 보안 패치
// 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);
}
}
엔지니어링 및 시스템 보안 강화 체크리스트
- ✓기기를 Android 보안 패치 수준 2024-09-01 이상(Pixel은 2024년 6월 업데이트 이상)으로 유지하세요. 둘 다 AOSP 8b7b2c66을 포함합니다.
- ✓파괴적인 삭제에서는 먼저 키 자료를 파기하고(크립토 슈레딩) 그다음에 느린 삭제를 시작해, 삭제가 중단되더라도 쓸 만한 것이 남지 않게 하세요.
- ✓정전, 부트로더 강제 진입, recovery 단계 생략 같은 중단 상황에서 삭제 흐름을 테스트하고, 이후 데이터를 복호화할 수 없는지 확인하세요.
- ✓MDM 운영 절차에서는 기기가 완료를 확인하거나 깨끗한 상태로 재등록했을 때만 삭제 완료로 보고, 삭제된 기기가 예전 상태로 다시 나타나면 경보를 울리세요.
- ✓민감한 데이터를 담은 기기에는 강력한 화면 잠금 자격 증명을 요구해, 삭제 실패 후 남은 암호화 데이터가 무차별 대입으로 뚫리지 않게 하세요.