Further improved the hardautopwn feature.

This commit is contained in:
Matthias Konrath 2019-08-22 14:55:06 +02:00
commit abb69e2dc9

View file

@ -168,17 +168,16 @@ static int usage_hf14_hardnested(void) {
} }
static int usage_hf14_hardautopwn(void) { static int usage_hf14_hardautopwn(void) {
PrintAndLogEx(NORMAL, "Usage:"); PrintAndLogEx(NORMAL, "Usage:");
PrintAndLogEx(NORMAL, " hf mf hardautopwn [k] <block number> <key A|B> <key (12 hex symbols)>"); PrintAndLogEx(NORMAL, " hf mf hardautopwn [k] <sector number> <key A|B> <key (12 hex symbols)>");
PrintAndLogEx(NORMAL, " <card memory> [d] [f] [s] [t] [i]"); PrintAndLogEx(NORMAL, " * <card memory> [d] [f] [s] [t] [i]");
PrintAndLogEx(NORMAL, " (card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K)"); PrintAndLogEx(NORMAL, " (card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " k <block> <keytype> <key> if a known key for a block is supplied"); PrintAndLogEx(NORMAL, " k <sector> <keytype> <key> if a known key for a block is supplied");
PrintAndLogEx(NORMAL, " d write keys to binary file"); PrintAndLogEx(NORMAL, " d write keys to binary file");
PrintAndLogEx(NORMAL, " f <name> keys to test (speed up the cracking, if some keys are known)"); PrintAndLogEx(NORMAL, " f <name> keys to test (speed up the cracking, if some keys are known)");
PrintAndLogEx(NORMAL, " s slower acquisition (required by some non standard cards)"); PrintAndLogEx(NORMAL, " s slower acquisition (required by some non standard cards)");
PrintAndLogEx(NORMAL, " t tests?");
PrintAndLogEx(NORMAL, " i <X> set type of SIMD instructions. Without this flag programs autodetect it."); PrintAndLogEx(NORMAL, " i <X> set type of SIMD instructions. Without this flag programs autodetect it.");
PrintAndLogEx(NORMAL, " i 5 = AVX512"); PrintAndLogEx(NORMAL, " i 5 = AVX512");
PrintAndLogEx(NORMAL, " i 2 = AVX2"); PrintAndLogEx(NORMAL, " i 2 = AVX2");
@ -188,9 +187,9 @@ static int usage_hf14_hardautopwn(void) {
PrintAndLogEx(NORMAL, " i n = none (use CPU regular instruction set)"); PrintAndLogEx(NORMAL, " i n = none (use CPU regular instruction set)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mf hardautopwn b 0 A FFFFFFFFFFFF 1 d"); PrintAndLogEx(NORMAL, " hf mf hardautopwn k 0 A FFFFFFFFFFFF d");
PrintAndLogEx(NORMAL, " hf mf hardautopwn 0 A FFFFFFFFFFFF 1 d f default_keys.dic"); PrintAndLogEx(NORMAL, " hf mf hardautopwn k 0 A FFFFFFFFFFFF * 1 d f default_keys.dic");
PrintAndLogEx(NORMAL, " hf mf hardautopwn 0 A FFFFFFFFFFFF 4 A f nonces.bin w s"); PrintAndLogEx(NORMAL, " hf mf hardautopwn k 0 A FFFFFFFFFFFF * 4 s i 5");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return 0; return 0;
} }
@ -1560,16 +1559,26 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
static int CmdHF14AMfHardAuto(const char *Cmd) { static int CmdHF14AMfHardAuto(const char *Cmd) {
/*
Author: Matthias Konrath
Company: Trustworks GmbH
Email: m.konrath@trustworks.at
*/
uint8_t blockNo = 0; uint8_t blockNo = 0;
uint8_t keyType = 0; uint8_t keyType = 0;
uint8_t *keyBlock, *p; uint8_t *keyBlock, *p;
uint8_t sectorsCnt = 1; uint8_t sectorsCnt = MIFARE_1K_MAXSECTOR;
sector_t *e_sector;
uint8_t arr[80];
uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t key[6] = {0, 0, 0, 0, 0, 0};
uint8_t trgkey[6] = {0, 0, 0, 0, 0, 0}; uint8_t tmpKey[6];
uint8_t cmdp = 0;
uint64_t key64 = 0; uint64_t key64 = 0;
char filename[FILE_PATH_SIZE] = {0}, *fptr;
char ctmp; uint64_t t1;
uint8_t foundKeysDictionary = 0;
uint8_t foundKeysReuse = 0;
uint8_t foundKeysHardnested = 0;
keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6); keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6);
if (keyBlock == NULL) return 1; if (keyBlock == NULL) return 1;
@ -1577,6 +1586,19 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++)
num_to_bytes(g_mifare_default_keys[cnt], 6, keyBlock + cnt * 6); num_to_bytes(g_mifare_default_keys[cnt], 6, keyBlock + cnt * 6);
FILE* f;
char buf[13] = {0};
char filename[FILE_PATH_SIZE] = {0}, *fptr;
uint8_t cmdp = 0;
char ctmp;
uint64_t foundkey = 0;
int16_t isOK = 0;
int i, i2, keycnt = 0;;
int current_sector_i, current_key_type_i, default_keys_i, found_keys_i;
uint32_t keyitems = ARRAYLEN(g_mifare_default_keys);
bool slow = false; bool slow = false;
bool nonce_file_read = false; bool nonce_file_read = false;
bool nonce_file_write = false; bool nonce_file_write = false;
@ -1624,7 +1646,7 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
case 'k': case 'k':
// Get the known block number // Get the known block number
if (param_getchar(Cmd, cmdp + 1) == 0x00) { if (param_getchar(Cmd, cmdp + 1) == 0x00) {
PrintAndLogEx(WARNING, "Block number is missing"); PrintAndLogEx(WARNING, "Sector number is missing");
return 1; return 1;
} }
blockNo = param_get8(Cmd, cmdp + 1); blockNo = param_get8(Cmd, cmdp + 1);
@ -1685,42 +1707,27 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
// Print parameters // Print parameters
PrintAndLogEx(NORMAL, "Used Parameters:"); PrintAndLogEx(NORMAL, "Used Parameters:");
PrintAndLogEx(NORMAL, "\t[+] Dumping the found keys: %d", createDumpFile); PrintAndLogEx(NORMAL, "[+] Dumping the found keys: %s", createDumpFile ? "True" : "False");
PrintAndLogEx(NORMAL, "\t[+] Card sectors: %d", sectorsCnt); PrintAndLogEx(NORMAL, "[+] Card sectors: %d", sectorsCnt);
PrintAndLogEx(NORMAL, "\t[+] Key supplied: %d", know_target_key); PrintAndLogEx(NORMAL, "[+] Key supplied: %s", know_target_key ? "True" : "False");
PrintAndLogEx(NORMAL, "\t[+] Known block: %d", blockNo); PrintAndLogEx(NORMAL, "[+] Known sector: %d", blockNo);
PrintAndLogEx(NORMAL, "\t[+] Keytype: %c", keyType ? 'B' : 'A'); PrintAndLogEx(NORMAL, "[+] Keytype: %c", keyType ? 'B' : 'A');
PrintAndLogEx(NORMAL, "\t[+] Kown key: 0x%02x%02x%02x%02x%02x%02x", key[0], key[1], key[2], key[3], key[4], key[5]); PrintAndLogEx(NORMAL, "[+] Kown key: 0x%02x%02x%02x%02x%02x%02x", key[0], key[1], key[2], key[3], key[4], key[5]);
PrintAndLogEx(NORMAL, "\t[+] Dictionary: %s", filename); PrintAndLogEx(NORMAL, "[+] Dictionary: %s", filename);
e_sector = calloc(sectorsCnt, sizeof(sector_t));
if (know_target_key) { if (know_target_key) {
// check if we can authenticate to sector // check if we can authenticate to sector
if (mfCheckKeys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) { if (mfCheckKeys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Key is wrong. Can't authenticate to block:%3d key type:%c", blockNo, keyType ? 'B' : 'A'); PrintAndLogEx(WARNING, "Key is wrong. Can't authenticate to sector:%3d key type:%c", blockNo, keyType ? 'B' : 'A');
free(e_sector);
return 3; return 3;
} }
} else { } else {
PrintAndLogEx(WARNING, "No known key was supplied, if no usable key is found in the dictionary, then this attack will fail!"); PrintAndLogEx(WARNING, "No known key was supplied, if no usable key is found in the dictionary, then this attack will fail!");
} }
// General stuff
// Add check for the hardnested attack!!
uint64_t foundkey = 0;
int16_t isOK = 0;
// Bruteforce stuff
FILE* f;
sector_t *e_sector = calloc(sectorsCnt, sizeof(sector_t));
uint8_t arr[80];
uint8_t tmpKey[6];
char buf[13] = {0};
int i, i2, keycnt = 0;;
int current_sector_i, current_key_type_i, default_keys_i, found_keys_i;
uint32_t keyitems = ARRAYLEN(g_mifare_default_keys);
// Clear the datastructures // Clear the datastructures
for (i=0; i<80; i++) { for (i=0; i<80; i++) {
arr[i] = 0; arr[i] = 0;
@ -1737,6 +1744,7 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
f = fopen(filename, "r"); f = fopen(filename, "r");
if (!f) { if (!f) {
PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", filename); PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", filename);
free(e_sector);
return 1; return 1;
} }
@ -1760,6 +1768,7 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
PrintAndLogEx(FAILED, "Cannot allocate memory for default keys"); PrintAndLogEx(FAILED, "Cannot allocate memory for default keys");
free(keyBlock); free(keyBlock);
fclose(f); fclose(f);
free(e_sector);
return 2; return 2;
} }
keyBlock = p; keyBlock = p;
@ -1774,8 +1783,9 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Loaded %2d keys from " _YELLOW_("%s"), keycnt, filename); PrintAndLogEx(SUCCESS, "Loaded %2d keys from " _YELLOW_("%s"), keycnt, filename);
} }
t1 = msclock();
// If no key is supplied by the user brute force with the dictionary // If no key is supplied by the user, brute force with the dictionary
if (know_target_key == false) { if (know_target_key == false) {
for (current_sector_i=0; current_sector_i < sectorsCnt; current_sector_i++) { for (current_sector_i=0; current_sector_i < sectorsCnt; current_sector_i++) {
for (current_key_type_i=0; current_key_type_i < 2; current_key_type_i++) { for (current_key_type_i=0; current_key_type_i < 2; current_key_type_i++) {
@ -1786,7 +1796,8 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
} }
if (mfCheckKeys(current_sector_i*4, current_key_type_i, true, 1, tmpKey, &key64) == PM3_SUCCESS) { if (mfCheckKeys(current_sector_i*4, current_key_type_i, true, 1, tmpKey, &key64) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "[ KEY ENUM ] Valid KEY FOUND: block:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"), PrintAndLogEx(SUCCESS, "Jackpot, we found a key! Now let the fun begin!");
PrintAndLogEx(SUCCESS, "[Dictio. KEYS] Valid KEY FOUND: sector:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"),
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', current_key_type_i ? 'B' : 'A',
tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]); tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]);
@ -1797,6 +1808,7 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
know_target_key = true; know_target_key = true;
blockNo = current_sector_i; blockNo = current_sector_i;
keyType = current_key_type_i; keyType = current_key_type_i;
foundKeysDictionary++;
// Exit the loop // Exit the loop
current_sector_i = sectorsCnt; current_sector_i = sectorsCnt;
@ -1809,17 +1821,17 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
} }
} }
// Set the user defined key // Set the user defined / bruteforced key
if (know_target_key) { if (know_target_key) {
e_sector[blockNo].Key[keyType] = bytes_to_num(key, 6); e_sector[blockNo].Key[keyType] = bytes_to_num(key, 6);
arr[blockNo + (keyType * sectorsCnt)] = 1; arr[blockNo + (keyType * sectorsCnt)] = 1;
} else { } else {
PrintAndLogEx(FAILED, "No usable key was found!"); PrintAndLogEx(FAILED, "No usable key was found!");
free(e_sector);
return 1; return 1;
} }
// Iterate over each sector and key(A/B)
// Iterate over each sector and key
for (current_sector_i=0; current_sector_i < sectorsCnt; current_sector_i++) { for (current_sector_i=0; current_sector_i < sectorsCnt; current_sector_i++) {
for (current_key_type_i=0; current_key_type_i < 2; current_key_type_i++) { for (current_key_type_i=0; current_key_type_i < 2; current_key_type_i++) {
@ -1827,29 +1839,29 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
// Try the found keys // Try the found keys
if (foundkey == 0) { if (foundkey == 0) {
for (found_keys_i=0; found_keys_i < current_sector_i; found_keys_i++) { for (found_keys_i=0; found_keys_i < sectorsCnt; found_keys_i++) {
// Iterate over the keys // Iterate over the keys
if (arr[found_keys_i + (current_key_type_i * sectorsCnt)] == 1) { if (arr[found_keys_i + (current_key_type_i * sectorsCnt)] == 1) {
num_to_bytes(e_sector[found_keys_i].Key[current_key_type_i], 6, tmpKey); num_to_bytes(e_sector[found_keys_i].Key[current_key_type_i], 6, tmpKey);
if (mfCheckKeys(current_sector_i*4, current_key_type_i, true, 1, tmpKey, &key64) == PM3_SUCCESS) { if (mfCheckKeys(current_sector_i*4, current_key_type_i, true, 1, tmpKey, &key64) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "[FOUND KEYS %c] Valid KEY FOUND: block:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"), PrintAndLogEx(SUCCESS, "[REUSED KEYS] Valid KEY FOUND: sector:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"),
current_key_type_i ? 'B' : 'A',
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', current_key_type_i ? 'B' : 'A',
tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]); tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]);
foundkey = bytes_to_num(tmpKey, 6); foundkey = bytes_to_num(tmpKey, 6);
foundKeysReuse++;
break; break;
} }
} }
if (arr[found_keys_i + (((current_key_type_i+1)%2) * sectorsCnt)] == 1) { if (arr[found_keys_i + (((current_key_type_i+1)%2) * sectorsCnt)] == 1) {
num_to_bytes(e_sector[found_keys_i].Key[(current_key_type_i+1)%2], 6, tmpKey); num_to_bytes(e_sector[found_keys_i].Key[(current_key_type_i+1)%2], 6, tmpKey);
if (mfCheckKeys(current_sector_i*4, current_key_type_i, true, 1, tmpKey, &key64) == PM3_SUCCESS) { if (mfCheckKeys(current_sector_i*4, current_key_type_i, true, 1, tmpKey, &key64) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "[FOUND KEYS %c] Valid KEY FOUND: block:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"), PrintAndLogEx(SUCCESS, "[REUSED KEYS] Valid KEY FOUND: sector:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"),
(current_key_type_i+1)%2 ? 'B' : 'A',
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', current_key_type_i ? 'B' : 'A',
tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]); tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]);
foundkey = bytes_to_num(tmpKey, 6); foundkey = bytes_to_num(tmpKey, 6);
foundKeysReuse++;
break; break;
} }
} }
@ -1864,29 +1876,48 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
} }
if (mfCheckKeys(current_sector_i*4, current_key_type_i, true, 1, tmpKey, &key64) == PM3_SUCCESS) { if (mfCheckKeys(current_sector_i*4, current_key_type_i, true, 1, tmpKey, &key64) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "[DEFAULT KEYS] Valid KEY FOUND: block:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"), PrintAndLogEx(SUCCESS, "[Dictio. KEYS] Valid KEY FOUND: sector:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"),
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', current_key_type_i ? 'B' : 'A',
tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]); tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]);
foundkey = bytes_to_num(tmpKey, 6); foundkey = bytes_to_num(tmpKey, 6);
foundKeysDictionary++;
break; break;
} }
} }
} }
// Bruteforce with hardnested // Bruteforce with hardnested
if (foundkey == 0) { if (foundkey == 0) {
PrintAndLogEx(SUCCESS, "[ BRUTEFORCE ] block no:%3d, target key type:%c, Slow: %s, Tests: %d ", PrintAndLogEx(SUCCESS, "[ BRUTEFORCE ] sector no:%3d, target key type:%c, Slow: %s, Tests: %d ",
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', current_key_type_i ? 'B' : 'A',
slow ? "Yes" : "No", slow ? "Yes" : "No",
tests); tests);
isOK = mfnestedhard(blockNo, keyType, key, current_sector_i*4, current_key_type_i, know_target_key ? trgkey : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey, filename); isOK = mfnestedhard(blockNo, keyType, key, current_sector_i*4, current_key_type_i, NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey, NULL);
DropField();
if (isOK) {
switch (isOK) {
case 1 :
PrintAndLogEx(ERR, "Error: No response from Proxmark3.\n");
break;
case 2 :
PrintAndLogEx(NORMAL, "Button pressed. Aborted.\n");
break;
default :
break;
}
free(e_sector);
return 2;
}
num_to_bytes(foundkey, 6, tmpKey); num_to_bytes(foundkey, 6, tmpKey);
PrintAndLogEx(SUCCESS, "[CRACKED KEY] Valid KEY FOUND: block:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"), PrintAndLogEx(SUCCESS, "[CRACKED KEY] Valid KEY FOUND: sector:%3d key type:%c key: " _YELLOW_("0x%02x%02x%02x%02x%02x%02x"),
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', current_key_type_i ? 'B' : 'A',
tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]); tmpKey[0], tmpKey[1], tmpKey[2], tmpKey[3], tmpKey[4], tmpKey[5]);
foundKeysHardnested++;
} }
// Add the key // Add the key
if (foundkey != 0) { if (foundkey != 0) {
@ -1908,8 +1939,10 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
if (createDumpFile) { if (createDumpFile) {
fptr = GenerateFilename("hf-mf-", "-key.bin"); fptr = GenerateFilename("hf-mf-", "-key.bin");
if (fptr == NULL) if (fptr == NULL) {
free(e_sector);
return 1; return 1;
}
FILE *fkeys = fopen(fptr, "wb"); FILE *fkeys = fopen(fptr, "wb");
if (fkeys == NULL) { if (fkeys == NULL) {
@ -1933,24 +1966,11 @@ static int CmdHF14AMfHardAuto(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s")" --> 0xffffffffffff has been inserted for unknown keys.", fptr); PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s")" --> 0xffffffffffff has been inserted for unknown keys.", fptr);
} }
t1 = msclock() - t1;
PrintAndLogEx(SUCCESS, "Key statistics: Dictionary: " _GREEN_("%d") ", Reuse: " _YELLOW_("%d") ", Bruteforce: " _MAGENTA_("%d") ", Total: " _YELLOW_("%d"), foundKeysDictionary, foundKeysReuse, foundKeysHardnested, sectorsCnt*2);
PrintAndLogEx(SUCCESS, "Required time for the hardautopwn attack: " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
free(e_sector); free(e_sector);
DropField();
if (isOK) {
switch (isOK) {
case 1 :
PrintAndLogEx(ERR, "Error: No response from Proxmark3.\n");
break;
case 2 :
PrintAndLogEx(NORMAL, "Button pressed. Aborted.\n");
break;
default :
break;
}
return 2;
}
return 0; return 0;
} }