adapted hardnested and autopwn to detect MFC Ev1 cards and use the known sector key in the key recovery vectors

This commit is contained in:
iceman1001 2022-11-12 09:39:28 +01:00
commit c393b0caca
6 changed files with 82 additions and 26 deletions

View file

@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Changed `hf mf hardnested` - now can detect and use MFC EV1 signature sector key (@iceman1001)
- Changed `hf mf autopwn` - now can detect and use MFC EV1 signature sector key (@iceman1001)
- Fixed `pm3` shell script now automatically detects WSL2 with USBIPD serial ports (@iceman1001) - Fixed `pm3` shell script now automatically detects WSL2 with USBIPD serial ports (@iceman1001)
- Fixed `trace list -c` - annotation of CRC bytes now is colored or squared if no ansi colors is supported (@iceman1001) - Fixed `trace list -c` - annotation of CRC bytes now is colored or squared if no ansi colors is supported (@iceman1001)
- Fixed `trace list -t mf` - now also finds UID if anticollision is partial captured, to be used for mfkey (@iceman1001) - Fixed `trace list -t mf` - now also finds UID if anticollision is partial captured, to be used for mfkey (@iceman1001)

View file

@ -2318,7 +2318,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
uint8_t signature[32] = {0}; uint8_t signature[32] = {0};
res = detect_mfc_ev1_signature(signature); res = read_mfc_ev1_signature(signature);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
mfc_ev1_print_signature(card.uid, card.uidlen, signature, sizeof(signature)); mfc_ev1_print_signature(card.uid, card.uidlen, signature, sizeof(signature));
} }

View file

