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.

This commit is contained in:
iceman1001 2024-07-11 10:57:19 +02:00
commit 05b50a6c26
2 changed files with 17 additions and 11 deletions

View file

@ -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");
}