[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 <alleteam@gmail.com>
This commit is contained in:
Astra 2023-06-09 15:41:40 +03:00 committed by GitHub
parent 2312fe5bfc
commit 4900e8b7a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 15 deletions

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,30.0,, Version,+,30.1,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,

1 entry status name type params
2 Version + 30.0 30.1
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,30.0,, Version,+,30.1,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.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,_Bool,"MfClassicDict*, uint8_t*"
Function,-,mf_classic_dict_is_key_present_str,_Bool,"MfClassicDict*, FuriString*" Function,-,mf_classic_dict_is_key_present_str,_Bool,"MfClassicDict*, FuriString*"
Function,-,mf_classic_dict_rewind,_Bool,MfClassicDict* 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_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_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*"
Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t

1 entry status name type params
2 Version + 30.0 30.1
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
1957 Function - mf_classic_dict_is_key_present _Bool MfClassicDict*, uint8_t*
1958 Function - mf_classic_dict_is_key_present_str _Bool MfClassicDict*, FuriString*
1959 Function - mf_classic_dict_rewind _Bool MfClassicDict*
1960 Function - mf_classic_emulator _Bool MfClassicEmulator*, FuriHalNfcTxRxContext* MfClassicEmulator*, FuriHalNfcTxRxContext*, _Bool
1961 Function - mf_classic_get_classic_type MfClassicType uint8_t, uint8_t, uint8_t
1962 Function - mf_classic_get_read_sectors_and_keys void MfClassicData*, uint8_t*, uint8_t*
1963 Function - mf_classic_get_sector_by_block uint8_t uint8_t

View File

@ -917,7 +917,8 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
if(mf_classic_authenticate_skip_activate( if(mf_classic_authenticate_skip_activate(
&tx_rx, block_num, key, MfClassicKeyA, !deactivated, cuid)) { &tx_rx, block_num, key, MfClassicKeyA, !deactivated, cuid)) {
mf_classic_set_key_found(data, i, MfClassicKeyA, key); 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); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
uint64_t found_key; uint64_t found_key;
@ -939,8 +940,14 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
deactivated = true; deactivated = true;
} else { } else {
// If the key A is marked as found and matches the searching key, invalidate it // 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) && 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); mf_classic_set_key_not_found(data, i, MfClassicKeyA);
is_key_a_found = false; is_key_a_found = false;
FURI_LOG_D(TAG, "Key %dA not found in attack", i); 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); is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB);
if(mf_classic_authenticate_skip_activate( if(mf_classic_authenticate_skip_activate(
&tx_rx, block_num, key, MfClassicKeyB, !deactivated, cuid)) { &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); mf_classic_set_key_found(data, i, MfClassicKeyB, key);
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); 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; deactivated = true;
} else { } else {
// If the key B is marked as found and matches the searching key, invalidate it // 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) && 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); mf_classic_set_key_not_found(data, i, MfClassicKeyB);
is_key_b_found = false; is_key_b_found = false;
FURI_LOG_D(TAG, "Key %dB not found in attack", i); 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); furi_hal_nfc_listen_start(nfc_data);
while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { //-V1044 while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { //-V1044
if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { 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) { if(emulator.data_changed) {
@ -1291,7 +1305,7 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) {
NfcProtocol protocol = NfcProtocol protocol =
reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8); reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8);
if(protocol == NfcDeviceProtocolMifareClassic) { if(protocol == NfcDeviceProtocolMifareClassic) {
mf_classic_emulator(&emulator, &tx_rx); mf_classic_emulator(&emulator, &tx_rx, true);
} }
} else { } else {
reader_no_data_received_cnt++; reader_no_data_received_cnt++;

View File

@ -845,7 +845,10 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data
return sectors_read; 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(emulator);
furi_assert(tx_rx); furi_assert(tx_rx);
bool command_processed = false; bool command_processed = false;
@ -892,11 +895,27 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
MfClassicSectorTrailer* sector_trailer = MfClassicSectorTrailer* sector_trailer =
(MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value;
if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) { if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) {
key = nfc_util_bytes2num(sector_trailer->key_a, 6); if(mf_classic_is_key_found(
access_key = MfClassicKeyA; &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 { } else {
key = nfc_util_bytes2num(sector_trailer->key_b, 6); if(mf_classic_is_key_found(
access_key = MfClassicKeyB; &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; uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA;

View File

@ -199,7 +199,10 @@ uint8_t mf_classic_read_card(
uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data); 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); void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto);