From bf7b91f45f684c58f573cf87483ebafa4a5df3be Mon Sep 17 00:00:00 2001 From: noproto Date: Wed, 23 Oct 2024 05:21:43 -0400 Subject: [PATCH 1/2] Fix typo --- lib/nfc/protocols/mf_classic/mf_classic_poller_i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index aac05748fd..deccdbcdad 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -5,7 +5,7 @@ #include -#define TAG "MfCLassicPoller" +#define TAG "MfClassicPoller" MfClassicError mf_classic_process_error(Iso14443_3aError error) { MfClassicError ret = MfClassicErrorNone; From 6dbb46a81d1de7aa0bc55775461ef747a3ab6964 Mon Sep 17 00:00:00 2001 From: noproto Date: Fri, 25 Oct 2024 18:38:11 -0400 Subject: [PATCH 2/2] Fix issue with resume logic --- applications/main/nfc/views/dict_attack.c | 2 ++ .../protocols/mf_classic/mf_classic_poller.c | 13 +++++++++---- .../protocols/mf_classic/mf_classic_poller.h | 17 +++++++++-------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index 4efbe6d604..726076972f 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -45,6 +45,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { furi_string_set(m->header, "PRNG Analysis"); break; case MfClassicNestedPhaseDictAttack: + case MfClassicNestedPhaseDictAttackVerify: case MfClassicNestedPhaseDictAttackResume: furi_string_set(m->header, "Nested Dictionary"); break; @@ -91,6 +92,7 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { float dict_progress = 0; if(m->nested_phase == MfClassicNestedPhaseAnalyzePRNG || m->nested_phase == MfClassicNestedPhaseDictAttack || + m->nested_phase == MfClassicNestedPhaseDictAttackVerify || m->nested_phase == MfClassicNestedPhaseDictAttackResume) { // Phase: Nested dictionary attack uint8_t target_sector = diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 8d58658652..edfdb2a959 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -1881,9 +1881,10 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance uint16_t dict_target_key_max = (dict_attack_ctx->prng_type == MfClassicPrngTypeWeak) ? (instance->sectors_total * 2) : (instance->sectors_total * 16); - if(dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttackResume) { + if(dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttackVerify) { if(!(mf_classic_nested_is_target_key_found(instance, true)) && (dict_attack_ctx->nested_nonce.count > 0)) { + dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttackResume; instance->state = MfClassicPollerStateNestedDictAttack; return command; } else { @@ -1898,7 +1899,8 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttack; } } - if((dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttack) && + if((dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttack || + dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttackResume) && (dict_attack_ctx->nested_target_key < dict_target_key_max)) { bool is_last_iter_for_hard_key = ((!is_weak) && ((dict_attack_ctx->nested_target_key % 8) == 7)); @@ -1922,11 +1924,14 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance NULL; } if((is_weak || is_last_iter_for_hard_key) && dict_attack_ctx->nested_nonce.count > 0) { - // Key reuse - dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttackResume; + // Key verify and reuse + dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttackVerify; dict_attack_ctx->auth_passed = false; instance->state = MfClassicPollerStateKeyReuseStartNoOffset; return command; + } else if(dict_attack_ctx->nested_phase == MfClassicNestedPhaseDictAttackResume) { + dict_attack_ctx->nested_phase = MfClassicNestedPhaseDictAttack; + dict_attack_ctx->auth_passed = true; } if(!(dict_attack_ctx->auth_passed)) { dict_attack_ctx->attempt_count++; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 7dfd3b6ab1..8efb931aae 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -52,14 +52,15 @@ typedef enum { * @brief MfClassic poller nested attack phase. */ typedef enum { - MfClassicNestedPhaseNone, - MfClassicNestedPhaseAnalyzePRNG, - MfClassicNestedPhaseDictAttack, - MfClassicNestedPhaseDictAttackResume, - MfClassicNestedPhaseCalibrate, - MfClassicNestedPhaseRecalibrate, - MfClassicNestedPhaseCollectNtEnc, - MfClassicNestedPhaseFinished, + MfClassicNestedPhaseNone, /**< No nested attack has taken place yet. */ + MfClassicNestedPhaseAnalyzePRNG, /**< Analyze nonces produced by the PRNG to determine if they fit a weak PRNG */ + MfClassicNestedPhaseDictAttack, /**< Search keys which match the expected PRNG properties and parity for collected nonces */ + MfClassicNestedPhaseDictAttackVerify, /**< Verify candidate keys by authenticating to the sector with the key */ + MfClassicNestedPhaseDictAttackResume, /**< Resume nested dictionary attack from the last tested (invalid) key */ + MfClassicNestedPhaseCalibrate, /**< Perform necessary calculations to recover the plaintext nonce during later collection phase (weak PRNG tags only) */ + MfClassicNestedPhaseRecalibrate, /**< Collect the next plaintext static encrypted nonce for backdoor static encrypted nonce nested attack */ + MfClassicNestedPhaseCollectNtEnc, /**< Log nonces collected during nested authentication for key recovery */ + MfClassicNestedPhaseFinished, /**< Nested attack has finished */ } MfClassicNestedPhase; /**