hf mf autopwn - now use cliparser

This commit is contained in:
iceman1001 2021-04-12 10:02:47 +02:00
commit b59e469d47
2 changed files with 236 additions and 277 deletions

View file

@ -43,48 +43,6 @@
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int usage_hf14_autopwn(void) {
PrintAndLogEx(NORMAL, "Usage:");
PrintAndLogEx(NORMAL, " hf mf autopwn [k] <sector number> <key A|B> <key (12 hex symbols)>");
PrintAndLogEx(NORMAL, " [* <card memory>] [f <dictionary>[.dic]] [s] [i <simd type>] [l] [v]");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Description:");
PrintAndLogEx(NORMAL, " This command automates the key recovery process on MIFARE Classic cards.");
PrintAndLogEx(NORMAL, " It uses the darkside, nested, hardnested and staticnested to recover keys.");
PrintAndLogEx(NORMAL, " If all keys are found, try dumping card content.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " k <sector> <key A|B> <key> known key is supplied");
PrintAndLogEx(NORMAL, " f <dictionary>[.dic] key dictionary file");
PrintAndLogEx(NORMAL, " s slower acquisition for hardnested (required by some non standard cards)");
PrintAndLogEx(NORMAL, " v verbose output (statistics)");
PrintAndLogEx(NORMAL, " l legacy mode (use the slow 'mf chk' for the key enumeration)");
PrintAndLogEx(NORMAL, " * <card memory> all sectors based on card memory");
PrintAndLogEx(NORMAL, " * 0 = MINI(320 bytes)");
PrintAndLogEx(NORMAL, " * 1 = 1k (default)");
PrintAndLogEx(NORMAL, " * 2 = 2k");
PrintAndLogEx(NORMAL, " * 4 = 4k");
PrintAndLogEx(NORMAL, " i <simd type> set type of SIMD instructions for hardnested. Default: autodetection.");
#if defined(COMPILER_HAS_SIMD_AVX512)
PrintAndLogEx(NORMAL, " i 5 = AVX512");
#endif
#if defined(COMPILER_HAS_SIMD)
PrintAndLogEx(NORMAL, " i 2 = AVX2");
PrintAndLogEx(NORMAL, " i a = AVX");
PrintAndLogEx(NORMAL, " i s = SSE2");
#endif
PrintAndLogEx(NORMAL, " i m = MMX");
PrintAndLogEx(NORMAL, " i n = none (use CPU regular instruction set)");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn")" -- target MIFARE Classic card with default keys");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn * 1 f mfc_default_keys")" -- target MIFARE Classic card (size 1k) with default dictionary");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn k 0 A FFFFFFFFFFFF")" -- target MIFARE Classic card with Sector0 typeA with known key 'FFFFFFFFFFFF'");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn k 0 A FFFFFFFFFFFF * 1 f mfc_default_keys")" -- this command combines the two above (reduce the need for nested / hardnested attacks, by using a dictionary)");
return PM3_SUCCESS;
}
/* /*
static int usage_hf14_keybrute(void) { static int usage_hf14_keybrute(void) {
PrintAndLogEx(NORMAL, "J_Run's 2nd phase of multiple sector nested authentication key recovery"); PrintAndLogEx(NORMAL, "J_Run's 2nd phase of multiple sector nested authentication key recovery");
@ -222,21 +180,6 @@ static void decode_print_st(uint16_t blockno, uint8_t *data) {
} }
} }
static uint16_t NumOfBlocks(char card) {
switch (card) {
case '0' :
return MIFARE_MINI_MAXBLOCK;
case '1' :
return MIFARE_1K_MAXBLOCK;
case '2' :
return MIFARE_2K_MAXBLOCK;
case '4' :
return MIFARE_4K_MAXBLOCK;
default :
return 0;
}
}
static uint8_t NumOfSectors(char card) { static uint8_t NumOfSectors(char card) {
switch (card) { switch (card) {
case '0' : case '0' :
@ -1758,20 +1701,14 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
bool nonce_file_write = arg_get_lit(ctx, 14); bool nonce_file_write = arg_get_lit(ctx, 14);
bool in = arg_get_lit(ctx, 15); bool in = arg_get_lit(ctx, 15);
bool im = false;
bool is = false;
bool ia = false;
bool i2 = false;
bool i5 = false;
#if defined(COMPILER_HAS_SIMD) #if defined(COMPILER_HAS_SIMD)
im = arg_get_lit(ctx, 16); bool im = arg_get_lit(ctx, 16);
is = arg_get_lit(ctx, 17); bool is = arg_get_lit(ctx, 17);
ia = arg_get_lit(ctx, 18); bool ia = arg_get_lit(ctx, 18);
i2 = arg_get_lit(ctx, 19); bool i2 = arg_get_lit(ctx, 19);
#endif #endif
#if defined(COMPILER_HAS_SIMD_AVX512) #if defined(COMPILER_HAS_SIMD_AVX512)
i5 = arg_get_lit(ctx, 20); bool i5 = arg_get_lit(ctx, 20);
#endif #endif
CLIParserFree(ctx); CLIParserFree(ctx);
@ -1872,149 +1809,173 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
} }
static int CmdHF14AMfAutoPWN(const char *Cmd) { static int CmdHF14AMfAutoPWN(const char *Cmd) {
// Nested and Hardnested parameter
uint8_t blockNo = 0; CLIParserContext *ctx;
uint8_t keyType = MF_KEY_A; CLIParserInit(&ctx, "hf mf autopwn",
"This command automates the key recovery process on MIFARE Classic cards.\n"
"It uses the fchk, chk, darkside, nested, hardnested and staticnested to recover keys.\n"
"If all keys are found, it try dumping card content both to file and emulator memory.",
"hf mf autopwn\n"
"hf mf autopwn -s 0 -a -k FFFFFFFFFFFF --> target MFC 1K card, Sector 0 with known key A 'FFFFFFFFFFFF'\n"
"hf mf autopwn --1k -f mfc_default_keys --> target MFC 1K card, default dictionary\n"
"hf mf autopwn --1k -s 0 -a -k FFFFFFFFFFFF -f mfc_default_keys --> combo of the two above samples"
);
void *argtable[] = {
arg_param_begin,
arg_str0("k", "key", "<hex>", "Known key, 12 hex bytes"),
arg_int0("s", "sector", "<dec>", "Input sector number"),
arg_lit0("a", NULL, "Input key A (def)"),
arg_lit0("b", NULL, "Input key B"),
arg_str0("f", "file", "<fn>", "filename of dictionary"),
arg_lit0("s", "slow", "Slower acquisition (required by some non standard cards)"),
arg_lit0("l", "legacy", "legacy mode (use the slow `hf mf chk`)"),
arg_lit0("v", "verbose", "verbose output (statistics)"),
arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (default)"),
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
arg_lit0(NULL, "in", "None (use CPU regular instruction set)"),
#if defined(COMPILER_HAS_SIMD)
arg_lit0(NULL, "im", "MMX"),
arg_lit0(NULL, "is", "SSE2"),
arg_lit0(NULL, "ia", "AVX"),
arg_lit0(NULL, "i2", "AVX2"),
#endif
#if defined(COMPILER_HAS_SIMD_AVX512)
arg_lit0(NULL, "i5", "AVX512"),
#endif
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int keylen = 0;
uint8_t key[6] = {0}; uint8_t key[6] = {0};
int32_t res = CLIParamHexToBuf(arg_get_str(ctx, 1), key, sizeof(key), &keylen);
if (res) {
CLIParserFree(ctx);
PrintAndLogEx(FAILED, "Error parsing key bytes");
return PM3_EINVARG;
}
bool know_target_key = (keylen == 6);
uint8_t sectorno = arg_get_u32_def(ctx, 2, 0);
uint8_t keytype = MF_KEY_A;
if (arg_get_lit(ctx, 3) && arg_get_lit(ctx, 4)) {
CLIParserFree(ctx);
PrintAndLogEx(WARNING, "Input key type must be A or B");
return PM3_EINVARG;
} else if (arg_get_lit(ctx, 4)) {
keytype = MF_KEY_B;
}
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool has_filename = (fnlen > 0);
bool slow = arg_get_lit(ctx, 6);
bool legacy_mfchk = arg_get_lit(ctx, 7);
bool verbose = arg_get_lit(ctx, 8);
bool m0 = arg_get_lit(ctx, 9);
bool m1 = arg_get_lit(ctx, 10);
bool m2 = arg_get_lit(ctx, 11);
bool m4 = arg_get_lit(ctx, 12);
bool in = arg_get_lit(ctx, 13);
#if defined(COMPILER_HAS_SIMD)
bool im = arg_get_lit(ctx, 14);
bool is = arg_get_lit(ctx, 15);
bool ia = arg_get_lit(ctx, 16);
bool i2 = arg_get_lit(ctx, 17);
#endif
#if defined(COMPILER_HAS_SIMD_AVX512)
bool i5 = arg_get_lit(ctx, 18);
#endif
CLIParserFree(ctx);
//validations
if ((m0 + m1 + m2 + m4) > 1) {
PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
return PM3_EINVARG;
} else if ((m0 + m1 + m2 + m4) == 0) {
m1 = true;
}
uint8_t sector_cnt = MIFARE_1K_MAXSECTOR;
uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
if (m0) {
sector_cnt = MIFARE_MINI_MAXSECTOR;
block_cnt = MIFARE_MINI_MAXBLOCK;
} else if (m1) {
sector_cnt = MIFARE_1K_MAXSECTOR;
block_cnt = MIFARE_1K_MAXBLOCK;
} else if (m2) {
sector_cnt = MIFARE_2K_MAXSECTOR;
block_cnt = MIFARE_2K_MAXBLOCK;
} else if (m4) {
sector_cnt = MIFARE_4K_MAXSECTOR;
block_cnt = MIFARE_4K_MAXBLOCK;
} else {
PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
return PM3_EINVARG;
}
// set SIM instructions
SetSIMDInstr(SIMD_AUTO);
#if defined(COMPILER_HAS_SIMD_AVX512)
if (i5)
SetSIMDInstr(SIMD_AVX512);
#endif
#if defined(COMPILER_HAS_SIMD)
if (i2)
SetSIMDInstr(SIMD_AVX2);
if (ia)
SetSIMDInstr(SIMD_AVX);
if (is)
SetSIMDInstr(SIMD_SSE2);
if (im)
SetSIMDInstr(SIMD_MMX);
#endif
if (in)
SetSIMDInstr(SIMD_NONE);
// Nested and Hardnested parameter
uint64_t key64 = 0; uint64_t key64 = 0;
bool calibrate = true; bool calibrate = true;
// Attack key storage variables // Attack key storage variables
uint8_t *keyBlock = NULL; uint8_t *keyBlock = NULL;
uint32_t key_cnt = 0; uint32_t key_cnt = 0;
sector_t *e_sector; sector_t *e_sector;
uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR;
int block_cnt = MIFARE_1K_MAXBLOCK;
uint8_t tmp_key[6] = {0}; uint8_t tmp_key[6] = {0};
bool know_target_key = false;
// For the timer
uint64_t t1;
// Parameters and dictionary file
char filename[FILE_PATH_SIZE] = {0};
uint8_t cmdp = 0;
char ctmp;
// Nested and Hardnested returned status // Nested and Hardnested returned status
uint64_t foundkey = 0; uint64_t foundkey = 0;
int isOK = 0; int isOK = 0;
int current_sector_i = 0, current_key_type_i = 0; int current_sector_i = 0, current_key_type_i = 0;
// Dumping and transfere to simulater memory // Dumping and transfere to simulater memory
uint8_t block[16] = {0x00}; uint8_t block[16] = {0x00};
uint8_t *dump;
int bytes; int bytes;
// Settings // Settings
bool slow = false;
bool legacy_mfchk = false;
int prng_type = PM3_EUNDEF; int prng_type = PM3_EUNDEF;
int has_staticnonce; int has_staticnonce;
bool verbose = false;
bool has_filename = false;
bool errors = false;
uint8_t num_found_keys = 0; uint8_t num_found_keys = 0;
// Parse the options given by the user // ------------------------------
while ((ctmp = param_getchar(Cmd, cmdp)) && !errors) {
switch (tolower(ctmp)) {
case 'h':
return usage_hf14_autopwn();
case 'f':
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) {
PrintAndLogEx(FAILED, "Filename too long");
errors = true;
} else {
has_filename = true;
}
cmdp += 2;
break;
case 'l':
legacy_mfchk = true;
cmdp++;
break;
case 'v':
verbose = true;
cmdp++;
break;
case '*':
// Get the number of sectors
sectors_cnt = NumOfSectors(param_getchar(Cmd, cmdp + 1));
block_cnt = NumOfBlocks(param_getchar(Cmd, cmdp + 1));
cmdp += 2;
break;
case 'k':
// Get the known block number
if (param_getchar(Cmd, cmdp + 1) == 0x00) {
errors = true;
break;
}
blockNo = param_get8(Cmd, cmdp + 1);
// Get the knonwn block type
ctmp = tolower(param_getchar(Cmd, cmdp + 2));
if (ctmp != 'a' && ctmp != 'b') {
PrintAndLogEx(WARNING, "Key type must be A or B");
errors = true;
break;
}
if (ctmp != 'a') {
keyType = MF_KEY_B;
}
// Get the known block key
if (param_gethex(Cmd, cmdp + 3, key, 12)) {
PrintAndLogEx(WARNING, "Key must include 12 HEX symbols");
errors = true;
}
know_target_key = true;
cmdp += 3;
case 's':
slow = true;
cmdp++;
break;
case 'i':
SetSIMDInstr(SIMD_AUTO);
ctmp = tolower(param_getchar(Cmd, cmdp + 1));
switch (ctmp) {
#if defined(COMPILER_HAS_SIMD_AVX512)
case '5':
SetSIMDInstr(SIMD_AVX512);
break;
#endif
#if defined(COMPILER_HAS_SIMD)
case '2':
SetSIMDInstr(SIMD_AVX2);
break;
case 'a':
SetSIMDInstr(SIMD_AVX);
break;
case 's':
SetSIMDInstr(SIMD_SSE2);
break;
case 'm':
SetSIMDInstr(SIMD_MMX);
break;
#endif
case 'n':
SetSIMDInstr(SIMD_NONE);
break;
default:
PrintAndLogEx(WARNING, "Unknown SIMD type. %c", ctmp);
return PM3_EINVARG;
}
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", ctmp);
return usage_hf14_autopwn();
}
}
if (errors) {
return usage_hf14_autopwn();
}
// create/initialize key storage structure // create/initialize key storage structure
int32_t res = initSectorTable(&e_sector, sectors_cnt); res = initSectorTable(&e_sector, sector_cnt);
if (res != sectors_cnt) { if (res != sector_cnt) {
free(e_sector); free(e_sector);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -2039,10 +2000,10 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
// print parameters // print parameters
if (verbose) { if (verbose) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " ======================="); PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " =======================");
PrintAndLogEx(INFO, " card sectors .. " _YELLOW_("%d"), sectors_cnt); PrintAndLogEx(INFO, " card sectors .. " _YELLOW_("%d"), sector_cnt);
PrintAndLogEx(INFO, " key supplied .. " _YELLOW_("%s"), know_target_key ? "True" : "False"); PrintAndLogEx(INFO, " key supplied .. " _YELLOW_("%s"), know_target_key ? "True" : "False");
PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), blockNo); PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), sectorno);
PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), (keyType == MF_KEY_B) ? 'B' : 'A'); PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), (keytype == MF_KEY_B) ? 'B' : 'A');
PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex(key, sizeof(key))); PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex(key, sizeof(key)));
if (has_staticnonce == NONCE_STATIC) if (has_staticnonce == NONCE_STATIC)
@ -2059,7 +2020,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
} }
// Start the timer // Start the timer
t1 = msclock(); uint64_t t1 = msclock();
// check the user supplied key // check the user supplied key
if (know_target_key == false) { if (know_target_key == false) {
@ -2069,30 +2030,30 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("START KNOWN KEY ATTACK") " ======================="); PrintAndLogEx(INFO, "======================= " _YELLOW_("START KNOWN KEY ATTACK") " =======================");
} }
if (mfCheckKeys(FirstBlockOfSector(blockNo), keyType, true, 1, key, &key64) == PM3_SUCCESS) { if (mfCheckKeys(FirstBlockOfSector(sectorno), keytype, true, 1, key, &key64) == PM3_SUCCESS) {
PrintAndLogEx(INFO, "target sector:%3u key type: %c -- using valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)", PrintAndLogEx(INFO, "target sector %3u key type %c -- using valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
blockNo, sectorno,
(keyType == MF_KEY_B) ? 'B' : 'A', (keytype == MF_KEY_B) ? 'B' : 'A',
sprint_hex(key, sizeof(key)) sprint_hex(key, sizeof(key))
); );
// Store the key for the nested / hardnested attack (if supplied by the user) // Store the key for the nested / hardnested attack (if supplied by the user)
e_sector[blockNo].Key[keyType] = key64; e_sector[sectorno].Key[keytype] = key64;
e_sector[blockNo].foundKey[keyType] = 'U'; e_sector[sectorno].foundKey[keytype] = 'U';
++num_found_keys; ++num_found_keys;
} else { } else {
know_target_key = false; know_target_key = false;
PrintAndLogEx(FAILED, "Key is wrong. Can't authenticate to sector:"_RED_("%3d") " key type: "_RED_("%c") " key: " _RED_("%s"), PrintAndLogEx(FAILED, "Key is wrong. Can't authenticate to sector"_RED_("%3d") " key type "_RED_("%c") " key " _RED_("%s"),
blockNo, sectorno,
(keyType == MF_KEY_B) ? 'B' : 'A', (keytype == MF_KEY_B) ? 'B' : 'A',
sprint_hex(key, sizeof(key)) sprint_hex(key, sizeof(key))
); );
PrintAndLogEx(WARNING, "falling back to dictionary"); PrintAndLogEx(WARNING, "falling back to dictionary");
} }
// Check if the user supplied key is used by other sectors // Check if the user supplied key is used by other sectors
for (int i = 0; i < sectors_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++) {
if (e_sector[i].foundKey[j] == 0) { if (e_sector[i].foundKey[j] == 0) {
if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, key, &key64) == PM3_SUCCESS) { if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, key, &key64) == PM3_SUCCESS) {
@ -2103,18 +2064,18 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
if (know_target_key == false) { if (know_target_key == false) {
num_to_bytes(e_sector[i].Key[j], 6, key); num_to_bytes(e_sector[i].Key[j], 6, key);
know_target_key = true; know_target_key = true;
blockNo = i; sectorno = i;
keyType = j; keytype = j;
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)", PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
i, i,
j ? 'B' : 'A', (j == MF_KEY_B) ? 'B' : 'A',
sprint_hex(key, sizeof(key)) sprint_hex_inrow(key, sizeof(key))
); );
} else { } else {
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]", PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
i, i,
j ? 'B' : 'A', (j == MF_KEY_B) ? 'B' : 'A',
sprint_hex(key, sizeof(key)) sprint_hex_inrow(key, sizeof(key))
); );
} }
++num_found_keys; ++num_found_keys;
@ -2123,7 +2084,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
} }
} }
if (num_found_keys == sectors_cnt * 2) { if (num_found_keys == sector_cnt * 2) {
goto all_found; goto all_found;
} }
} }
@ -2162,7 +2123,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
if (legacy_mfchk) { if (legacy_mfchk) {
PrintAndLogEx(INFO, "." NOLF); PrintAndLogEx(INFO, "." NOLF);
// Check all the sectors // Check all the sectors
for (int i = 0; i < sectors_cnt; i++) { for (int i = 0; i < sector_cnt; i++) {
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
// Check if the key is known // Check if the key is known
if (e_sector[i].foundKey[j] == 0) { if (e_sector[i].foundKey[j] == 0) {
@ -2202,7 +2163,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
if (size == key_cnt - i) if (size == key_cnt - i)
lastChunk = true; lastChunk = true;
res = mfCheckKeys_fast(sectors_cnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false); res = mfCheckKeys_fast(sector_cnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false);
if (firstChunk) if (firstChunk)
firstChunk = false; firstChunk = false;
// all keys, aborted // all keys, aborted
@ -2218,7 +2179,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
} }
// Analyse the dictionary attack // Analyse the dictionary attack
for (int i = 0; i < sectors_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++) {
if (e_sector[i].foundKey[j] == 1) { if (e_sector[i].foundKey[j] == 1) {
e_sector[i].foundKey[j] = 'D'; e_sector[i].foundKey[j] = 'D';
@ -2228,18 +2189,18 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
if (know_target_key == false) { if (know_target_key == false) {
num_to_bytes(e_sector[i].Key[j], 6, key); num_to_bytes(e_sector[i].Key[j], 6, key);
know_target_key = true; know_target_key = true;
blockNo = i; sectorno = i;
keyType = j; keytype = j;
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)", PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
i, i,
j ? 'B' : 'A', (j == MF_KEY_B) ? 'B' : 'A',
sprint_hex(tmp_key, sizeof(tmp_key)) sprint_hex_inrow(tmp_key, sizeof(tmp_key))
); );
} else { } else {
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]", PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
i, i,
j ? 'B' : 'A', (j == MF_KEY_B)? 'B' : 'A',
sprint_hex(tmp_key, sizeof(tmp_key)) sprint_hex_inrow(tmp_key, sizeof(tmp_key))
); );
} }
} }
@ -2253,7 +2214,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
if (verbose) { if (verbose) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " ======================="); PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
} }
isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType + 0x60, &key64); isOK = mfDarkside(FirstBlockOfSector(sectorno), keytype + 0x60, &key64);
switch (isOK) { switch (isOK) {
case -1 : case -1 :
@ -2273,17 +2234,17 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
PrintAndLogEx(WARNING, "\nAborted via keyboard."); PrintAndLogEx(WARNING, "\nAborted via keyboard.");
goto noValidKeyFound; goto noValidKeyFound;
default : default :
PrintAndLogEx(SUCCESS, "\nFound valid key: [ " _GREEN_("%012" PRIx64) " ]\n", key64); PrintAndLogEx(SUCCESS, "\nFound valid key [ " _GREEN_("%012" PRIx64) " ]\n", key64);
break; break;
} }
// Store the keys // Store the keys
num_to_bytes(key64, 6, key); num_to_bytes(key64, 6, key);
e_sector[blockNo].Key[keyType] = key64; e_sector[sectorno].Key[keytype] = key64;
e_sector[blockNo].foundKey[keyType] = 'S'; e_sector[sectorno].foundKey[keytype] = 'S';
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%012" PRIx64) " ] (used for nested / hardnested attack)", PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%012" PRIx64) " ] (used for nested / hardnested attack)",
blockNo, sectorno,
(keyType == MF_KEY_B) ? 'B' : 'A', (keytype == MF_KEY_B) ? 'B' : 'A',
key64 key64
); );
} else { } else {
@ -2302,7 +2263,7 @@ noValidKeyFound:
bool nested_failed = false; bool nested_failed = false;
// Iterate over each sector and key(A/B) // Iterate over each sector and key(A/B)
for (current_sector_i = 0; current_sector_i < sectors_cnt; current_sector_i++) { for (current_sector_i = 0; current_sector_i < sector_cnt; 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++) {
// If the key is already known, just skip it // If the key is already known, just skip it
@ -2310,10 +2271,10 @@ noValidKeyFound:
// Try the found keys are reused // Try the found keys are reused
if (bytes_to_num(tmp_key, 6) != 0) { if (bytes_to_num(tmp_key, 6) != 0) {
// <!> The fast check --> mfCheckKeys_fast(sectors_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);
// <!> 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 < sectors_cnt; i++) { for (int i = 0; i < sector_cnt; i++) {
for (int j = 0; j < 2; j++) { for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
// Check if the sector key is already broken // Check if the sector key is already broken
if (e_sector[i].foundKey[j]) if (e_sector[i].foundKey[j])
continue; continue;
@ -2322,10 +2283,10 @@ noValidKeyFound:
if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, tmp_key, &key64) == PM3_SUCCESS) { if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, tmp_key, &key64) == PM3_SUCCESS) {
e_sector[i].Key[j] = bytes_to_num(tmp_key, 6); e_sector[i].Key[j] = bytes_to_num(tmp_key, 6);
e_sector[i].foundKey[j] = 'R'; e_sector[i].foundKey[j] = 'R';
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]", PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
i, i,
j ? 'B' : 'A', (j == MF_KEY_B) ? 'B' : 'A',
sprint_hex(tmp_key, sizeof(tmp_key)) sprint_hex_inrow(tmp_key, sizeof(tmp_key))
); );
} }
} }
@ -2334,13 +2295,13 @@ noValidKeyFound:
// Clear the last found key // Clear the last found key
num_to_bytes(0, 6, tmp_key); num_to_bytes(0, 6, tmp_key);
if (current_key_type_i == 1) { if (current_key_type_i == MF_KEY_B) {
if (e_sector[current_sector_i].foundKey[0] && !e_sector[current_sector_i].foundKey[1]) { if (e_sector[current_sector_i].foundKey[0] && !e_sector[current_sector_i].foundKey[1]) {
if (verbose) { if (verbose) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("START READ B KEY ATTACK") " ======================="); PrintAndLogEx(INFO, "======================= " _YELLOW_("START READ B KEY ATTACK") " =======================");
PrintAndLogEx(INFO, "reading B key: sector: %3d key type: %c", PrintAndLogEx(INFO, "reading B key of sector %3d with key type %c",
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A'); (current_key_type_i == MF_KEY_B) ? 'B' : 'A');
} }
uint8_t sectrail = (FirstBlockOfSector(current_sector_i) + NumBlocksPerSector(current_sector_i) - 1); uint8_t sectrail = (FirstBlockOfSector(current_sector_i) + NumBlocksPerSector(current_sector_i) - 1);
@ -2364,16 +2325,16 @@ noValidKeyFound:
e_sector[current_sector_i].foundKey[current_key_type_i] = 'A'; e_sector[current_sector_i].foundKey[current_key_type_i] = 'A';
e_sector[current_sector_i].Key[current_key_type_i] = key64; e_sector[current_sector_i].Key[current_key_type_i] = key64;
num_to_bytes(key64, 6, tmp_key); num_to_bytes(key64, 6, tmp_key);
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]", PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', (current_key_type_i == MF_KEY_B) ? 'B' : 'A',
sprint_hex(tmp_key, sizeof(tmp_key)) sprint_hex_inrow(tmp_key, sizeof(tmp_key))
); );
} else { } else {
if (verbose) { if (verbose) {
PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c", PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c",
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A' (current_key_type_i == MF_KEY_B) ? 'B' : 'A'
); );
PrintAndLogEx(INFO, " -- reading the B key was not possible, maybe due to access rights?"); PrintAndLogEx(INFO, " -- reading the B key was not possible, maybe due to access rights?");
@ -2394,12 +2355,12 @@ skipReadBKey:
uint8_t retries = 0; uint8_t retries = 0;
if (verbose) { if (verbose) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("START NESTED ATTACK") " ======================="); PrintAndLogEx(INFO, "======================= " _YELLOW_("START NESTED ATTACK") " =======================");
PrintAndLogEx(INFO, "sector no: %3d, target key type: %c", PrintAndLogEx(INFO, "sector no %3d, target key type %c",
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A'); (current_key_type_i == MF_KEY_B) ? 'B' : 'A');
} }
tryNested: tryNested:
isOK = mfnested(FirstBlockOfSector(blockNo), keyType, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key, calibrate); isOK = mfnested(FirstBlockOfSector(sectorno), keytype, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key, calibrate);
switch (isOK) { switch (isOK) {
case PM3_ETIMEOUT: { case PM3_ETIMEOUT: {
@ -2451,22 +2412,22 @@ tryNested:
tryHardnested: // If the nested attack fails then we try the hardnested attack tryHardnested: // If the nested attack fails then we try the hardnested attack
if (verbose) { if (verbose) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("START HARDNESTED ATTACK") " ======================="); PrintAndLogEx(INFO, "======================= " _YELLOW_("START HARDNESTED ATTACK") " =======================");
PrintAndLogEx(INFO, "sector no: %3d, target key type: %c, Slow: %s", PrintAndLogEx(INFO, "sector no %3d, target key type %c, Slow %s",
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', (current_key_type_i == MF_KEY_B) ? 'B' : 'A',
slow ? "Yes" : "No"); slow ? "Yes" : "No");
} }
isOK = mfnestedhard(FirstBlockOfSector(blockNo), keyType, key, FirstBlockOfSector(current_sector_i), current_key_type_i, NULL, false, false, slow, 0, &foundkey, NULL); isOK = mfnestedhard(FirstBlockOfSector(sectorno), keytype, key, FirstBlockOfSector(current_sector_i), current_key_type_i, NULL, false, false, slow, 0, &foundkey, NULL);
DropField(); DropField();
if (isOK) { if (isOK) {
switch (isOK) { switch (isOK) {
case 1: { case 1: {
PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
break; break;
} }
case 2: { case 2: {
PrintAndLogEx(NORMAL, "\nButton pressed. Aborted."); PrintAndLogEx(NORMAL, "\nButton pressed, user aborted");
break; break;
} }
default: { default: {
@ -2488,22 +2449,22 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
tryStaticnested: tryStaticnested:
if (verbose) { if (verbose) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " ======================="); PrintAndLogEx(INFO, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " =======================");
PrintAndLogEx(INFO, "sector no: %3d, target key type: %c", PrintAndLogEx(INFO, "sector no %3d, target key type %c",
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A'); (current_key_type_i == MF_KEY_B) ? 'B' : 'A');
} }
isOK = mfStaticNested(blockNo, keyType, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key); isOK = mfStaticNested(sectorno, keytype, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key);
DropField(); DropField();
switch (isOK) { switch (isOK) {
case PM3_ETIMEOUT: { case PM3_ETIMEOUT: {
PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
free(e_sector); free(e_sector);
free(fptr); free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
case PM3_EOPABORTED: { case PM3_EOPABORTED: {
PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); PrintAndLogEx(WARNING, "\nButton pressed, user aborted");
free(e_sector); free(e_sector);
free(fptr); free(fptr);
return PM3_EOPABORTED; return PM3_EOPABORTED;
@ -2521,10 +2482,10 @@ tryStaticnested:
// Check if the key was found // Check if the key was found
if (e_sector[current_sector_i].foundKey[current_key_type_i]) { if (e_sector[current_sector_i].foundKey[current_key_type_i]) {
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]", PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
current_sector_i, current_sector_i,
current_key_type_i ? 'B' : 'A', (current_key_type_i == MF_KEY_B) ? 'B' : 'A',
sprint_hex(tmp_key, sizeof(tmp_key)) sprint_hex_inrow(tmp_key, sizeof(tmp_key))
); );
} }
} }
@ -2538,12 +2499,12 @@ all_found:
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
printKeyTable(sectors_cnt, e_sector); printKeyTable(sector_cnt, e_sector);
// Dump the keys // Dump the keys
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
if (createMfcKeyDump(fptr, sectors_cnt, e_sector) != PM3_SUCCESS) { if (createMfcKeyDump(fptr, sector_cnt, e_sector) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to save keys to file"); PrintAndLogEx(ERR, "Failed to save keys to file");
} }
@ -2553,7 +2514,7 @@ all_found:
PrintAndLogEx(SUCCESS, "transferring keys to simulator memory (Cmd Error: 04 can occur)"); PrintAndLogEx(SUCCESS, "transferring keys to simulator memory (Cmd Error: 04 can occur)");
for (current_sector_i = 0; current_sector_i < sectors_cnt; current_sector_i++) { for (current_sector_i = 0; current_sector_i < sector_cnt; current_sector_i++) {
mfEmlGetMem(block, current_sector_i, 1); mfEmlGetMem(block, current_sector_i, 1);
if (e_sector[current_sector_i].foundKey[0]) if (e_sector[current_sector_i].foundKey[0])
num_to_bytes(e_sector[current_sector_i].Key[0], 6, block); num_to_bytes(e_sector[current_sector_i].Key[0], 6, block);
@ -2564,17 +2525,16 @@ all_found:
} }
// use ecfill trick // use ecfill trick
FastDumpWithEcFill(sectors_cnt); FastDumpWithEcFill(sector_cnt);
bytes = block_cnt * MFBLOCK_SIZE; bytes = block_cnt * MFBLOCK_SIZE;
dump = calloc(bytes, sizeof(uint8_t)); uint8_t *dump = calloc(bytes, sizeof(uint8_t));
if (!dump) { if (dump == NULL) {
PrintAndLogEx(ERR, "Fail, cannot allocate memory"); PrintAndLogEx(ERR, "Fail, cannot allocate memory");
free(e_sector); free(e_sector);
free(fptr); free(fptr);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
memset(dump, 0, bytes);
PrintAndLogEx(INFO, "downloading the card content from emulator memory"); PrintAndLogEx(INFO, "downloading the card content from emulator memory");
if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) {
@ -2585,15 +2545,16 @@ all_found:
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
char *fnameptr = GenerateFilename("hf-mf-", "-dump"); free(fptr);
if (fnameptr == NULL) { fptr = GenerateFilename("hf-mf-", "-dump");
if (fptr == NULL) {
free(dump); free(dump);
free(e_sector); free(e_sector);
free(fptr); free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
strcpy(filename, fnameptr); strcpy(filename, fptr);
free(fnameptr); free(fptr);
saveFile(filename, ".bin", dump, bytes); saveFile(filename, ".bin", dump, bytes);
saveFileEML(filename, dump, bytes, MFBLOCK_SIZE); saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
@ -2605,7 +2566,6 @@ all_found:
free(dump); free(dump);
free(e_sector); free(e_sector);
free(fptr);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2632,7 +2592,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
arg_lit0(NULL, "emu", "Fill simulator keys from found keys"), arg_lit0(NULL, "emu", "Fill simulator keys from found keys"),
arg_lit0(NULL, "dump", "Dump found keys to binary file"), arg_lit0(NULL, "dump", "Dump found keys to binary file"),
arg_lit0(NULL, "mem", "Use dictionary from flashmemory"), arg_lit0(NULL, "mem", "Use dictionary from flashmemory"),
arg_str0("f", "file", "<filename>", "filename of dictionary"), arg_str0("f", "file", "<fn>", "filename of dictionary"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -2863,8 +2823,8 @@ out:
conn.block_after_ACK = true; conn.block_after_ACK = true;
uint8_t block[16] = {0x00}; uint8_t block[16] = {0x00};
for (i = 0; i < sectorsCnt; ++i) { for (i = 0; i < sectorsCnt; ++i) {
uint8_t blockno = FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1; uint8_t b = FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1;
mfEmlGetMem(block, blockno, 1); mfEmlGetMem(block, b, 1);
if (e_sector[i].foundKey[0]) if (e_sector[i].foundKey[0])
num_to_bytes(e_sector[i].Key[0], 6, block); num_to_bytes(e_sector[i].Key[0], 6, block);
@ -2876,7 +2836,7 @@ out:
// Disable fast mode on last packet // Disable fast mode on last packet
conn.block_after_ACK = false; conn.block_after_ACK = false;
} }
mfEmlSetMem(block, blockno, 1); mfEmlSetMem(block, b, 1);
} }
PrintAndLogEx(SUCCESS, "Found keys have been transferred to the emulator memory"); PrintAndLogEx(SUCCESS, "Found keys have been transferred to the emulator memory");

View file

@ -16,7 +16,6 @@ hf felica auth1
hf felica auth2 hf felica auth2
hf felica rqspecver hf felica rqspecver
hf felica resetmode hf felica resetmode
hf mf autopwn
lf hitag reader lf hitag reader
lf hitag writer lf hitag writer
lf hitag dump lf hitag dump