adapt text out for hf mf info

This commit is contained in:
iceman1001 2023-12-11 23:37:05 +01:00
commit c533d3aba8
3 changed files with 89 additions and 65 deletions

View file

@ -1767,7 +1767,7 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't
} }
PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt); PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt);
int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, use_flashmemory); int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, use_flashmemory, false);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Fast check found all keys"); PrintAndLogEx(SUCCESS, "Fast check found all keys");
goto jumptoend; goto jumptoend;
@ -1809,7 +1809,7 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't
e_sector[sectorNo].foundKey[trgKeyType] = 1; e_sector[sectorNo].foundKey[trgKeyType] = 1;
e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6); e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false); mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false);
continue; continue;
default : default :
PrintAndLogEx(ERR, "Unknown error\n"); PrintAndLogEx(ERR, "Unknown error\n");
@ -2023,7 +2023,7 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
} }
PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt); PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt);
int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false); int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false, false);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
// all keys found // all keys found
PrintAndLogEx(SUCCESS, "Fast check found all keys"); PrintAndLogEx(SUCCESS, "Fast check found all keys");
@ -2056,7 +2056,7 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
e_sector[sectorNo].foundKey[trgKeyType] = 1; e_sector[sectorNo].foundKey[trgKeyType] = 1;
e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6); e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
// mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false); // mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false);
continue; continue;
default : default :
PrintAndLogEx(ERR, "unknown error.\n"); PrintAndLogEx(ERR, "unknown error.\n");
@ -2713,7 +2713,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
lastChunk = true; lastChunk = true;
} }
res = mfCheckKeys_fast(sector_cnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * MIFARE_KEY_SIZE), e_sector, false); res = mfCheckKeys_fast(sector_cnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * MIFARE_KEY_SIZE), e_sector, false, verbose);
if (firstChunk) { if (firstChunk) {
firstChunk = false; firstChunk = false;
} }
@ -2834,7 +2834,7 @@ noValidKeyFound:
// Try the found keys are reused // Try the found keys are reused
if (bytes_to_num(tmp_key, MIFARE_KEY_SIZE) != 0) { if (bytes_to_num(tmp_key, MIFARE_KEY_SIZE) != 0) {
// <!> The fast check --> mfCheckKeys_fast(sector_cnt, true, true, 2, 1, tmp_key, e_sector, false); // <!> The fast check --> mfCheckKeys_fast(sector_cnt, true, true, 2, 1, tmp_key, e_sector, false, verbose);
// <!> Returns false keys, so we just stick to the slower mfchk. // <!> Returns false keys, so we just stick to the slower mfchk.
for (int i = 0; i < sector_cnt; i++) { for (int i = 0; i < sector_cnt; i++) {
for (int j = MF_KEY_A; j <= MF_KEY_B; j++) { for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
@ -3259,7 +3259,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
if (use_flashmemory) { if (use_flashmemory) {
PrintAndLogEx(SUCCESS, "Using dictionary in flash memory"); PrintAndLogEx(SUCCESS, "Using dictionary in flash memory");
mfCheckKeys_fast(sectorsCnt, true, true, 1, 0, keyBlock, e_sector, use_flashmemory); mfCheckKeys_fast(sectorsCnt, true, true, 1, 0, keyBlock, e_sector, use_flashmemory, false);
} else { } else {
// strategys. 1= deep first on sector 0 AB, 2= width first on all sectors // strategys. 1= deep first on sector 0 AB, 2= width first on all sectors
@ -3280,7 +3280,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
if (size == keycnt - i) if (size == keycnt - i)
lastChunk = true; lastChunk = true;
int res = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * MIFARE_KEY_SIZE), e_sector, false); int res = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * MIFARE_KEY_SIZE), e_sector, false, false);
if (firstChunk) if (firstChunk)
firstChunk = false; firstChunk = false;
@ -8799,9 +8799,11 @@ static int CmdHFMFHidEncode(const char *Cmd) {
static int CmdHF14AMfInfo(const char *Cmd) { static int CmdHF14AMfInfo(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf info", CLIParserInit(&ctx, "hf mf info",
"Information and check vulnerabilities in the mfc card\n" "Information and check vulnerabilities in a MIFARE Classic card\n"
"To check some of them need to specify key and/or specific keys in the copmmand line", "Some cards in order to extract information you need to specify key\n"
"hf mf info -k ffffffff -nv\n" "and/or specific keys in the copmmand line",
"hf mf info\n"
"hf mf info -k ffffffff -n -v\n"
); );
void *argtable[] = { void *argtable[] = {
@ -8828,7 +8830,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
} }
int keylen = 0; int keylen = 0;
uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t key[MIFARE_KEY_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
CLIGetHexWithReturn(ctx, 4, key, &keylen); CLIGetHexWithReturn(ctx, 4, key, &keylen);
bool do_nack_test = arg_get_lit(ctx, 5); bool do_nack_test = arg_get_lit(ctx, 5);
@ -8836,11 +8838,12 @@ static int CmdHF14AMfInfo(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
uint8_t dbg_curr = DBG_NONE; uint8_t dbg_curr = DBG_NONE;
if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) {
return PM3_EFAILED; return PM3_EFAILED;
}
if (keylen != 0 && keylen != 6) { if (keylen != 0 && keylen != MIFARE_KEY_SIZE) {
PrintAndLogEx(ERR, "Key length must be 6 bytes"); PrintAndLogEx(ERR, "Key length must be %u bytes", MIFARE_KEY_SIZE);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -8878,26 +8881,37 @@ static int CmdHF14AMfInfo(const char *Cmd) {
return select_status; return select_status;
} }
PrintAndLogEx(INFO, "--- " _CYAN_("ISO14443-a Information") "---------------------"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("ISO14443-a Information") " ---------------------");
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]);
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]); PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
if (setDeviceDebugLevel(verbose ? DBG_INFO : DBG_NONE, false) != PM3_SUCCESS) if (setDeviceDebugLevel(verbose ? DBG_INFO : DBG_NONE, false) != PM3_SUCCESS) {
return PM3_EFAILED; return PM3_EFAILED;
}
PrintAndLogEx(INFO, "--- " _CYAN_("Backdoors Information") "---------------------"); uint8_t signature[32] = {0};
if (detect_mf_magic(true) == 0) int res = read_mfc_ev1_signature(signature);
PrintAndLogEx(INFO, "<none>"); if (res == PM3_SUCCESS) {
mfc_ev1_print_signature(card.uid, card.uidlen, signature, sizeof(signature));
}
PrintAndLogEx(INFO, "--- " _CYAN_("Keys Information") "---------------------"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Magic Tag Information"));
if (detect_mf_magic(true) == 0) {
PrintAndLogEx(INFO, "<N/A>");
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Keys Information"));
uint8_t fkey[MIFARE_KEY_SIZE] = {0}; uint8_t fkey[MIFARE_KEY_SIZE] = {0};
uint8_t fKeyType = 0xff; uint8_t fKeyType = 0xff;
int sectorsCnt = 1; int sectorsCnt = 1;
uint8_t *keyBlock = NULL; uint8_t *keyBlock = NULL;
uint32_t keycnt = 0; uint32_t keycnt = 0;
int res = mfLoadKeys(&keyBlock, &keycnt, NULL, 0, NULL, 0); res = mfLoadKeys(&keyBlock, &keycnt, NULL, 0, NULL, 0);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
return res; return res;
} }
@ -8908,89 +8922,95 @@ static int CmdHF14AMfInfo(const char *Cmd) {
free(keyBlock); free(keyBlock);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
res = mfCheckKeys_fast(sectorsCnt, true, true, 1, keycnt, keyBlock, e_sector, false);
res = mfCheckKeys_fast(sectorsCnt, true, true, 1, keycnt, keyBlock, e_sector, false, verbose);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
uint8_t blockdata[MFBLOCK_SIZE] = {0}; uint8_t blockdata[MFBLOCK_SIZE] = {0};
if (e_sector[0].foundKey[0]) { if (e_sector[0].foundKey[0]) {
PrintAndLogEx(SUCCESS, "Sector 0 key A... %12llx", e_sector[0].Key[0]); PrintAndLogEx(SUCCESS, "Sector 0 key A... " _GREEN_("%12" PRIX64), e_sector[0].Key[0]);
num_to_bytes(e_sector[0].Key[0], MIFARE_KEY_SIZE, fkey); num_to_bytes(e_sector[0].Key[MF_KEY_A], MIFARE_KEY_SIZE, fkey);
if (mfReadBlock(0, MF_KEY_A, key, blockdata) == PM3_SUCCESS) if (mfReadBlock(0, MF_KEY_A, key, blockdata) == PM3_SUCCESS) {
fKeyType = MF_KEY_A; fKeyType = MF_KEY_A;
}
if (e_sector[0].foundKey[1]) {
PrintAndLogEx(SUCCESS, "Sector 0 key B... %12llx", e_sector[0].Key[1]);
if (fKeyType == 0xff) {
num_to_bytes(e_sector[0].Key[1], MIFARE_KEY_SIZE, fkey);
if (mfReadBlock(0, MF_KEY_B, key, blockdata) == PM3_SUCCESS)
fKeyType = MF_KEY_B;
} }
} }
if (fKeyType != 0xff) if (e_sector[0].foundKey[1]) {
PrintAndLogEx(SUCCESS, "Sector 0 key B... " _GREEN_("%12" PRIX64), e_sector[0].Key[1]);
if (fKeyType == 0xFF) {
num_to_bytes(e_sector[0].Key[MF_KEY_B], MIFARE_KEY_SIZE, fkey);
if (mfReadBlock(0, MF_KEY_B, key, blockdata) == PM3_SUCCESS) {
fKeyType = MF_KEY_B;
}
}
}
if (fKeyType != 0xFF) {
PrintAndLogEx(SUCCESS, "Block 0.......... %s", sprint_hex(blockdata, MFBLOCK_SIZE)); PrintAndLogEx(SUCCESS, "Block 0.......... %s", sprint_hex(blockdata, MFBLOCK_SIZE));
}
} else {
PrintAndLogEx(INFO, "<N/A>");
} }
free(keyBlock); free(keyBlock);
free(e_sector); free(e_sector);
PrintAndLogEx(INFO, "--- " _CYAN_("RNG Information") "---------------------"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("RNG Information"));
res = detect_classic_static_nonce(); res = detect_classic_static_nonce();
if (res == NONCE_STATIC) if (res == NONCE_STATIC) {
PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes")); PrintAndLogEx(SUCCESS, "Static nonce... " _YELLOW_("yes"));
}
if (res == NONCE_FAIL && verbose) if (res == NONCE_FAIL && verbose) {
PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("read failed")); PrintAndLogEx(SUCCESS, "Static nonce... " _RED_("read failed"));
}
if (res == NONCE_NORMAL) { if (res == NONCE_NORMAL) {
// not static // not static
res = detect_classic_prng(); res = detect_classic_prng();
if (res == 1) if (res == 1)
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak")); PrintAndLogEx(SUCCESS, "Prng... " _GREEN_("weak"));
else if (res == 0) else if (res == 0)
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard")); PrintAndLogEx(SUCCESS, "Prng... " _YELLOW_("hard"));
else else
PrintAndLogEx(FAILED, "Prng detection: " _RED_("fail")); PrintAndLogEx(FAILED, "Prng... " _RED_("fail"));
// detect static encrypted nonce // detect static encrypted nonce
if (keylen == 6) { if (keylen == MIFARE_KEY_SIZE) {
res = detect_classic_static_encrypted_nonce(blockn, keytype, key); res = detect_classic_static_encrypted_nonce(blockn, keytype, key);
if (res == NONCE_STATIC) { if (res == NONCE_STATIC) {
PrintAndLogEx(SUCCESS, "Static nested nonce: " _YELLOW_("yes")); PrintAndLogEx(SUCCESS, "Static nested nonce... " _YELLOW_("yes"));
fKeyType = 0xff; // dont detect twice fKeyType = 0xFF; // dont detect twice
} }
if (res == NONCE_STATIC_ENC) { if (res == NONCE_STATIC_ENC) {
PrintAndLogEx(SUCCESS, "Static encrypted nonce: " _YELLOW_("yes")); PrintAndLogEx(SUCCESS, "Static encrypted nonce... " _RED_("yes"));
fKeyType = 0xff; // dont detect twice fKeyType = 0xFF; // dont detect twice
} }
} }
if (fKeyType != 0xff) {
if (fKeyType != 0xFF) {
res = detect_classic_static_encrypted_nonce(0, fKeyType, fkey); res = detect_classic_static_encrypted_nonce(0, fKeyType, fkey);
if (res == NONCE_STATIC) if (res == NONCE_STATIC)
PrintAndLogEx(SUCCESS, "Static nested nonce: " _YELLOW_("yes")); PrintAndLogEx(SUCCESS, "Static nested nonce... " _YELLOW_("yes"));
if (res == NONCE_STATIC_ENC) if (res == NONCE_STATIC_ENC)
PrintAndLogEx(SUCCESS, "Static encrypted nonce: " _YELLOW_("yes")); PrintAndLogEx(SUCCESS, "Static encrypted nonce... " _RED_("yes"));
} }
if (do_nack_test) if (do_nack_test) {
detect_classic_nackbug(verbose); detect_classic_nackbug(verbose);
}
} }
uint8_t signature[32] = {0}; if (setDeviceDebugLevel(dbg_curr, false) != PM3_SUCCESS) {
res = read_mfc_ev1_signature(signature);
if (res == PM3_SUCCESS) {
PrintAndLogEx(INFO, "--- " _CYAN_("Signature Information") "---------------------");
mfc_ev1_print_signature(card.uid, card.uidlen, signature, sizeof(signature));
}
if (setDeviceDebugLevel(dbg_curr, false) != PM3_SUCCESS)
return PM3_EFAILED; return PM3_EFAILED;
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -222,7 +222,7 @@ int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keyc
// 1 == // 1 ==
// 2 == Time-out, aborting // 2 == Time-out, aborting
int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, 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) { uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory, bool verbose) {
uint64_t t2 = msclock(); uint64_t t2 = msclock();
@ -256,7 +256,9 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk,
// time to convert the returned data. // time to convert the returned data.
uint8_t curr_keys = resp.oldarg[0]; uint8_t curr_keys = resp.oldarg[0];
PrintAndLogEx(INFO, "Chunk %.1fs | found %u/%u keys (%u)", (float)(t2 / 1000.0), curr_keys, (sectorsCnt << 1), size); if (verbose) {
PrintAndLogEx(INFO, "Chunk %.1fs | found %u/%u keys (%u)", (float)(t2 / 1000.0), curr_keys, (sectorsCnt << 1), size);
}
// all keys? // all keys?
if (curr_keys == sectorsCnt * 2 || lastChunk) { if (curr_keys == sectorsCnt * 2 || lastChunk) {
@ -1385,8 +1387,9 @@ int detect_mf_magic(bool is_mfc) {
uint8_t payload[] = { is_mfc }; uint8_t payload[] = { is_mfc };
SendCommandNG(CMD_HF_MIFARE_CIDENT, payload, sizeof(payload)); SendCommandNG(CMD_HF_MIFARE_CIDENT, payload, sizeof(payload));
if (WaitForResponseTimeout(CMD_HF_MIFARE_CIDENT, &resp, 1500)) { if (WaitForResponseTimeout(CMD_HF_MIFARE_CIDENT, &resp, 1500)) {
if (resp.status == PM3_SUCCESS) if (resp.status == PM3_SUCCESS) {
isGeneration = resp.data.asBytes[0]; isGeneration = resp.data.asBytes[0];
}
} }
switch (isGeneration) { switch (isGeneration) {

View file

@ -74,7 +74,8 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey); int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey);
int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key); int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key);
int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, 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); uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector,
bool use_flashmemory, bool verbose);
int mfCheckKeys_file(uint8_t *destfn, uint64_t *key); int mfCheckKeys_file(uint8_t *destfn, uint64_t *key);