From 3b91624ea6f36091b21ce89b3737332aaae802aa Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 16 Oct 2024 01:43:46 +0200 Subject: [PATCH] Mifare1ksim logic closer to SimulateIso14443aTag and keep running when using mfkey32v2 --- armsrc/iso14443a.c | 2 +- armsrc/mifaresim.c | 94 +++++++++++++++++++++---------------------- client/src/cmdhf14a.c | 13 ------ client/src/cmdhfmf.c | 65 ++++++++++++++++++------------ 4 files changed, 86 insertions(+), 88 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 23d1d91c3..b89a9728f 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1432,7 +1432,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, uint8 //----------------------------------------------------------------------------- void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_t exitAfterNReads, uint8_t *iRATs) { -#define ATTACK_KEY_COUNT 8 // keep same as define in cmdhfmf.c -> readerAttack() +#define ATTACK_KEY_COUNT 16 tag_response_info_t *responses; uint32_t cuid = 0; diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index ca93a59f4..00d3119c3 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -496,7 +496,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 uint8_t rats_len = 0; - // if fct is called with NULL we need to assign some memory since this pointer is passaed around + // if fct is called with NULL we need to assign some memory since this pointer is passed around uint8_t datain_tmp[10] = {0}; if (datain == NULL) { datain = datain_tmp; @@ -505,14 +505,11 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 // This will be used in the reader-only attack. - //allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys -#define ATTACK_KEY_COUNT 7 // keep same as define in cmdhfmf.c -> readerAttack() (Cannot be more than 7) - nonces_t ar_nr_resp[ATTACK_KEY_COUNT * 2]; // *2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes + //allow collecting up to 16 sets of nonces to allow recovery of up to 16 keys +#define ATTACK_KEY_COUNT 16 + nonces_t ar_nr_resp[ATTACK_KEY_COUNT]; // for moebius attack type memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); - uint8_t ar_nr_collected[ATTACK_KEY_COUNT ]; // for moebius attack type - memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); - // Authenticate response - nonce uint8_t rAUTH_NT[4] = {0, 0, 0, 1}; uint8_t rAUTH_NT_keystream[4]; @@ -547,7 +544,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 WDT_HIT(); - if (counter == 3000) { + if (counter == 1000) { if (data_available()) { Dbprintf("----------- " _GREEN_("BREAKING") " ----------"); break; @@ -1151,36 +1148,33 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) { for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { - if (ar_nr_collected[i] == 0 || + if (ar_nr_resp[i].state == EMPTY || ( + (ar_nr_resp[i].state != EMPTY) && (cardAUTHSC == ar_nr_resp[i].sector) && - (cardAUTHKEY == ar_nr_resp[i].keytype) && - (ar_nr_collected[i] > 0) + (cardAUTHKEY == ar_nr_resp[i].keytype) ) ) { // if first auth for sector, or matches sector and keytype of previous auth - if (ar_nr_collected[i] < 2) { + if (ar_nr_resp[i].state != SECOND) { // if we haven't already collected 2 nonces for this sector - if (ar_nr_resp[ar_nr_collected[i]].ar != ar) { - // Avoid duplicates... probably not necessary, ar should vary. - if (ar_nr_collected[i] == 0) { - // first nonce collect - ar_nr_resp[i].cuid = cuid; - ar_nr_resp[i].sector = cardAUTHSC; - ar_nr_resp[i].keytype = cardAUTHKEY; - ar_nr_resp[i].nonce = nonce; - ar_nr_resp[i].nr = nr; - ar_nr_resp[i].ar = ar; - ar_nr_collected[i]++; - } else { // second nonce collect - // make sure we have different nonces for moebius attack - if (ar_nr_resp[i].nonce != nonce) { - ar_nr_resp[i].nonce2 = nonce; - ar_nr_resp[i].nr2 = nr; - ar_nr_resp[i].ar2 = ar; - ar_nr_collected[i]++; - finished = true; - } + if (ar_nr_resp[i].state == EMPTY) { + // first nonce collect + ar_nr_resp[i].cuid = cuid; + ar_nr_resp[i].sector = cardAUTHSC; + ar_nr_resp[i].keytype = cardAUTHKEY; + ar_nr_resp[i].nonce = nonce; + ar_nr_resp[i].nr = nr; + ar_nr_resp[i].ar = ar; + ar_nr_resp[i].state = FIRST; + } else { // second nonce collect + // make sure we have different nonces for moebius attack + if (ar_nr_resp[i].nonce != nonce) { + ar_nr_resp[i].nonce2 = nonce; + ar_nr_resp[i].nr2 = nr; + ar_nr_resp[i].ar2 = ar; + ar_nr_resp[i].state = SECOND; + finished = true; } } } @@ -1326,22 +1320,26 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 FpgaDisableTracing(); // NR AR ATTACK - if (((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) && (g_dbglevel >= DBG_INFO)) { + uint8_t index = 0; + if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) { 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 sector %d " _YELLOW_("%s") - , ar_nr_resp[i].sector - , (ar_nr_resp[i].keytype == AUTHKEYA) ? "key A" : "key B" - ); - Dbprintf("../tools/mfc/card_reader/mfkey32v2 %08x %08x %08x %08x %08x %08x %08x", - ar_nr_resp[i].cuid, //UID - ar_nr_resp[i].nonce, //NT - ar_nr_resp[i].nr, //NR1 - ar_nr_resp[i].ar, //AR1 - ar_nr_resp[i].nonce2,//NT2 - ar_nr_resp[i].nr2, //NR2 - ar_nr_resp[i].ar2 //AR2 - ); + if (ar_nr_resp[i].state == SECOND) { + index = i; + if (g_dbglevel >= DBG_INFO) { + Dbprintf("Collected two pairs of AR/NR which can be used to extract sector %d " _YELLOW_("%s") + , ar_nr_resp[i].sector + , (ar_nr_resp[i].keytype == AUTHKEYA) ? "key A" : "key B" + ); + Dbprintf("../tools/mfc/card_reader/mfkey32v2 %08x %08x %08x %08x %08x %08x %08x", + ar_nr_resp[i].cuid, //UID + ar_nr_resp[i].nonce, //NT + ar_nr_resp[i].nr, //NR1 + ar_nr_resp[i].ar, //AR1 + ar_nr_resp[i].nonce2,//NT2 + ar_nr_resp[i].nr2, //NR2 + ar_nr_resp[i].ar2 //AR2 + ); + } } } } @@ -1351,7 +1349,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 if ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK //Send the collected ar_nr in the response - reply_mix(CMD_ACK, CMD_HF_MIFARE_SIMULATE, button_pushed, 0, &ar_nr_resp, sizeof(ar_nr_resp)); + reply_ng(CMD_HF_MIFARE_SIMULATE, button_pushed ? PM3_EOPABORTED : PM3_SUCCESS, (uint8_t *)&ar_nr_resp[index], sizeof(nonces_t)); } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 45d801c6a..b6c19d0f1 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -912,11 +912,6 @@ int CmdHF14ASim(const char *Cmd) { // inform device to break the sim loop since client has exited SendCommandNG(CMD_BREAK_LOOP, NULL, 0); } - - if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) { - //iceman: readerAttack call frees k_sector , this call is useless. - showSectorTable(k_sector, k_sectors_cnt); - } } PrintAndLogEx(INFO, "Done!"); @@ -3799,9 +3794,6 @@ int CmdHF14AAIDSim(const char *Cmd) { SendCommandNG(CMD_HF_ISO14443A_SIM_AID, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp = {0}; - sector_t *k_sector = NULL; - size_t k_sectors_cnt = MIFARE_4K_MAXSECTOR; - PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation"); bool keypress = kbd_enter_pressed(); while (keypress == false) { @@ -3823,11 +3815,6 @@ int CmdHF14AAIDSim(const char *Cmd) { // inform device to break the sim loop since client has exited SendCommandNG(CMD_BREAK_LOOP, NULL, 0); } - - if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) { - //iceman: readerAttack call frees k_sector , this call is useless. - showSectorTable(k_sector, k_sectors_cnt); - } } diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 0670bfe84..00cd80eef 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -4251,36 +4251,49 @@ static int CmdHF14AMfSim(const char *Cmd) { payload.sak = sak[0]; clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_SIMULATE, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; if (flags & FLAG_INTERACTIVE) { - PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or send another cmd to abort simulation"); - - sector_t *k_sector = NULL; - - while (kbd_enter_pressed() == 0) { - - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) - continue; - - if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) - break; - - if ((resp.oldarg[0] & 0xffff) != CMD_HF_MIFARE_SIMULATE) - break; - - nonces_t data[1]; - memcpy(data, resp.data.asBytes, sizeof(data)); - readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose); - break; - } - //iceman: readerAttack call frees k_sector. this call below is useless. - showSectorTable(k_sector, k_sectors_cnt); - + PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or a key to abort simulation"); } else { - PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation"); + PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or send another cmd to abort simulation"); } + bool cont; + do { + cont = false; + SendCommandNG(CMD_HF_MIFARE_SIMULATE, (uint8_t *)&payload, sizeof(payload)); + if (flags & FLAG_INTERACTIVE) { + PacketResponseNG resp; + sector_t *k_sector = NULL; + + bool keypress = kbd_enter_pressed(); + while (keypress == false) { + + if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) { + keypress = kbd_enter_pressed(); + continue; + } + + if (resp.status != PM3_SUCCESS) + break; + + if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) + break; + + const nonces_t *data = (nonces_t *)resp.data.asBytes; + readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose); + cont = true; + break; + } + if (keypress) { + if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) { + // inform device to break the sim loop since client has exited + PrintAndLogEx(INFO, "Key pressed, please wait a few seconds for the pm3 to stop..."); + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + } + } + } + + } while (cont); return PM3_SUCCESS; }