mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
hf mfp check: dictionary works, verbose mode works
This commit is contained in:
parent
94eb741a4f
commit
2dfbe151b9
4 changed files with 82 additions and 19 deletions
|
@ -643,7 +643,8 @@ static int CmdHFMFPWrbl(const char *cmd) {
|
||||||
#define MAX_KEYS_LIST_LEN 1024
|
#define MAX_KEYS_LIST_LEN 1024
|
||||||
|
|
||||||
int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB,
|
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;
|
int res;
|
||||||
bool selectCard = true;
|
bool selectCard = true;
|
||||||
uint8_t keyn[2] = {0};
|
uint8_t keyn[2] = {0};
|
||||||
|
@ -655,6 +656,8 @@ static int CmdHFMFPWrbl(const char *cmd) {
|
||||||
// main cycle with key check
|
// main cycle with key check
|
||||||
for (int i = 0; i < keyListLen; i++) {
|
for (int i = 0; i < keyListLen; i++) {
|
||||||
if (i % 10 == 0) {
|
if (i % 10 == 0) {
|
||||||
|
if (!verbose)
|
||||||
|
printf(".");
|
||||||
if (kbd_enter_pressed()) {
|
if (kbd_enter_pressed()) {
|
||||||
PrintAndLogEx(WARNING, "\nAborted via keyboard!\n");
|
PrintAndLogEx(WARNING, "\nAborted via keyboard!\n");
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -671,18 +674,25 @@ static int CmdHFMFPWrbl(const char *cmd) {
|
||||||
if (res != 2)
|
if (res != 2)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
printf("retried[%d]...\n", retry);
|
if (verbose)
|
||||||
|
PrintAndLogEx(WARNING, "retried[%d]...", retry);
|
||||||
|
else
|
||||||
|
printf("R");
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
selectCard = true;
|
selectCard = true;
|
||||||
msleep(100);
|
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
|
// key for [sector,keyAB] found
|
||||||
if (res == 0) {
|
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;
|
foundKeys[keyAB][sector][0] = 0x01;
|
||||||
memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN);
|
memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN);
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -693,6 +703,10 @@ static int CmdHFMFPWrbl(const char *cmd) {
|
||||||
|
|
||||||
// 5 - auth error (rnd not equal)
|
// 5 - auth error (rnd not equal)
|
||||||
if (res != 5) {
|
if (res != 5) {
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(ERR, "Exchange error. Aborted.");
|
||||||
|
else
|
||||||
|
printf("E");
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ECARDEXCHANGE;
|
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_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
|
||||||
arg_str0(NULL, "startp2b", "<Pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
|
arg_str0(NULL, "startp2b", "<Pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
|
||||||
arg_str0("jJ", "json", "<file>", "json file to save keys"),
|
arg_str0("jJ", "json", "<file>", "json file to save keys"),
|
||||||
|
arg_lit0("vV", "verbose", "verbose mode."),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(cmd, argtable, true);
|
CLIExecWithReturn(cmd, argtable, true);
|
||||||
|
@ -815,6 +830,8 @@ static int CmdHFMFPChk(const char *cmd) {
|
||||||
}
|
}
|
||||||
jsonname[jsonnamelen] = 0;
|
jsonname[jsonnamelen] = 0;
|
||||||
|
|
||||||
|
bool verbose = arg_get_lit(11);
|
||||||
|
|
||||||
CLIParserFree();
|
CLIParserFree();
|
||||||
|
|
||||||
uint8_t startKeyAB = 0;
|
uint8_t startKeyAB = 0;
|
||||||
|
@ -840,12 +857,13 @@ static int CmdHFMFPChk(const char *cmd) {
|
||||||
Fill2bPattern(keyList, &keyListLen, &startPattern);
|
Fill2bPattern(keyList, &keyListLen, &startPattern);
|
||||||
|
|
||||||
// dictionary mode
|
// dictionary mode
|
||||||
|
size_t endFilePosition = 0;
|
||||||
if (dict_filenamelen) {
|
if (dict_filenamelen) {
|
||||||
size_t endFilePosition = 0;
|
|
||||||
uint16_t keycnt = 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;
|
keyListLen = keycnt;
|
||||||
printf("---endFilePosition %d\n", endFilePosition);
|
if (endFilePosition)
|
||||||
|
PrintAndLogEx(SUCCESS, "First part of dictionary successfully loaded.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyListLen == 0) {
|
if (keyListLen == 0) {
|
||||||
|
@ -862,20 +880,31 @@ static int CmdHFMFPChk(const char *cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!verbose)
|
||||||
|
printf("Search keys:");
|
||||||
while (true) {
|
while (true) {
|
||||||
res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys);
|
res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose);
|
||||||
printf("--- res: %d\n", res);
|
|
||||||
if (res == PM3_EOPABORTED)
|
if (res == PM3_EOPABORTED)
|
||||||
break;
|
break;
|
||||||
if (pattern2b && startPattern < 0x10000) {
|
if (pattern2b && startPattern < 0x10000) {
|
||||||
|
if (!verbose)
|
||||||
|
printf("p");
|
||||||
keyListLen = 0;
|
keyListLen = 0;
|
||||||
Fill2bPattern(keyList, &keyListLen, &startPattern);
|
Fill2bPattern(keyList, &keyListLen, &startPattern);
|
||||||
continue;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!verbose)
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
// print result
|
// print result
|
||||||
bool printedHeader = false;
|
bool printedHeader = false;
|
||||||
|
|
27
client/dictionaries/mfp_default_keys.dic
Normal file
27
client/dictionaries/mfp_default_keys.dic
Normal file
|
@ -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
|
|
@ -754,11 +754,11 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u
|
||||||
keylen = 6;
|
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,
|
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)
|
if (endFilePosition)
|
||||||
*endFilePosition = 0;
|
*endFilePosition = 0;
|
||||||
if (data == NULL) return PM3_EINVARG;
|
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);
|
fseek(f, startFilePosition, SEEK_SET);
|
||||||
|
|
||||||
// read file
|
// 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
|
// add null terminator
|
||||||
line[keylen] = 0;
|
line[keylen] = 0;
|
||||||
|
@ -804,11 +810,10 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// cant store more data
|
// cant store more data
|
||||||
if (maxdatalen && (counter + keylen > maxdatalen)) {
|
if (maxdatalen && (counter + (keylen >> 1) > maxdatalen)) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
int pos = ftell(f) - strlen(line) - 2; // 2 - `\r\n`
|
if (endFilePosition)
|
||||||
if (endFilePosition && (pos > 0))
|
*endFilePosition = filepos;
|
||||||
*endFilePosition = pos;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,7 +825,8 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale
|
||||||
counter += (keylen >> 1);
|
counter += (keylen >> 1);
|
||||||
}
|
}
|
||||||
fclose(f);
|
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)
|
if (datalen)
|
||||||
*datalen = counter;
|
*datalen = counter;
|
||||||
|
|
|
@ -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 keycnt key count that lays in data. may be NULL
|
||||||
* @param startFilePosition start position in dictionary file. used for big dictionaries.
|
* @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 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
|
* @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,
|
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.
|
* @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue