From 2dfbe151b9e6511d627c895107308f7612f5f9bc Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 23:21:00 +0200 Subject: [PATCH] hf mfp check: dictionary works, verbose mode works --- client/cmdhfmfp.c | 49 +++++++++++++++++++----- client/dictionaries/mfp_default_keys.dic | 27 +++++++++++++ client/fileutils.c | 22 +++++++---- client/fileutils.h | 3 +- 4 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 client/dictionaries/mfp_default_keys.dic diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 541847897..a616fcc00 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -643,7 +643,8 @@ static int CmdHFMFPWrbl(const char *cmd) { #define MAX_KEYS_LIST_LEN 1024 int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, - uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1]) { + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], + bool verbose) { int res; bool selectCard = true; uint8_t keyn[2] = {0}; @@ -655,6 +656,8 @@ static int CmdHFMFPWrbl(const char *cmd) { // main cycle with key check for (int i = 0; i < keyListLen; i++) { if (i % 10 == 0) { + if (!verbose) + printf("."); if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); DropField(); @@ -671,18 +674,25 @@ static int CmdHFMFPWrbl(const char *cmd) { if (res != 2) break; - printf("retried[%d]...\n", retry); + if (verbose) + PrintAndLogEx(WARNING, "retried[%d]...", retry); + else + printf("R"); DropField(); selectCard = true; msleep(100); } - PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); + if (verbose) + PrintAndLogEx(WARNING, "sector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); // key for [sector,keyAB] found if (res == 0) { - PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + if (verbose) + PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + else + printf("+"); foundKeys[keyAB][sector][0] = 0x01; memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); DropField(); @@ -693,6 +703,10 @@ static int CmdHFMFPWrbl(const char *cmd) { // 5 - auth error (rnd not equal) if (res != 5) { + if (verbose) + PrintAndLogEx(ERR, "Exchange error. Aborted."); + else + printf("E"); DropField(); return PM3_ECARDEXCHANGE; } @@ -744,6 +758,7 @@ static int CmdHFMFPChk(const char *cmd) { arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), arg_str0(NULL, "startp2b", "", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), arg_str0("jJ", "json", "", "json file to save keys"), + arg_lit0("vV", "verbose", "verbose mode."), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -815,6 +830,8 @@ static int CmdHFMFPChk(const char *cmd) { } jsonname[jsonnamelen] = 0; + bool verbose = arg_get_lit(11); + CLIParserFree(); uint8_t startKeyAB = 0; @@ -840,12 +857,13 @@ static int CmdHFMFPChk(const char *cmd) { Fill2bPattern(keyList, &keyListLen, &startPattern); // dictionary mode + size_t endFilePosition = 0; if (dict_filenamelen) { - size_t endFilePosition = 0; uint16_t keycnt = 0; - res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition); + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition, true); keyListLen = keycnt; - printf("---endFilePosition %d\n", endFilePosition); + if (endFilePosition) + PrintAndLogEx(SUCCESS, "First part of dictionary successfully loaded."); } if (keyListLen == 0) { @@ -862,20 +880,31 @@ static int CmdHFMFPChk(const char *cmd) { return PM3_EINVARG; } + if (!verbose) + printf("Search keys:"); while (true) { - res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys); - printf("--- res: %d\n", res); + res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); if (res == PM3_EOPABORTED) break; if (pattern2b && startPattern < 0x10000) { + if (!verbose) + printf("p"); keyListLen = 0; Fill2bPattern(keyList, &keyListLen, &startPattern); continue; } - if (dict_filenamelen) { + if (dict_filenamelen && endFilePosition) { + if (!verbose) + printf("d"); + uint16_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); + keyListLen = keycnt; + continue; } break; } + if (!verbose) + printf("\n"); // print result bool printedHeader = false; diff --git a/client/dictionaries/mfp_default_keys.dic b/client/dictionaries/mfp_default_keys.dic new file mode 100644 index 000000000..0f20b69bf --- /dev/null +++ b/client/dictionaries/mfp_default_keys.dic @@ -0,0 +1,27 @@ +ffffffffffffffffffffffffffffffff +00000000000000000000000000000000 +a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7 +b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7 +d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 +11111111111111111111111111111111 +22222222222222222222222222222222 +33333333333333333333333333333333 +44444444444444444444444444444444 +55555555555555555555555555555555 +66666666666666666666666666666666 +77777777777777777777777777777777 +88888888888888888888888888888888 +99999999999999999999999999999999 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +cccccccccccccccccccccccccccccccc +dddddddddddddddddddddddddddddddd +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +000102030405060708090a0b0c0d0e0f +0102030405060708090a0b0c0d0e0f10 +00010203040506070809101112131415 +01020304050607080910111213141516 +16151413121110090807060504030201 +15141312111009080706050403020100 +0f0e0d0c0b0a09080706050403020100 +100f0e0d0c0b0a090807060504030201 diff --git a/client/fileutils.c b/client/fileutils.c index ebe29f0bd..624c0259d 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -754,11 +754,11 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u keylen = 6; } - return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL); + return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL, true); } int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, - size_t startFilePosition, size_t *endFilePosition) { + size_t startFilePosition, size_t *endFilePosition, bool verbose) { if (endFilePosition) *endFilePosition = 0; if (data == NULL) return PM3_EINVARG; @@ -787,7 +787,13 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale fseek(f, startFilePosition, SEEK_SET); // read file - while (!feof(f) && fgets(line, sizeof(line), f)) { + while (!feof(f)) { + size_t filepos = ftell(f); + if (!fgets(line, sizeof(line), f)) { + if (endFilePosition) + *endFilePosition = 0; + break; + } // add null terminator line[keylen] = 0; @@ -804,11 +810,10 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale continue; // cant store more data - if (maxdatalen && (counter + keylen > maxdatalen)) { + if (maxdatalen && (counter + (keylen >> 1) > maxdatalen)) { retval = 1; - int pos = ftell(f) - strlen(line) - 2; // 2 - `\r\n` - if (endFilePosition && (pos > 0)) - *endFilePosition = pos; + if (endFilePosition) + *endFilePosition = filepos; break; } @@ -820,7 +825,8 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale counter += (keylen >> 1); } fclose(f); - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path); + if (verbose) + PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path); if (datalen) *datalen = counter; diff --git a/client/fileutils.h b/client/fileutils.h index 612c9fee6..c9de3b4fb 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -196,10 +196,11 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u * @param keycnt key count that lays in data. may be NULL * @param startFilePosition start position in dictionary file. used for big dictionaries. * @param endFilePosition in case we have keys in file and maxdatalen reached it returns current key position in file. may be NULL + * @param verbose print messages if true * @return 0 for ok, 1 for failz */ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, - size_t startFilePosition, size_t *endFilePosition); + size_t startFilePosition, size_t *endFilePosition, bool verbose); /** * @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name.