From 4900e8b7a2f416c106fe09567cbbfcf1b0d18e70 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Fri, 9 Jun 2023 15:41:40 +0300 Subject: [PATCH] [FL-3284] Fix reading Mifare Classic cards with unusual access conditions and fix emulation of unknown keys (#2620) * I was outplayed by the C programming language * Fix emulating empty keys as 0s * Add exceptions for Detect Reader * Sync api_symbols.csv for F18 * Outplayed by the C language [X2] Co-authored-by: Aleksandr Kutuzov --- firmware/targets/f18/api_symbols.csv | 2 +- firmware/targets/f7/api_symbols.csv | 4 ++-- lib/nfc/nfc_worker.c | 26 +++++++++++++++++++------ lib/nfc/protocols/mifare_classic.c | 29 +++++++++++++++++++++++----- lib/nfc/protocols/mifare_classic.h | 5 ++++- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 85f09f1c3ca..d429de655a2 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,30.0,, +Version,+,30.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index afa76163272..80b4eedbdc4 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,30.0,, +Version,+,30.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1957,7 +1957,7 @@ Function,-,mf_classic_dict_get_total_keys,uint32_t,MfClassicDict* Function,-,mf_classic_dict_is_key_present,_Bool,"MfClassicDict*, uint8_t*" Function,-,mf_classic_dict_is_key_present_str,_Bool,"MfClassicDict*, FuriString*" Function,-,mf_classic_dict_rewind,_Bool,MfClassicDict* -Function,-,mf_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*" +Function,-,mf_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*, _Bool" Function,-,mf_classic_get_classic_type,MfClassicType,"uint8_t, uint8_t, uint8_t" Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 974bb0a4d19..a6bb93f59ef 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -917,7 +917,8 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { if(mf_classic_authenticate_skip_activate( &tx_rx, block_num, key, MfClassicKeyA, !deactivated, cuid)) { mf_classic_set_key_found(data, i, MfClassicKeyA, key); - FURI_LOG_D(TAG, "Key A found"); + FURI_LOG_D( + TAG, "Key A found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); uint64_t found_key; @@ -939,8 +940,14 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { deactivated = true; } else { // If the key A is marked as found and matches the searching key, invalidate it + uint8_t found_key[6]; + memcpy(found_key, data->block[i].value, 6); + + uint8_t current_key[6]; + memcpy(current_key, &key, 6); + if(mf_classic_is_key_found(data, i, MfClassicKeyA) && - data->block[i].value[0] == key) { + memcmp(found_key, current_key, 6) == 0) { mf_classic_set_key_not_found(data, i, MfClassicKeyA); is_key_a_found = false; FURI_LOG_D(TAG, "Key %dA not found in attack", i); @@ -950,7 +957,8 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); if(mf_classic_authenticate_skip_activate( &tx_rx, block_num, key, MfClassicKeyB, !deactivated, cuid)) { - FURI_LOG_D(TAG, "Key B found"); + FURI_LOG_D( + TAG, "Key B found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); mf_classic_set_key_found(data, i, MfClassicKeyB, key); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); @@ -958,8 +966,14 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { deactivated = true; } else { // If the key B is marked as found and matches the searching key, invalidate it + uint8_t found_key[6]; + memcpy(found_key, data->block[i].value + 10, 6); + + uint8_t current_key[6]; + memcpy(current_key, &key, 6); + if(mf_classic_is_key_found(data, i, MfClassicKeyB) && - data->block[i].value[10] == key) { + memcmp(found_key, current_key, 6) == 0) { mf_classic_set_key_not_found(data, i, MfClassicKeyB); is_key_b_found = false; FURI_LOG_D(TAG, "Key %dB not found in attack", i); @@ -1004,7 +1018,7 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { furi_hal_nfc_listen_start(nfc_data); while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { //-V1044 if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { - mf_classic_emulator(&emulator, &tx_rx); + mf_classic_emulator(&emulator, &tx_rx, false); } } if(emulator.data_changed) { @@ -1291,7 +1305,7 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) { NfcProtocol protocol = reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8); if(protocol == NfcDeviceProtocolMifareClassic) { - mf_classic_emulator(&emulator, &tx_rx); + mf_classic_emulator(&emulator, &tx_rx, true); } } else { reader_no_data_received_cnt++; diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index d2d7467dce0..ebe49a4a0e0 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -845,7 +845,10 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data return sectors_read; } -bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx) { +bool mf_classic_emulator( + MfClassicEmulator* emulator, + FuriHalNfcTxRxContext* tx_rx, + bool is_reader_analyzer) { furi_assert(emulator); furi_assert(tx_rx); bool command_processed = false; @@ -892,11 +895,27 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ MfClassicSectorTrailer* sector_trailer = (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) { - key = nfc_util_bytes2num(sector_trailer->key_a, 6); - access_key = MfClassicKeyA; + if(mf_classic_is_key_found( + &emulator->data, mf_classic_get_sector_by_block(block), MfClassicKeyA) || + is_reader_analyzer) { + key = nfc_util_bytes2num(sector_trailer->key_a, 6); + access_key = MfClassicKeyA; + } else { + FURI_LOG_D(TAG, "Key not known"); + command_processed = true; + break; + } } else { - key = nfc_util_bytes2num(sector_trailer->key_b, 6); - access_key = MfClassicKeyB; + if(mf_classic_is_key_found( + &emulator->data, mf_classic_get_sector_by_block(block), MfClassicKeyB) || + is_reader_analyzer) { + key = nfc_util_bytes2num(sector_trailer->key_b, 6); + access_key = MfClassicKeyB; + } else { + FURI_LOG_D(TAG, "Key not known"); + command_processed = true; + break; + } } uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA; diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index c03350f2e93..b3e3cbdf80d 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -199,7 +199,10 @@ uint8_t mf_classic_read_card( uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data); -bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); +bool mf_classic_emulator( + MfClassicEmulator* emulator, + FuriHalNfcTxRxContext* tx_rx, + bool is_reader_analyzer); void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto);