From 05b50a6c264d9a86a9e72f36e8aa53b2b0334bc5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 11 Jul 2024 10:57:19 +0200 Subject: [PATCH] fix #2418 - the tool mf_nonce_brute has in some odd cases when bruteforcing the last upper 16 bits a chance of actually decrypt the four bytes into a valid mifare classic protocol command with a valid ISO14443-a CRC. See github issue for example.\n We now bruteforce all 0xFFFF keyspace and keep track of how many candidates was found. The output has been improved to help user in this case too. --- CHANGELOG.md | 1 + tools/mf_nonce_brute/mf_nonce_brute.c | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98797cc01..cc47f0156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] +- Changed `mf_nonce_brute` tool to handle the odd case of multiple key candidates (@iceman1001) - Fixed a bad memory erase (@iceman1001) - Fixed BT serial comms (@iceman1001) - Changed `intertic.py` - updated and code clean up (@gentilkiwi) diff --git a/tools/mf_nonce_brute/mf_nonce_brute.c b/tools/mf_nonce_brute/mf_nonce_brute.c index 1c00f4eef..2e10ccbf1 100644 --- a/tools/mf_nonce_brute/mf_nonce_brute.c +++ b/tools/mf_nonce_brute/mf_nonce_brute.c @@ -560,9 +560,9 @@ static void *brute_thread(void *arguments) { pthread_mutex_unlock(&print_lock); free(revstate); continue; - } else { - printf("<-- " _GREEN_("valid cmd") "\n"); } + + printf("<-- " _GREEN_("valid cmd") "\n"); } lfsr_rollback_word(revstate, 0, 0); @@ -591,6 +591,7 @@ static void *brute_thread(void *arguments) { return NULL; } +// Bruteforce the upper 16 bits of the key static void *brute_key_thread(void *arguments) { struct thread_key_args *args = (struct thread_key_args *) arguments; @@ -600,10 +601,6 @@ static void *brute_key_thread(void *arguments) { for (uint64_t count = args->idx; count <= 0xFFFF; count += thread_count) { - if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) { - break; - } - key = args->part_key | (count << 32); // Init cipher with key @@ -628,15 +625,20 @@ static void *brute_key_thread(void *arguments) { continue; } - __sync_fetch_and_add(&global_found, 1); + __sync_fetch_and_add(&global_found_candidate, 1); // lock this section to avoid interlacing prints from different threats pthread_mutex_lock(&print_lock); printf("\nenc: %s\n", sprint_hex_inrow_ex(local_enc, args->enc_len, 0)); printf("dec: %s\n", sprint_hex_inrow_ex(dec, args->enc_len, 0)); - printf("\nValid Key found [ " _GREEN_("%012" PRIx64) " ]\n\n", key); + + if (key == global_candidate_key) { + printf("\nValid Key found [ " _GREEN_("%012" PRIx64) " ] - " _YELLOW_("matches candidate") "\n\n", key); + } else { + printf("\nValid Key found [ " _GREEN_("%012" PRIx64) " ]\n\n", key); + } + pthread_mutex_unlock(&print_lock); - break; } free(args); return NULL; @@ -797,12 +799,12 @@ int main(int argc, const char *argv[]) { } // reset thread signals - global_found = 0; global_found_candidate = 0; printf("\n----------- " _CYAN_("Phase 3 validating") " ----------------------------\n"); printf("uid.................. %08x\n", uid); printf("partial key.......... %08x\n", (uint32_t)(global_candidate_key & 0xFFFFFFFF)); + printf("possible key......... %012" PRIx64 "\n", global_candidate_key); printf("nt enc............... %08x\n", nt_enc); printf("nr enc............... %08x\n", nr_enc); printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc, enc_len, 0)); @@ -828,7 +830,10 @@ int main(int argc, const char *argv[]) { pthread_join(threads[i], NULL); } - if (!global_found && !global_found_candidate) { + if (global_found_candidate > 1) { + printf("\nOdd case but we found " _GREEN_("%d") " possible keys", global_found_candidate); + printf("\n" _YELLOW_("You need to test all of them manually, start with the one matching the candidate\n\n")); + } else { printf("\nfailed to find a key\n\n"); }