From: marshmellow42 Date: Wed, 22 Jun 2016 15:03:37 +0000 (-0400) Subject: improve hf mf sim x reader attack X-Git-Tag: v3.0.0~87^2~8 X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/79dcb9e0900d51edf30d8cf863aca7be2f257ff4 improve hf mf sim x reader attack can now directly extract multiple keys for multiple sectors --- diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 11e02c7a..928c50c4 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -12,6 +12,8 @@ #ifndef __BIGBUF_H #define __BIGBUF_H +#include // for bool +#include "common.h" // for ramfunc #define BIGBUF_SIZE 40000 #define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 27574dad..4f0a990f 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2307,6 +2307,18 @@ void ReaderMifare(bool first_try) set_tracing(FALSE); } +typedef struct { + uint32_t cuid; + uint8_t sector; + uint8_t keytype; + uint32_t nonce; + uint32_t ar; + uint32_t nr; + uint32_t nonce2; + uint32_t ar2; + uint32_t nr2; +} nonces_t; + /** *MIFARE 1K simulate. * @@ -2353,12 +2365,18 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; - //Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2 + //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 // This can be used in a reader-only attack. // (it can also be retrieved via 'hf 14a list', but hey... - uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0}; - uint8_t ar_nr_collected = 0; - + + //allow collecting up to 4 sets of nonces to allow recovery of 4 keys (2 keyA & 2 keyB) + // must be set in multiples of 2 (for 1 keyA and 1 keyB) + #define ATTACK_KEY_COUNT 4 + nonces_t ar_nr_resp[ATTACK_KEY_COUNT]; + memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); + + uint8_t ar_nr_collected[ATTACK_KEY_COUNT]; + memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); // Authenticate response - nonce uint32_t nonce = bytes_to_num(rAUTH_NT, 4); @@ -2506,16 +2524,35 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint32_t ar = bytes_to_num(receivedCmd, 4); uint32_t nr = bytes_to_num(&receivedCmd[4], 4); - - //Collect AR/NR - if(ar_nr_collected < 2){ - if(ar_nr_responses[2] != ar) - {// Avoid duplicates... probably not necessary, ar should vary. - ar_nr_responses[ar_nr_collected*4] = cuid; - ar_nr_responses[ar_nr_collected*4+1] = nonce; - ar_nr_responses[ar_nr_collected*4+2] = ar; - ar_nr_responses[ar_nr_collected*4+3] = nr; - ar_nr_collected++; + + //Collect AR/NR per key/sector + if(flags & FLAG_NR_AR_ATTACK) { + for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if(cardAUTHKEY > 0 && i < (ATTACK_KEY_COUNT/2) ) { + i=ATTACK_KEY_COUNT/2; //keyB skip to keyB + } else if (cardAUTHKEY == 0 && i == ATTACK_KEY_COUNT/2) { + break; //should not get here - quit + } + // if first auth for sector, or matches sector of previous auth + if ( ar_nr_collected[i]==0 || (cardAUTHSC == ar_nr_resp[i].sector && ar_nr_collected[i] > 0) ) { + if(ar_nr_collected[i] < 2) { + if(ar_nr_resp[ar_nr_collected[i]].ar != ar) + {// Avoid duplicates... probably not necessary, ar should vary. + if (ar_nr_collected[i]==0) { + ar_nr_resp[i].cuid = cuid; + ar_nr_resp[i].sector = cardAUTHSC; + ar_nr_resp[i].nonce = nonce; + ar_nr_resp[i].ar = ar; + ar_nr_resp[i].nr = nr; + } else { + ar_nr_resp[i].ar2 = ar; + ar_nr_resp[i].nr2 = nr; + } + ar_nr_collected[i]++; + break; + } + } + } } } @@ -2537,6 +2574,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } + //auth successful ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); num_to_bytes(ans, 4, rAUTH_AT); @@ -2780,37 +2818,29 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK - { - //May just aswell send the collected ar_nr in the response aswell - cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4); - } - - if(flags & FLAG_NR_AR_ATTACK) + if(flags & 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/mfkey32 %08x %08x %08x %08x %08x %08x", - ar_nr_responses[0], // UID - ar_nr_responses[1], //NT - ar_nr_responses[2], //AR1 - ar_nr_responses[3], //NR1 - ar_nr_responses[6], //AR2 - ar_nr_responses[7] //NR2 - ); - } else { - Dbprintf("Failed to obtain two AR/NR pairs!"); - if(ar_nr_collected >0) { - Dbprintf("Only got these: UID=%08x, nonce=%08x, AR1=%08x, NR1=%08x", - ar_nr_responses[0], // UID - ar_nr_responses[1], //NT - ar_nr_responses[2], //AR1 - ar_nr_responses[3] //NR1 + 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()); + + if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK + { + //May just aswell send the collected ar_nr in the response aswell + cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_resp,sizeof(ar_nr_resp)); + } } diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 48e78b1c..df504416 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" +#include "./nonce2key/nonce2key.h" static int CmdHelp(const char *Cmd); @@ -28,7 +29,7 @@ int CmdHF14AMifare(const char *Cmd) printf("-------------------------------------------------------------------------\n"); -start: + start: clearCommandBuffer(); SendCommand(&c); @@ -1079,6 +1080,64 @@ int CmdHF14AMf1kSim(const char *Cmd) //We're waiting only 1.5 s at a time, otherwise we get the // annoying message about "Waiting for a response... " } + //got a response + if (flags & FLAG_NR_AR_ATTACK) { + typedef struct { + uint32_t cuid; + uint8_t sector; + uint8_t keytype; + uint32_t nonce; + uint32_t ar; + uint32_t nr; + uint32_t nonce2; + uint32_t ar2; + uint32_t nr2; + } nonces_t; + nonces_t ar_resp[4]; + //uint32_t ar_responses[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint64_t key = 0; + //uint64_t keyB = 0; + //uint8_t arnr_len = 8; + memcpy (ar_resp, resp.d.asBytes, sizeof(ar_resp)); + + for (uint8_t i = 0; i<4; i++) { + if (ar_resp[i].ar2 > 0) { + key = mfkey32(ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); + if (key>0) { + PrintAndLog("\nFound Key%s for sector %d: [%04x%08x]", (i<2) ? "A" : "B", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + //set emulator memory for key + } + } + } + /* + if (ar_resp[1] && ar_responses[2] && ar_responses[3] && ar_responses[6] && ar_responses[7]) { + keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]); + if (keyA>0) { + PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF)); + //set emulator memory for key + } else { + keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]); + if (keyA>0) { + PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF)); + //set emulator memory for key + } + } + } else { + PrintAndLog("keyA response error: %d %d %d %d %d",ar_responses[1] , ar_responses[2] , ar_responses[3] , ar_responses[6] , ar_responses[7]); + } + if (ar_responses[1] && ar_responses[2+arnr_len] && ar_responses[3+arnr_len] && ar_responses[6+arnr_len] && ar_responses[7+arnr_len]) { + keyB = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2+arnr_len],ar_responses[3+arnr_len],ar_responses[6+arnr_len],ar_responses[7+arnr_len]); + if (keyB>0) { + PrintAndLog("\nFound KeyB: [%04x%08x]\n\n", (uint32_t) (keyB>>32), (uint32_t) (keyB & 0xFFFFFFFF)); + //set emulator memory for key + } + } + if (keyA || keyB) { + //TODO retry sim with new keys in emulator memory? (somehow flag to check that to see if new key has successful auth now?) + // to validate key is correct + } + */ + } } return 0;