From 98273d00ae9071a7177b52f00e31a41b26938011 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 29 Jul 2024 15:22:42 +0200 Subject: [PATCH] hf mf fchk: allow to crack a single key and show progress info --- armsrc/mifarecmd.c | 35 +++++++++++++++++++++++++++ client/src/cmdhfmf.c | 43 +++++++++++++++++++++++++++------- client/src/mifare/mifarehost.c | 29 ++++++++++++++++++----- client/src/mifare/mifarehost.h | 3 +++ 4 files changed, 95 insertions(+), 15 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index cacbaac06..af8fa972a 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1557,10 +1557,14 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da uint8_t sectorcnt = arg0 & 0xFF; // 16; uint8_t firstchunk = (arg0 >> 8) & 0xF; uint8_t lastchunk = (arg0 >> 12) & 0xF; + uint16_t singleSectorParams = (arg0 >> 16) & 0xFFFF; uint8_t strategy = arg1 & 0xFF; uint8_t use_flashmem = (arg1 >> 8) & 0xFF; uint16_t keyCount = arg2 & 0xFF; uint8_t status = 0; + bool singleSectorMode = (singleSectorParams >> 15) & 1; + uint8_t keytype = (singleSectorParams >> 8) & 1; + uint8_t blockn = singleSectorParams & 0xFF; struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; @@ -1661,6 +1665,37 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da chk_data.pcs = pcs; chk_data.block = 0; + if (singleSectorMode) { + chk_data.block = blockn; + chk_data.keyType = keytype; + for (uint16_t i = 0; i < keyCount; ++i) { + + // Allow button press / usb cmd to interrupt device + if (BUTTON_PRESS() || data_available()) { + goto OUT; + } + + WDT_HIT(); + + chk_data.key = bytes_to_num(datain + i * 6, 6); + if (chkKey(&chk_data) == 0) { + reply_old(CMD_ACK, 1, 0, 0, datain + i * 6, 6); + goto out; + } + } + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); +out: + LEDsoff(); + crypto1_deinit(pcs); + set_tracing(false); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + BigBuf_free(); + BigBuf_Clear_ext(false); + g_dbglevel = oldbg; + return; + } + + // keychunk loop - depth first one sector. if (strategy == 1 || use_flashmem) { diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 7ac5f2340..ace8dd5c2 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -3241,6 +3241,9 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { arg_lit0(NULL, "dump", "Dump found keys to binary file"), arg_lit0(NULL, "mem", "Use dictionary from flashmemory"), arg_str0("f", "file", "", "filename of dictionary"), + arg_int0(NULL, "blk", "", "block number (single block recovery mode)"), + arg_lit0("a", NULL, "single block recovery key A"), + arg_lit0("b", NULL, "single block recovery key B"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -3262,6 +3265,16 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 9), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + int blockn = arg_get_int_def(ctx, 10, -1); + uint8_t keytype = MF_KEY_A; + if (arg_get_lit(ctx, 11) && arg_get_lit(ctx, 12)) { + CLIParserFree(ctx); + PrintAndLogEx(WARNING, "Input key type must be A or B"); + return PM3_EINVARG; + } else if (arg_get_lit(ctx, 12)) { + keytype = MF_KEY_B; + } + CLIParserFree(ctx); //validations @@ -3309,12 +3322,16 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { // time uint64_t t1 = msclock(); + uint16_t singleSectorParams = 0; + if (blockn != -1) { + singleSectorParams = (blockn & 0xFF)| keytype << 8 | 1 << 15; + } if (use_flashmemory) { PrintAndLogEx(SUCCESS, "Using dictionary in flash memory"); - mfCheckKeys_fast(sectorsCnt, true, true, 1, 0, keyBlock, e_sector, use_flashmemory, false); + mfCheckKeys_fast_ex(sectorsCnt, true, true, 1, 0, keyBlock, e_sector, use_flashmemory, false, false, singleSectorParams); } else { - // strategys. 1= deep first on sector 0 AB, 2= width first on all sectors + // strategies. 1= deep first on sector 0 AB, 2= width first on all sectors for (uint8_t strategy = 1; strategy < 3; strategy++) { PrintAndLogEx(INFO, "Running strategy %u", strategy); @@ -3322,33 +3339,41 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { for (i = 0; i < keycnt; i += chunksize) { if (kbd_enter_pressed()) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); goto out; } - + PrintAndLogEx(INPLACE, "Testing %5i/%5i %02.1f%%", i, keycnt, (float)i * 100 / keycnt); uint32_t size = ((keycnt - i) > chunksize) ? chunksize : keycnt - i; // last chunk? if (size == keycnt - i) lastChunk = true; - int res = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * MIFARE_KEY_SIZE), e_sector, false, false); - + int res = mfCheckKeys_fast_ex(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * MIFARE_KEY_SIZE), e_sector, false, false, true, singleSectorParams); if (firstChunk) firstChunk = false; // all keys, aborted - if (res == PM3_SUCCESS || res == 2) + if (res == PM3_SUCCESS || res == 2) { + PrintAndLogEx(NORMAL, ""); goto out; - + } } // end chunks of keys + PrintAndLogEx(INPLACE, "Testing %5i/%5i 100.00%%", keycnt, keycnt); + PrintAndLogEx(NORMAL, ""); firstChunk = true; lastChunk = false; + if (blockn != -1) break; } // end strategy } out: t1 = msclock() - t1; - PrintAndLogEx(INFO, "time in checkkeys (fast) " _YELLOW_("%.1fs") "\n", (float)(t1 / 1000.0)); + PrintAndLogEx(INFO, "Time in checkkeys (fast) " _YELLOW_("%.1fs") "\n", (float)(t1 / 1000.0)); + + if (blockn != -1) { + goto out2; + } // check.. uint8_t found_keys = 0; @@ -3413,7 +3438,7 @@ out: free(fptr); } } - +out2: free(keyBlock); free(e_sector); PrintAndLogEx(NORMAL, ""); diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index b08d7e430..40242f85a 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -221,21 +221,24 @@ int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keyc // 0 == ok all keys found // 1 == // 2 == Time-out, aborting -int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, - uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory, bool verbose) { +int mfCheckKeys_fast_ex(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, + uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory, + bool verbose, bool quiet, uint16_t singleSectorParams) { uint64_t t2 = msclock(); // send keychunk clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFARE_CHKKEYS_FAST, (sectorsCnt | (firstChunk << 8) | (lastChunk << 12)), ((use_flashmemory << 8) | strategy), size, keyBlock, 6 * size); + SendCommandOLD(CMD_HF_MIFARE_CHKKEYS_FAST, (sectorsCnt | (firstChunk << 8) | (lastChunk << 12) | (singleSectorParams << 16)), ((use_flashmemory << 8) | strategy), size, keyBlock, 6 * size); PacketResponseNG resp; uint32_t timeout = 0; while (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { - PrintAndLogEx((timeout) ? NORMAL : INFO, "." NOLF); - fflush(stdout); + if (! quiet) { + PrintAndLogEx((timeout) ? NORMAL : INFO, "." NOLF); + fflush(stdout); + } timeout++; @@ -249,13 +252,22 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, } t2 = msclock() - t2; - if (timeout) { + if (timeout && ! quiet) { PrintAndLogEx(NORMAL, ""); } // time to convert the returned data. uint8_t curr_keys = resp.oldarg[0]; + if ((singleSectorParams >> 15) & 1) { + if (curr_keys) { + uint64_t foo = bytes_to_num(resp.data.asBytes, 6); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("Key %s for block %2i found: %012" PRIx64), (singleSectorParams >> 8) & 1 ? "B":"A", singleSectorParams & 0xFF, foo); + return PM3_SUCCESS; + } + } + if (verbose) { PrintAndLogEx(INFO, "Chunk %.1fs | found %u/%u keys (%u)", (float)(t2 / 1000.0), curr_keys, (sectorsCnt << 1), size); } @@ -317,6 +329,11 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, return PM3_ESOFT; } +int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, + uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory, bool verbose) { + return mfCheckKeys_fast_ex(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock, e_sector, use_flashmemory, verbose, false, 0); +} + // Trigger device to use a binary file on flash mem as keylist for mfCheckKeys. // As of now, 255 keys possible in the file // 6 * 255 = 1500 bytes diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index 83a280d77..661cad078 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -76,6 +76,9 @@ int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keyc int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory, bool verbose); +int mfCheckKeys_fast_ex(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, + uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory, + bool verbose, bool quiet, uint16_t singleSectorParams); int mfCheckKeys_file(uint8_t *destfn, uint64_t *key);