diff --git a/client/src/cmdcrc.c b/client/src/cmdcrc.c index ae424662c..7cbee8d2f 100644 --- a/client/src/cmdcrc.c +++ b/client/src/cmdcrc.c @@ -435,6 +435,8 @@ static int CmdrevengSearch(const char *Cmd) { return 0; } + str_lower(inHexStr); + // try each model and get result for (int i = 0; i < count; i++) { /*if (found) { @@ -479,16 +481,21 @@ static int CmdrevengSearch(const char *Cmd) { ans = RunModel(Models[i], outHex, false, 0, result); if (ans) { + + str_lower(result); + // test for match if (memcmp(result, inCRC, crcChars) == 0) { - PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value: %s\n", Models[i], result); + PrintAndLogEx(SUCCESS, "model... " _YELLOW_("%s"), Models[i]); + PrintAndLogEx(SUCCESS, "value... %s\n", result); //optional - stop searching if found... found = true; } else { if (crcChars > 2) { char *swapEndian = SwapEndianStr(result, crcChars, crcChars); if (memcmp(swapEndian, inCRC, crcChars) == 0) { - PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value endian swapped: %s\n", Models[i], swapEndian); + PrintAndLogEx(SUCCESS, "model... " _YELLOW_("%s"), Models[i]); + PrintAndLogEx(SUCCESS, "value endian swapped... %s\n", swapEndian); // optional - stop searching if found... found = true; } @@ -498,16 +505,20 @@ static int CmdrevengSearch(const char *Cmd) { } ans = RunModel(Models[i], outHex, true, 0, revResult); if (ans) { + str_lower(revResult); + // test for match if (memcmp(revResult, inCRC, crcChars) == 0) { - PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value: %s\n", Models[i], revResult); + PrintAndLogEx(SUCCESS, "model reversed... " _YELLOW_("%s"), Models[i]); + PrintAndLogEx(SUCCESS, "value... %s\n", revResult); // optional - stop searching if found... found = true; } else { if (crcChars > 2) { char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars); if (memcmp(swapEndian, inCRC, crcChars) == 0) { - PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value endian swapped: %s\n", Models[i], swapEndian); + PrintAndLogEx(SUCCESS, "model reversed... " _YELLOW_("%s"), Models[i]); + PrintAndLogEx(SUCCESS, "value endian swapped... %s\n", swapEndian); // optional - stop searching if found... found = true; } @@ -520,9 +531,9 @@ static int CmdrevengSearch(const char *Cmd) { free(Models[i]); } - if (found == false) + if (found == false) { PrintAndLogEx(FAILED, "\nno matches found\n"); - + } return PM3_SUCCESS; } diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 796821159..bc4218180 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -991,7 +991,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav // CRC Check if (iLen == -1) { if (silentMode == false) { - PrintAndLogEx(ERR, "ISO 14443A CRC error."); + PrintAndLogEx(ERR, "ISO 14443A CRC error"); } return PM3_ECRC; } @@ -1665,23 +1665,85 @@ static void printTag(const char *tag) { PrintAndLogEx(SUCCESS, " " _YELLOW_("%s"), tag); } -typedef enum { - MTNONE = 0, - MTCLASSIC = 1, - MTMINI = 2, - MTDESFIRE = 4, - MTPLUS = 8, - MTULTRALIGHT = 16, - HID_SEOS = 32, - MTOTHER = 64, - MTEMV = 128, - MTFUDAN = 256, - MTISO18092 = 512, - MT424 = 1024, -} nxp_mifare_type_t; +int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) { + + int type = MTNONE; + + if ((sak & 0x02) != 0x02) { + if ((sak & 0x19) == 0x19) { + type |= MTCLASSIC; + } else if ((sak & 0x40) == 0x40) { + type |= MTISO18092; + } else if ((sak & 0x38) == 0x38) { + type |= MTCLASSIC; + } else if ((sak & 0x18) == 0x18) { + if (select_status == 1) { + type |= MTPLUS; + } else { + type |= MTCLASSIC; + } + } else if ((sak & 0x09) == 0x09) { + type |= MTMINI; + } else if ((sak & 0x28) == 0x28) { + type |= MTCLASSIC; + } else if ((sak & 0x08) == 0x08) { + if (select_status == 1) { + type |= MTPLUS; + } else { + type |= MTCLASSIC; + } + } else if ((sak & 0x11) == 0x11) { + type |= MTPLUS; + } else if ((sak & 0x10) == 0x10) { + type |= MTPLUS; + } else if ((sak & 0x01) == 0x01) { + type |= MTCLASSIC; + } else if ((sak & 0x24) == 0x24) { + type |= MTDESFIRE; + } else if ((sak & 0x20) == 0x20) { + if (select_status == 1) { + if ((atqa & 0x0040) == 0x0040) { + if ((atqa & 0x0300) == 0x0300) { + type |= MTDESFIRE; + } else { + type |= MTPLUS; + } + } else { + + if ((atqa & 0x0001) == 0x0001) { + type |= HID_SEOS; + } else { + type |= MTPLUS; + } + + if ((atqa & 0x0004) == 0x0004) { + type |= MTEMV; + } + } + type |= (MTDESFIRE | MT424); + } + } else if ((sak & 0x04) == 0x04) { + type |= MTDESFIRE; + } else { + type |= MTULTRALIGHT; + } + } else if ((sak & 0x0A) == 0x0A) { + + if ((atqa & 0x0003) == 0x0003) { + type |= MTFUDAN; + } else if ((atqa & 0x0005) == 0x0005) { + type |= MTFUDAN; + } + } else if ((sak & 0x53) == 0x53) { + type |= MTFUDAN; + } + + return type; +} + // Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1 -static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) { +static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_status) { int type = MTNONE; PrintAndLogEx(SUCCESS, "Possible types:"); @@ -1829,7 +1891,7 @@ static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) { printTag("FM11RF005SH (FUDAN Shanghai Metro)"); type |= MTFUDAN; } else if ((atqa & 0x0005) == 0x0005) { - printTag("FM11RF005M (FUDAN MIFARE Classic clone)"); + printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)"); type |= MTFUDAN; } } else if ((sak & 0x53) == 0x53) { @@ -2007,6 +2069,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]); + bool isMifareMini = false; bool isMifareClassic = true; bool isMifareDESFire = false; bool isMifarePlus = false; @@ -2020,8 +2083,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { int nxptype = MTNONE; if (card.uidlen <= 4) { - nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); + nxptype = detect_nxp_card_print(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); + isMifareMini = ((nxptype & MTMINI) == MTMINI); isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC); isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE); isMifarePlus = ((nxptype & MTPLUS) == MTPLUS); @@ -2046,8 +2110,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { isMifareClassic = false; break; case 0x04: // NXP - nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); + nxptype = detect_nxp_card_print(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); + isMifareMini = ((nxptype & MTMINI) == MTMINI); isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC); isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE); isMifarePlus = ((nxptype & MTPLUS) == MTPLUS); @@ -2136,7 +2201,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } else if (card.atqa[0] == 0x05) { // Uses MIFARE Crypto-1 algo - printTag("FM11RF005M (FUDAN MIFARE Classic clone)"); + printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)"); } break; } @@ -2383,10 +2448,13 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } else { if (card.ats[pos] == 0x80 || card.ats[pos] == 0x00) { - PrintAndLogEx(SUCCESS, " %s (compact TLV data object)", sprint_hex_inrow(&card.ats[pos], calen)); + PrintAndLogEx(SUCCESS, "%s (compact TLV data object)", sprint_hex_inrow(&card.ats[pos], calen)); get_compact_tlv(card.ats + pos, calen); } else { - PrintAndLogEx(SUCCESS, " %s", sprint_hex_inrow(card.ats + pos, calen)); + PrintAndLogEx(SUCCESS, "%s - %s" + , sprint_hex_inrow(card.ats + pos, calen) + , sprint_ascii(card.ats + pos, calen) + ); } PrintAndLogEx(NORMAL, ""); @@ -2495,7 +2563,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { uint16_t isMagic = 0; - if (isMifareClassic) { + if (isMifareClassic || isMifareMini) { isMagic = detect_mf_magic(true, MF_KEY_B, 0xFFFFFFFFFFFF); } @@ -2503,7 +2571,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { isMagic = detect_mf_magic(false, MF_KEY_A, 0); } - if (isMifareClassic) { + if (isMifareClassic || isMifareMini) { int res = detect_classic_static_nonce(); if (res == NONCE_STATIC) { PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes")); @@ -2594,7 +2662,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("hf ntag424 info") "`"); } - if (isMifareClassic) { + if (isMifareClassic || isMifareMini) { if (((isMagic & MAGIC_FLAG_GEN_1A) == MAGIC_FLAG_GEN_1A) || ((isMagic & MAGIC_FLAG_GEN_1B) == MAGIC_FLAG_GEN_1B)) { PrintAndLogEx(HINT, "Hint: use `" _YELLOW_("hf mf c*") "` magic commands"); diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index d7304501f..5d76a0699 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -36,6 +36,21 @@ typedef struct { const char *hint; } hintAIDList_t; +typedef enum { + MTNONE = 0, + MTCLASSIC = 1, + MTMINI = 2, + MTDESFIRE = 4, + MTPLUS = 8, + MTULTRALIGHT = 16, + HID_SEOS = 32, + MTOTHER = 64, + MTEMV = 128, + MTFUDAN = 256, + MTISO18092 = 512, + MT424 = 1024, +} nxp_mifare_type_t; + int CmdHF14A(const char *Cmd); int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff int CmdHF14ASim(const char *Cmd); // used by hf mfu sim @@ -43,6 +58,8 @@ int CmdHF14ANdefRead(const char *Cmd); // used by cmdnfc.c int CmdHF14ANdefFormat(const char *Cmd); // used by cmdnfc.c int CmdHF14ANdefWrite(const char *Cmd); // used by cmdnfc.c +int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status); + int hf14a_getconfig(hf14a_config *config); int hf14a_setconfig(hf14a_config *config, bool verbose); int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search); diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index b7c89a957..be11aea2b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -32,7 +32,7 @@ #include "crapto1/crapto1.h" // prng_successor #include "commonutil.h" // num_to_bytes #include "util_posix.h" // msclock -#include "ui.h" // searchhomedirectory +#include "ui.h" // search home directory #include "proxgui.h" // Picture Window // Max file size in bytes. Used in several places. diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e2845918d..b833b12ac 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1419,8 +1419,9 @@ static int CmdHF14aDesChk(const char *Cmd) { } if (pattern2b && startPattern < 0x10000) { - if (verbose == false) + if (verbose == false) { PrintAndLogEx(NORMAL, "p" NOLF); + } aeskeyListLen = 0; deskeyListLen = 0; @@ -1430,29 +1431,34 @@ static int CmdHF14aDesChk(const char *Cmd) { } if (dict_filenamelen) { - if (verbose == false) + if (verbose == false) { PrintAndLogEx(NORMAL, "d" NOLF); + } uint32_t keycnt = 0; res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); - if (res == PM3_SUCCESS && endFilePosition) + if (res == PM3_SUCCESS && endFilePosition) { deskeyListLen = keycnt; + } keycnt = 0; res = loadFileDICTIONARYEx((char *)dict_filename, aeskeyList, sizeof(aeskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); - if (res == PM3_SUCCESS && endFilePosition) + if (res == PM3_SUCCESS && endFilePosition) { aeskeyListLen = keycnt; + } keycnt = 0; res = loadFileDICTIONARYEx((char *)dict_filename, k3kkeyList, sizeof(k3kkeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); - if (res == PM3_SUCCESS && endFilePosition) + if (res == PM3_SUCCESS && endFilePosition) { k3kkeyListLen = keycnt; + } continue; } } - if (verbose == false) + if (verbose == false) { PrintAndLogEx(NORMAL, ""); + } // save keys to json if ((jsonnamelen > 0) && result) { @@ -4848,13 +4854,15 @@ static int DesfileReadFileAndPrint(DesfireContext_t *dctx, PrintAndLogEx(WARNING, "File needs to be authenticated with key 0x%02x or 0x%02x but current authentication key is 0x%02x", fsettings.rAccess, fsettings.rwAccess, dctx->keyNum); if (fsettings.rAccess == 0x0f && fsettings.rwAccess == 0x0f) - PrintAndLogEx(WARNING, "File access denied. All read access rights is 0x0f."); + PrintAndLogEx(WARNING, "File access denied. All read access rights is 0x0F"); - if (verbose) - PrintAndLogEx(INFO, "Got file type: %s. Option: %s. comm mode: %s", - GetDesfireFileType(fsettings.fileType), - CLIGetOptionListStr(DesfireReadFileTypeOpts, filetype), - CLIGetOptionListStr(DesfireCommunicationModeOpts, fsettings.commMode)); + if (verbose) { + PrintAndLogEx(INFO, _CYAN_("File type:") " %s Option: %s comm mode: %s", + GetDesfireFileType(fsettings.fileType), + CLIGetOptionListStr(DesfireReadFileTypeOpts, filetype), + CLIGetOptionListStr(DesfireCommunicationModeOpts, fsettings.commMode) + ); + } } else { PrintAndLogEx(WARNING, "GetFileSettings error. Can't get file type."); } diff --git a/client/src/cmdhftopaz.c b/client/src/cmdhftopaz.c index 5b8ab2677..dba9d65c4 100644 --- a/client/src/cmdhftopaz.c +++ b/client/src/cmdhftopaz.c @@ -829,8 +829,16 @@ static int CmdHFTopazSniff(const char *Cmd) { CLIParserFree(ctx); uint8_t param = 0; + + PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort sniffing"); + SendCommandNG(CMD_HF_ISO14443A_SNIFF, (uint8_t *)¶m, sizeof(uint8_t)); + PacketResponseNG resp; + WaitForResponse(CMD_HF_ISO14443A_SNIFF, &resp); + PrintAndLogEx(INFO, "Done!"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf topaz list")"` to view captured tracelog"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing"); return PM3_SUCCESS; }