hf mf fchk: allow to crack a single key and show progress info

This commit is contained in:
Philippe Teuwen 2024-07-29 15:22:42 +02:00
parent 29c180285e
commit 98273d00ae
4 changed files with 95 additions and 15 deletions

View file

@ -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) {

View file

@ -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", "<fn>", "filename of dictionary"),
arg_int0(NULL, "blk", "<dec>", "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, "");

View file

@ -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

View file

@ -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);