From 4be9e793421828516579b152bac716b961dd55f7 Mon Sep 17 00:00:00 2001 From: noproto Date: Thu, 17 Oct 2024 19:16:30 -0400 Subject: [PATCH] Fix multiple crashes and state machine logic --- .../protocols/mf_classic/mf_classic_poller.c | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 7417322e9..963bdeec5 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -8,7 +8,6 @@ // TODO: Buffer writes for Hardnested, set state to Log when finished and sum property matches // TODO: Store target key in CUID dictionary -// TODO: Fix rare nested_target_key 64 bug // TODO: Dead code for malloc returning NULL? // TODO: Auth1 static encrypted exists (rare) @@ -1663,7 +1662,7 @@ NfcCommand mf_classic_poller_handler_nested_dict_attack(MfClassicPoller* instanc "Found key candidate %06llx", bit_lib_bytes_to_num_be(key_candidate->data, sizeof(MfClassicKey))); dict_attack_ctx->current_key = *key_candidate; - dict_attack_ctx->reuse_key_sector = (target_block / 4); + dict_attack_ctx->reuse_key_sector = target_sector; dict_attack_ctx->current_key_type = target_key_type; free(key_candidate); break; @@ -2004,9 +2003,7 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance } uint16_t nonce_collect_key_max; if(dict_attack_ctx->prng_type == MfClassicPrngTypeWeak) { - nonce_collect_key_max = dict_attack_ctx->static_encrypted ? - ((instance->sectors_total * 4) - 2) : - (instance->sectors_total * 4); + nonce_collect_key_max = instance->sectors_total * 4; } else { nonce_collect_key_max = instance->sectors_total * 2; } @@ -2047,30 +2044,6 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance dict_attack_ctx->attempt_count = 0; } dict_attack_ctx->auth_passed = true; - if(!(dict_attack_ctx->current_key_checked)) { - dict_attack_ctx->current_key_checked = true; - - // Check if the nested target key is a known key - if(mf_classic_nested_is_target_key_found(instance, false)) { - // Continue to next key - if(!(dict_attack_ctx->static_encrypted)) { - dict_attack_ctx->nested_target_key++; - dict_attack_ctx->current_key_checked = false; - } - instance->state = MfClassicPollerStateNestedController; - return command; - } - - // If it is not a known key, we'll need to calibrate for static encrypted backdoored tags - if((dict_attack_ctx->backdoor == MfClassicBackdoorAuth3) && - (dict_attack_ctx->nested_target_key < nonce_collect_key_max) && - !(recalibrated)) { - dict_attack_ctx->calibrated = false; - dict_attack_ctx->nested_phase = MfClassicNestedPhaseRecalibrate; - instance->state = MfClassicPollerStateNestedController; - return command; - } - } // If we have tried to collect this nonce too many times, skip if((is_weak && (dict_attack_ctx->attempt_count >= MF_CLASSIC_NESTED_RETRY_MAXIMUM)) || @@ -2096,12 +2069,52 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance dict_attack_ctx->attempt_count = 0; } + FURI_LOG_D( + TAG, + "Nested target key: %u (max: %u)", + dict_attack_ctx->nested_target_key, + nonce_collect_key_max); + + if(!(dict_attack_ctx->current_key_checked)) { + if(dict_attack_ctx->nested_target_key == nonce_collect_key_max) { + // All nonces have been collected + FURI_LOG_D(TAG, "All nonces collected"); + instance->state = MfClassicPollerStateNestedController; + return command; + } + + dict_attack_ctx->current_key_checked = true; + + // Check if the nested target key is a known key + if(mf_classic_nested_is_target_key_found(instance, false)) { + // Continue to next key + if(!(dict_attack_ctx->static_encrypted)) { + dict_attack_ctx->nested_target_key++; + dict_attack_ctx->current_key_checked = false; + } + instance->state = MfClassicPollerStateNestedController; + return command; + } + + // If it is not a known key, we'll need to calibrate for static encrypted backdoored tags + if((dict_attack_ctx->backdoor == MfClassicBackdoorAuth3) && + (dict_attack_ctx->nested_target_key < nonce_collect_key_max) && + !(recalibrated)) { + dict_attack_ctx->calibrated = false; + dict_attack_ctx->nested_phase = MfClassicNestedPhaseRecalibrate; + instance->state = MfClassicPollerStateNestedController; + return command; + } + } + FURI_LOG_T(TAG, "Collecting a nonce"); + // Collect a nonce dict_attack_ctx->auth_passed = false; instance->state = MfClassicPollerStateNestedCollectNtEnc; return command; } } + dict_attack_ctx->nested_target_key = 0; dict_attack_ctx->nested_phase = MfClassicNestedPhaseFinished; instance->state = MfClassicPollerStateSuccess; return command;