Skip to content

Commit

Permalink
[FL-3284] Fix reading Mifare Classic cards with unusual access condit…
Browse files Browse the repository at this point in the history
…ions 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 <[email protected]>
  • Loading branch information
Astrrra and skotopes authored Jun 9, 2023
1 parent 2312fe5 commit 4900e8b
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 15 deletions.
2 changes: 1 addition & 1 deletion firmware/targets/f18/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -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,,
Expand Down
4 changes: 2 additions & 2 deletions firmware/targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -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,,
Expand Down Expand Up @@ -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
Expand Down
26 changes: 20 additions & 6 deletions lib/nfc/nfc_worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -950,16 +957,23 @@ 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);
}
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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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++;
Expand Down
29 changes: 24 additions & 5 deletions lib/nfc/protocols/mifare_classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion lib/nfc/protocols/mifare_classic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 4900e8b

Please sign in to comment.