@ -1841,19 +1841,22 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf hardnested", CLIParserInit(&ctx, "hf mf hardnested",
"Nested attack for hardened MIFARE Classic cards.\n" "Nested attack for hardened MIFARE Classic cards.\n"
"if card is EV1, command can detect and use known key see example below\n"
"\n"
"`--i<X>` set type of SIMD instructions. Without this flag programs autodetect it.\n" "`--i<X>` set type of SIMD instructions. Without this flag programs autodetect it.\n"
" or \n" " or \n"
" hf mf hardnested -r --tk [known target key]\n" " hf mf hardnested -r --tk [known target key]\n"
"Add the known target key to check if it is present in the remaining key space\n" "Add the known target key to check if it is present in the remaining key space\n"
" hf mf hardnested --blk 0 -a -k A0A1A2A3A4A5 --tblk 4 --ta --tk FFFFFFFFFFFF\n" " hf mf hardnested --blk 0 -a -k A0A1A2A3A4A5 --tblk 4 --ta --tk FFFFFFFFFFFF\n"
, ,
"hf mf hardnested --tblk 4 --ta --> works for MFC EV1\n"
"hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta\n" "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta\n"
"hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -w\n" "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -w\n"
"hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -f nonces.bin -w -s\n" "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -f nonces.bin -w -s\n"
"hf mf hardnested -r\n" "hf mf hardnested -r\n"
"hf mf hardnested -r --tk a0a1a2a3a4a5\n" "hf mf hardnested -r --tk a0a1a2a3a4a5\n"
"hf mf hardnested -t --tk a0a1a2a3a4a5\n" "hf mf hardnested -t --tk a0a1a2a3a4a5\n"
"hf mf hardnested --blk 0 -a -k a0a1a2a3a4a5 --tblk 4 --ta --tk FFFFFFFFFFFF" "hf mf hardnested --blk 0 -a -k a0a1a2a3a4a5 --tblk 4 --ta --tk FFFFFFFFFFFF\n"
); );
void *argtable[] = { void *argtable[] = {
@ -1976,7 +1979,7 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
SetSIMDInstr(SIMD_NONE); SetSIMDInstr(SIMD_NONE);
bool know_target_key = (trg_keylen); bool known_target_key = (trg_keylen);
if (nonce_file_read) { if (nonce_file_read) {
char *fptr = GenerateFilename("hf-mf-", "-nonces.bin"); char *fptr = GenerateFilename("hf-mf-", "-nonces.bin");
@ -2000,7 +2003,15 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
snprintf(filename, FILE_PATH_SIZE, "hf-mf-%s-nonces.bin", uid); snprintf(filename, FILE_PATH_SIZE, "hf-mf-%s-nonces.bin", uid);
} }
if (know_target_key == false && nonce_file_read == false) { // detect MFC EV1 Signature
if (detect_mfc_ev1_signature() && keylen == 0) {
PrintAndLogEx(INFO, "MIFARE Classic EV1 card detected");
blockno = 69;
keytype = MF_KEY_B;
memcpy(key, g_mifare_signature_key_b, sizeof(g_mifare_signature_key_b));
}
if (known_target_key == false && nonce_file_read == false) {
// check if tag doesn't have static nonce // check if tag doesn't have static nonce
if (detect_classic_static_nonce() == NONCE_STATIC) { if (detect_classic_static_nonce() == NONCE_STATIC) {
@ -2021,7 +2032,7 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
trg_blockno, trg_blockno,
(trg_keytype == MF_KEY_B) ? 'B' : 'A', (trg_keytype == MF_KEY_B) ? 'B' : 'A',
trg_key[0], trg_key[1], trg_key[2], trg_key[3], trg_key[4], trg_key[5], trg_key[0], trg_key[1], trg_key[2], trg_key[3], trg_key[4], trg_key[5],
know_target_key ? "" : " (not set)" known_target_key ? "" : " (not set)"
); );
PrintAndLogEx(INFO, "File action: " _YELLOW_("%s") ", Slow: " _YELLOW_("%s") ", Tests: " _YELLOW_("%d"), PrintAndLogEx(INFO, "File action: " _YELLOW_("%s") ", Slow: " _YELLOW_("%s") ", Tests: " _YELLOW_("%d"),
nonce_file_write ? "write" : nonce_file_read ? "read" : "none", nonce_file_write ? "write" : nonce_file_read ? "read" : "none",
@ -2029,7 +2040,7 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
tests); tests);
uint64_t foundkey = 0; uint64_t foundkey = 0;
int16_t isOK = mfnestedhard(blockno, keytype, key, trg_blockno, trg_keytype, know_target_key ? trg_key : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey, filename); int16_t isOK = mfnestedhard(blockno, keytype, key, trg_blockno, trg_keytype, known_target_key ? trg_key : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey, filename);
if ((tests == 0) && IfPm3Iso14443a()) { if ((tests == 0) && IfPm3Iso14443a()) {
DropField(); DropField();
@ -2105,7 +2116,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
bool know_target_key = (keylen == 6); bool known_key = (keylen == 6);
uint8_t sectorno = arg_get_u32_def(ctx, 2, 0); uint8_t sectorno = arg_get_u32_def(ctx, 2, 0);
@ -2223,7 +2234,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
int bytes; int bytes;
// Settings // Settings
int prng_type = PM3_EUNDEF; int prng_type = PM3_EUNDEF;
int has_staticnonce;
uint8_t num_found_keys = 0; uint8_t num_found_keys = 0;
// ------------------------------ // ------------------------------
@ -2247,6 +2257,14 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
iso14a_card_select_t card; iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
// detect MFC EV1 Signature
bool is_ev1 = detect_mfc_ev1_signature();
if (is_ev1) {
// hidden sectors on MFC EV1
sector_cnt += 2;
}
// create/initialize key storage structure // create/initialize key storage structure
uint32_t e_sector_size = sector_cnt > sectorno ? sector_cnt : sectorno + 1; uint32_t e_sector_size = sector_cnt > sectorno ? sector_cnt : sectorno + 1;
res = initSectorTable(&e_sector, e_sector_size); res = initSectorTable(&e_sector, e_sector_size);
@ -2255,11 +2273,31 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
if (is_ev1) {
PrintAndLogEx(INFO, "MIFARE Classic EV1 card detected");
// Store the keys
e_sector[16].Key[MF_KEY_A] = bytes_to_num((uint8_t *)g_mifare_signature_key_a, sizeof(g_mifare_signature_key_a));
e_sector[16].foundKey[MF_KEY_A] = 'D';
e_sector[17].Key[MF_KEY_A] = bytes_to_num((uint8_t *)g_mifare_signature_key_a, sizeof(g_mifare_signature_key_a));
e_sector[17].foundKey[MF_KEY_A] = 'D';
e_sector[17].Key[MF_KEY_B] = bytes_to_num((uint8_t *)g_mifare_signature_key_b, sizeof(g_mifare_signature_key_b));
e_sector[17].foundKey[MF_KEY_B] = 'D';
// use found key if not supplied
if (known_key == false) {
known_key = true;
sectorno = 17;
keytype = MF_KEY_B;
memcpy(key, g_mifare_signature_key_b, sizeof(g_mifare_signature_key_b));
}
}
// read uid to generate a filename for the key file // read uid to generate a filename for the key file
char *fptr = GenerateFilename("hf-mf-", "-key.bin"); char *fptr = GenerateFilename("hf-mf-", "-key.bin");
// check if tag doesn't have static nonce // check if tag doesn't have static nonce
has_staticnonce = detect_classic_static_nonce(); int has_staticnonce = detect_classic_static_nonce();
// card prng type (weak=1 / hard=0 / select/card comm error = negative value) // card prng type (weak=1 / hard=0 / select/card comm error = negative value)
if (has_staticnonce == NONCE_NORMAL) { if (has_staticnonce == NONCE_NORMAL) {
@ -2276,7 +2314,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
if (verbose) { if (verbose) {
PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " ======================="); PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " =======================");
PrintAndLogEx(INFO, " card sectors .. " _YELLOW_("%d"), sector_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"), known_key ? "True" : "False");
PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), sectorno); 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)));
@ -2298,7 +2336,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
uint64_t t1 = msclock(); uint64_t t1 = msclock();
// check the user supplied key // check the user supplied key
if (know_target_key == false) { if (known_key == false) {
PrintAndLogEx(WARNING, "no known key was supplied, key recovery might fail"); PrintAndLogEx(WARNING, "no known key was supplied, key recovery might fail");
} else { } else {
if (verbose) { if (verbose) {
@ -2318,7 +2356,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
++num_found_keys; ++num_found_keys;
} else { } else {
know_target_key = false; known_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"),
sectorno, sectorno,
(keytype == MF_KEY_B) ? 'B' : 'A', (keytype == MF_KEY_B) ? 'B' : 'A',
@ -2336,9 +2374,9 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
e_sector[i].foundKey[j] = 'U'; e_sector[i].foundKey[j] = 'U';
// If the user supplied secctor / keytype was wrong --> just be nice and correct it ;) // If the user supplied secctor / keytype was wrong --> just be nice and correct it ;)
if (know_target_key == false) { if (known_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; known_key = true;
sectorno = 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)",
@ -2461,9 +2499,9 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
num_to_bytes(e_sector[i].Key[j], 6, tmp_key); num_to_bytes(e_sector[i].Key[j], 6, tmp_key);
// Store valid credentials for the nested / hardnested attack if none exist // Store valid credentials for the nested / hardnested attack if none exist
if (know_target_key == false) { if (known_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; known_key = true;
sectorno = 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)",
@ -2483,7 +2521,8 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
} }
// Check if at least one sector key was found // Check if at least one sector key was found
if (know_target_key == false) { if (known_key == false) {
// Check if the darkside attack can be used // Check if the darkside attack can be used
if (prng_type && has_staticnonce != NONCE_STATIC) { if (prng_type && has_staticnonce != NONCE_STATIC) {
if (verbose) { if (verbose) {
@ -2520,6 +2559,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
key64 key64
); );
} else { } else {
noValidKeyFound: noValidKeyFound:
PrintAndLogEx(FAILED, "No usable key was found!"); PrintAndLogEx(FAILED, "No usable key was found!");
free(keyBlock); free(keyBlock);

View file

@ -29,6 +29,7 @@ static const uint64_t g_mifare_default_keys[] = {
0x000000000000, // Blank key 0x000000000000, // Blank key
0xa0a1a2a3a4a5, // NFCForum MAD key 0xa0a1a2a3a4a5, // NFCForum MAD key
0xd3f7d3f7d3f7, // NDEF public key 0xd3f7d3f7d3f7, // NDEF public key
0x4b791bea7bcc, // MFC EV1 Signature B
0xb0b1b2b3b4b5, 0xb0b1b2b3b4b5,
0xaabbccddeeff, 0xaabbccddeeff,
0x1a2b3c4d5e6f, 0x1a2b3c4d5e6f,
@ -75,6 +76,10 @@ static const uint8_t g_mifare_default_key[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0x
static const uint8_t g_mifare_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; static const uint8_t g_mifare_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5};
static const uint8_t g_mifare_mad_key_b[] = {0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A}; static const uint8_t g_mifare_mad_key_b[] = {0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A};
// 16 key B D01AFEEB890A
static const uint8_t g_mifare_signature_key_a[] = {0x5C, 0x8F, 0xF9, 0x99, 0x0D, 0xA2};
static const uint8_t g_mifare_signature_key_b[] = {0x4b, 0x79, 0x1b, 0xea, 0x7b, 0xcc};
static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7};
static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7};
static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7};

View file

@ -35,6 +35,8 @@
#include "util_posix.h" // msclock #include "util_posix.h" // msclock
#include "cmdparser.h" // detection of flash capabilities #include "cmdparser.h" // detection of flash capabilities
#include "cmdflashmemspiffs.h" // upload to flash mem #include "cmdflashmemspiffs.h" // upload to flash mem
#include "mifaredefault.h" // default keys
int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
uint32_t uid = 0; uint32_t uid = 0;
@ -880,7 +882,7 @@ int mfReadSector(uint8_t sectorNo, uint8_t keyType, const uint8_t *key, uint8_t
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int mfReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t *data) { int mfReadBlock(uint8_t blockNo, uint8_t keyType, const uint8_t *key, uint8_t *data) {
mf_readblock_t payload = { mf_readblock_t payload = {
.blockno = blockNo, .blockno = blockNo,
.keytype = keyType .keytype = keyType
@ -1417,15 +1419,20 @@ int detect_mf_magic(bool is_mfc) {
return isGeneration; return isGeneration;
} }
int detect_mfc_ev1_signature(uint8_t *signature) { bool detect_mfc_ev1_signature(void) {
uint64_t key = 0;
int res = mfCheckKeys(69, MF_KEY_B, false, 1, (uint8_t*)g_mifare_signature_key_b, &key);
return (res == PM3_SUCCESS);
}
int read_mfc_ev1_signature(uint8_t *signature) {
if (signature == NULL) { if (signature == NULL) {
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t sign[32] = {0}; uint8_t sign[32] = {0};
uint8_t key[] = {0x4b, 0x79, 0x1b, 0xea, 0x7b, 0xcc}; int res = mfReadBlock(69, MF_KEY_B, g_mifare_signature_key_b, sign);
int res = mfReadBlock(69, 1, key, sign);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
res = mfReadBlock(70, 1, key, sign + 16); res = mfReadBlock(70, MF_KEY_B, g_mifare_signature_key_b, sign + 16);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
memcpy(signature, sign, sizeof(sign)); memcpy(signature, sign, sizeof(sign));
} }

View file

@ -80,7 +80,7 @@ int mfCheckKeys_file(uint8_t *destfn, uint64_t *key);
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, const uint8_t *key, uint64_t *resultkey); int mfKeyBrute(uint8_t blockNo, uint8_t keyType, const uint8_t *key, uint64_t *resultkey);
int mfReadSector(uint8_t sectorNo, uint8_t keyType, const uint8_t *key, uint8_t *data); int mfReadSector(uint8_t sectorNo, uint8_t keyType, const uint8_t *key, uint8_t *data);
int mfReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t *data); int mfReadBlock(uint8_t blockNo, uint8_t keyType, const uint8_t *key, uint8_t *data);
int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
@ -104,7 +104,9 @@ int detect_classic_prng(void);
int detect_classic_nackbug(bool verbose); int detect_classic_nackbug(bool verbose);
int detect_mf_magic(bool is_mfc); int detect_mf_magic(bool is_mfc);
int detect_classic_static_nonce(void); int detect_classic_static_nonce(void);
int detect_mfc_ev1_signature(uint8_t *signature); bool detect_mfc_ev1_signature(void);
int read_mfc_ev1_signature(uint8_t *signature);
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted);
#endif #endif