From b6e05350b2826c6d43fd8e7363de8a1eeef149a6 Mon Sep 17 00:00:00 2001 From: Michael Farrell Date: Sat, 22 Oct 2016 21:47:26 +1100 Subject: [PATCH] hf mf sim: Multiple fixes (iceman1001/proxmark3 #45) - Fix `hf mf sim` to use nonce_t structures, so key recovery works - Increases verbosity on the key recovery functionality - Fix use-after-free for k_sector - Add help info on `e` option to `hf mf sim` --- armsrc/iso14443a.c | 149 ++++++++++++++++++++++++++++------- client/cmdhfmf.c | 47 ++++++++--- client/nonce2key/nonce2key.c | 24 ++++++ 3 files changed, 180 insertions(+), 40 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 61c018bb..570f028c 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2484,12 +2484,20 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // Here, we collect CUID, NT, NR, AR, CUID2, NT2, NR2, AR2 // This can be used in a reader-only attack. - uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0,0}; - uint8_t ar_nr_collected = 0; + nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; // for 2 separate attack types (nml, moebius) + memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); + + uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; // for 2nd attack type (moebius) + memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); + uint8_t nonce1_count = 0; + uint8_t nonce2_count = 0; + uint8_t moebius_n_count = 0; + bool gettingMoebius = false; + uint8_t mM = 0; // moebius_modifier for collection storage + bool doBufResetNext = false; // Authenticate response - nonce uint32_t nonce = bytes_to_num(rAUTH_NT, 4); - ar_nr_responses[1] = nonce; // -- Determine the UID // Can be set from emulator memory or incoming data @@ -2515,7 +2523,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * case 4: sak_4[0] &= 0xFB; // save CUID - ar_nr_responses[0] = cuid = bytes_to_num(rUIDBCC1, 4); + cuid = bytes_to_num(rUIDBCC1, 4); // BCC rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; if (MF_DBGLEVEL >= 2) { @@ -2531,7 +2539,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * atqa[0] |= 0x40; sak_7[0] &= 0xFB; // save CUID - ar_nr_responses[0] = cuid = bytes_to_num(rUIDBCC2, 4); + cuid = bytes_to_num(rUIDBCC2, 4); // CascadeTag, CT rUIDBCC1[0] = 0x88; // BCC @@ -2553,7 +2561,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * atqa[0] |= 0x80; sak_10[0] &= 0xFB; // save CUID - ar_nr_responses[0] = cuid = bytes_to_num(rUIDBCC3, 4); + cuid = bytes_to_num(rUIDBCC3, 4); // CascadeTag, CT rUIDBCC1[0] = 0x88; rUIDBCC2[0] = 0x88; @@ -2731,6 +2739,81 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint32_t nr = bytes_to_num(receivedCmd, 4); uint32_t ar = bytes_to_num(&receivedCmd[4], 4); + if (doBufResetNext) { + // Reset, lets try again! + Dbprintf("Re-read after previous NR_AR_ATTACK, resetting buffer"); + memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); + memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); + mM = 0; + doBufResetNext = false; + } + + for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if ( ar_nr_collected[i+mM]==0 || ((cardAUTHSC == ar_nr_resp[i+mM].sector) && (cardAUTHKEY == ar_nr_resp[i+mM].keytype) && (ar_nr_collected[i+mM] > 0)) ) { + + // if first auth for sector, or matches sector and keytype of previous auth + if (ar_nr_collected[i+mM] < 2) { + // if we haven't already collected 2 nonces for this sector + if (ar_nr_resp[ar_nr_collected[i+mM]].ar != ar) { + // Avoid duplicates... probably not necessary, ar should vary. + if (ar_nr_collected[i+mM]==0) { + // first nonce collect + ar_nr_resp[i+mM].cuid = cuid; + ar_nr_resp[i+mM].sector = cardAUTHSC; + ar_nr_resp[i+mM].keytype = cardAUTHKEY; + ar_nr_resp[i+mM].nonce = nonce; + ar_nr_resp[i+mM].nr = nr; + ar_nr_resp[i+mM].ar = ar; + nonce1_count++; + // add this nonce to first moebius nonce + ar_nr_resp[i+ATTACK_KEY_COUNT].cuid = cuid; + ar_nr_resp[i+ATTACK_KEY_COUNT].sector = cardAUTHSC; + ar_nr_resp[i+ATTACK_KEY_COUNT].keytype = cardAUTHKEY; + ar_nr_resp[i+ATTACK_KEY_COUNT].nonce = nonce; + ar_nr_resp[i+ATTACK_KEY_COUNT].nr = nr; + ar_nr_resp[i+ATTACK_KEY_COUNT].ar = ar; + ar_nr_collected[i+ATTACK_KEY_COUNT]++; + } else { // second nonce collect (std and moebius) + ar_nr_resp[i+mM].nonce2 = nonce; + ar_nr_resp[i+mM].nr2 = nr; + ar_nr_resp[i+mM].ar2 = ar; + if (!gettingMoebius) { + nonce2_count++; + // check if this was the last second nonce we need for std attack + if ( nonce2_count == nonce1_count ) { + // done collecting std test switch to moebius + // first finish incrementing last sample + ar_nr_collected[i+mM]++; + // switch to moebius collection + gettingMoebius = true; + mM = ATTACK_KEY_COUNT; + break; + } + } else { + moebius_n_count++; + // if we've collected all the nonces we need - finish. + + if (nonce1_count == moebius_n_count) { + cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_resp,sizeof(ar_nr_resp)); + nonce1_count = 0; + nonce2_count = 0; + moebius_n_count = 0; + gettingMoebius = false; + doBufResetNext = true; + finished = ( ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE)); + } + } + } + ar_nr_collected[i+mM]++; + } + } + // we found right spot for this nonce stop looking + break; + } + } + + + /* // Collect AR/NR // if(ar_nr_collected < 2 && cardAUTHSC == 2){ if(ar_nr_collected < 2) { @@ -2745,7 +2828,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // Interactive mode flag, means we need to send ACK finished = ( ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE)&& ar_nr_collected == 2); } - /* + crypto1_word(pcs, ar , 1); cardRr = nr ^ crypto1_word(pcs, 0, 0); @@ -2980,37 +3063,45 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } // Interactive mode flag, means we need to send ACK + /* if((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) { // May just aswell send the collected ar_nr in the response aswell uint8_t len = ar_nr_collected * 4 * 4; cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, len, 0, &ar_nr_responses, len); } - + + */ if( ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK ) && MF_DBGLEVEL >= 1 ) { - if(ar_nr_collected > 1 ) { - Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:"); - Dbprintf("../tools/mfkey/mfkey32v2.exe %08x %08x %08x %08x %08x %08x %08x", - ar_nr_responses[0], // CUID - ar_nr_responses[1], // NT1 - ar_nr_responses[2], // NR1 - ar_nr_responses[3], // AR1 - // ar_nr_responses[4], // CUID2 - ar_nr_responses[5], // NT2 - ar_nr_responses[6], // NR2 - ar_nr_responses[7] // AR2 - ); - } else { - Dbprintf("Failed to obtain two AR/NR pairs!"); - if(ar_nr_collected == 1 ) { - Dbprintf("Only got these: UID=%08x, nonce=%08x, NR1=%08x, AR1=%08x", - ar_nr_responses[0], // CUID - ar_nr_responses[1], // NT - ar_nr_responses[2], // NR1 - ar_nr_responses[3] // AR1 - ); + for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if (ar_nr_collected[i] == 2) { + Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index dc8f7898..99a91ced 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -31,6 +31,7 @@ int usage_hf14_mf1ksim(void){ PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); + PrintAndLog(" e (Optional) Fill simulator keys from what we crack"); PrintAndLog("samples:"); PrintAndLog(" hf mf sim u 0a0a0a0a"); PrintAndLog(" hf mf sim u 11223344556677"); @@ -1384,7 +1385,9 @@ void readerAttack(nonces_t data[], bool setEmulatorMem) { printf("enter reader attack\n"); for (uint8_t i = 0; i < ATTACK_KEY_COUNT; ++i) { if (data[i].ar2 > 0) { - + + // We can probably skip this, mfkey32v2 is more reliable. +#ifdef HFMF_TRYMFK32 if (tryMfk32(data[i], &key)) { PrintAndLog("Found Key%s for sector %02d: [%012"llx"]" , (data[i].keytype) ? "B" : "A" @@ -1400,22 +1403,43 @@ void readerAttack(nonces_t data[], bool setEmulatorMem) { uint8_t memBlock[16] = {0,0,0,0,0,0, 0xff, 0x0F, 0x80, 0x69, 0,0,0,0,0,0}; num_to_bytes( k_sector[i].Key[0], 6, memBlock); num_to_bytes( k_sector[i].Key[1], 6, memBlock+10); - mfEmlSetMem( memBlock, i*4 + 3, 1); PrintAndLog("Setting Emulator Memory Block %02d: [%s]" - , i*4 + 3 + , ((data[i].sector)*4) + 3 , sprint_hex( memBlock, sizeof(memBlock)) ); + mfEmlSetMem( memBlock, ((data[i].sector)*4) + 3, 1); } - break; + continue; } +#endif //moebius attack - // if (tryMfk32_moebius(data[i+ATTACK_KEY_COUNT], &key)) { - // PrintAndLog("M-Found Key%s for sector %02d: [%012"llx"]" - // ,(data[i+ATTACK_KEY_COUNT].keytype) ? "B" : "A" - // , data[i+ATTACK_KEY_COUNT].sector - // , key - // ); - // } + if (tryMfk32_moebius(data[i+ATTACK_KEY_COUNT], &key)) { + uint8_t sectorNum = data[i+ATTACK_KEY_COUNT].sector; + uint8_t keyType = data[i+ATTACK_KEY_COUNT].keytype; + + PrintAndLog("M-Found Key%s for sector %02d: [%012"llx"]" + , keyType ? "B" : "A" + , sectorNum + , key + ); + + k_sector[sectorNum].Key[keyType] = key; + k_sector[sectorNum].foundKey[keyType] = TRUE; + + //set emulator memory for keys + if (setEmulatorMem) { + uint8_t memBlock[16] = {0,0,0,0,0,0, 0xff, 0x0F, 0x80, 0x69, 0,0,0,0,0,0}; + num_to_bytes( k_sector[sectorNum].Key[0], 6, memBlock); + num_to_bytes( k_sector[sectorNum].Key[1], 6, memBlock+10); + PrintAndLog("Setting Emulator Memory Block %02d: [%s]" + , (sectorNum*4) + 3 + , sprint_hex( memBlock, sizeof(memBlock)) + ); + mfEmlSetMem( memBlock, (sectorNum*4) + 3, 1); + } + continue; + } + } } } @@ -1506,6 +1530,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { if (k_sector != NULL) { printKeyTable(k_sectorsCount, k_sector ); free(k_sector); + k_sector = NULL; } } return 0; diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c index 048d2adf..14b03bcb 100644 --- a/client/nonce2key/nonce2key.c +++ b/client/nonce2key/nonce2key.c @@ -170,7 +170,18 @@ bool tryMfk32(nonces_t data, uint64_t *outputkey) { bool isSuccess = FALSE; uint8_t counter = 0; + printf("Recovering key for:\n"); + printf(" uid: %08x\n",uid); + printf(" nt: %08x\n",nt); + printf(" {nr_0}: %08x\n",nr0_enc); + printf(" {ar_0}: %08x\n",ar0_enc); + printf(" {nr_1}: %08x\n",nr1_enc); + printf(" {ar_1}: %08x\n",ar1_enc); + + printf("\nLFSR succesors of the tag challenge:\n"); uint32_t p64 = prng_successor(nt, 64); + printf(" nt': %08x\n", p64); + printf(" nt'': %08x\n", prng_successor(p64, 32)); s = lfsr_recovery32(ar0_enc ^ p64, 0); @@ -212,12 +223,25 @@ bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) { bool isSuccess = FALSE; int counter = 0; + printf("Recovering key for:\n"); + printf(" uid: %08x\n",uid); + printf(" nt_0: %08x\n",nt0); + printf(" {nr_0}: %08x\n",nr0_enc); + printf(" {ar_0}: %08x\n",ar0_enc); + printf(" nt_1: %08x\n",nt1); + printf(" {nr_1}: %08x\n",nr1_enc); + printf(" {ar_1}: %08x\n",ar1_enc); + //PrintAndLog("Enter mfkey32_moebius"); clock_t t1 = clock(); + printf("\nLFSR succesors of the tag challenge:\n"); uint32_t p640 = prng_successor(nt0, 64); uint32_t p641 = prng_successor(nt1, 64); + printf(" nt': %08x\n", p640); + printf(" nt'': %08x\n", prng_successor(p640, 32)); + s = lfsr_recovery32(ar0_enc ^ p640, 0); for(t = s; t->odd | t->even; ++t) { -- 2.39.2