mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
hf mf info: add detection for unknown backdoor keys and for some backdoor variants
This commit is contained in:
parent
c25dbf8f21
commit
66fc610a66
4 changed files with 103 additions and 13 deletions
|
@ -3,6 +3,7 @@ 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...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Changed `hf mf info` - add detection for unknown backdoor keys and for some backdoor variants (@doegox)
|
||||
- Changed `mqtt` commnands - now honors preference settings (@iceman1001)
|
||||
- Changed `prefs` - now handles MQTT settings too (@iceman1001)
|
||||
- Fixed `mqtt` segfault and gdb warning under windows (proper thread stopping and socket handling). (@virtyvoid)
|
||||
|
|
|
@ -10342,7 +10342,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
|||
PrintAndLogEx(SUCCESS, "Sector 0 key A... " _GREEN_("%012" PRIX64), e_sector[0].Key[MF_KEY_A]);
|
||||
|
||||
num_to_bytes(e_sector[0].Key[MF_KEY_A], MIFARE_KEY_SIZE, fkey);
|
||||
if (mf_read_block(0, MF_KEY_A, key, blockdata) == PM3_SUCCESS) {
|
||||
if (mf_read_block(0, MF_KEY_A, fkey, blockdata) == PM3_SUCCESS) {
|
||||
fKeyType = MF_KEY_A;
|
||||
}
|
||||
}
|
||||
|
@ -10352,7 +10352,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
|||
|
||||
if (fKeyType == 0xFF) {
|
||||
num_to_bytes(e_sector[0].Key[MF_KEY_B], MIFARE_KEY_SIZE, fkey);
|
||||
if (mf_read_block(0, MF_KEY_B, key, blockdata) == PM3_SUCCESS) {
|
||||
if (mf_read_block(0, MF_KEY_B, fkey, blockdata) == PM3_SUCCESS) {
|
||||
fKeyType = MF_KEY_B;
|
||||
}
|
||||
}
|
||||
|
@ -10361,33 +10361,56 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
|||
if (e_sector[1].foundKey[MF_KEY_A]) {
|
||||
PrintAndLogEx(SUCCESS, "Sector 1 key A... " _GREEN_("%012" PRIX64), e_sector[1].Key[MF_KEY_A]);
|
||||
}
|
||||
|
||||
if (e_sector[1].foundKey[MF_KEY_B]) {
|
||||
PrintAndLogEx(SUCCESS, "Sector 1 key B... " _GREEN_("%012" PRIX64), e_sector[1].Key[MF_KEY_B]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t k08s[MIFARE_KEY_SIZE] = {0xA3, 0x96, 0xEF, 0xA4, 0xE2, 0x4F};
|
||||
uint8_t k08[MIFARE_KEY_SIZE] = {0xA3, 0x16, 0x67, 0xA8, 0xCE, 0xC1};
|
||||
uint8_t k32[MIFARE_KEY_SIZE] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60};
|
||||
uint8_t k32n[MIFARE_KEY_SIZE] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60};
|
||||
uint8_t k32n2[MIFARE_KEY_SIZE] = {0x73, 0xB9, 0x83, 0x6C, 0xF1, 0x68};
|
||||
if (mf_read_block(0, 4, k08s, blockdata) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08s, sizeof(k08s)));
|
||||
fKeyType = MF_KEY_BD;
|
||||
memcpy(fkey, k08s, sizeof(fkey));
|
||||
|
||||
} else if (mf_read_block(0, 4, k08, blockdata) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08, sizeof(k08)));
|
||||
fKeyType = MF_KEY_BD;
|
||||
memcpy(fkey, k08, sizeof(fkey));
|
||||
} else if (mf_read_block(0, 4, k32, blockdata) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k32, sizeof(k32)));
|
||||
} else if (mf_read_block(0, 4, k32n, blockdata) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k32n, sizeof(k32n)));
|
||||
fKeyType = MF_KEY_BD;
|
||||
memcpy(fkey, k32, sizeof(fkey));
|
||||
memcpy(fkey, k32n, sizeof(fkey));
|
||||
} else if (mf_read_block(0, 4, k32n2, blockdata) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k32n2, sizeof(k32n2)));
|
||||
fKeyType = MF_KEY_BD;
|
||||
memcpy(fkey, k32n2, sizeof(fkey));
|
||||
}
|
||||
|
||||
if ((fKeyType == MF_KEY_A) || (fKeyType == MF_KEY_B)) {
|
||||
// we've a key but not a backdoor key
|
||||
uint8_t blockdata2[MFBLOCK_SIZE] = {0};
|
||||
if (mf_read_block(0, fKeyType + 4, key, blockdata2) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Backdoor key..... " _GREEN_("same as keyA/keyB"));
|
||||
} else if (detect_classic_auth(MF_KEY_BD)) {
|
||||
PrintAndLogEx(SUCCESS, "Backdoor key..... " _RED_("detected but unknown!"));
|
||||
PrintAndLogEx(HINT, "Hint: Try........ "
|
||||
_YELLOW_("hf mf nested --blk 0 -%s -k %s --tblk 0 --tc 4"),
|
||||
(fKeyType == MF_KEY_A) ? "a" : "b", sprint_hex_inrow(fkey, sizeof(fkey)));
|
||||
fKeyType = MF_KEY_BD;
|
||||
}
|
||||
}
|
||||
|
||||
if (fKeyType != 0xFF) {
|
||||
PrintAndLogEx(SUCCESS, "Block 0.... %s | " NOLF, sprint_hex_inrow(blockdata, MFBLOCK_SIZE));
|
||||
PrintAndLogEx(SUCCESS, "Block 0.......... %s | " NOLF, sprint_hex_inrow(blockdata, MFBLOCK_SIZE));
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_ascii(blockdata + 8, 8));
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint"));
|
||||
bool expect_static_enc_nonce = false;
|
||||
|
||||
if (fKeyType != 0xFF) {
|
||||
// cards with known backdoor
|
||||
|
@ -10397,15 +10420,23 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
|||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08s, sizeof(fkey)) == 0
|
||||
&& card.sak == 0x08 && memcmp(blockdata + 5, "\x08\x04\x00", 3) == 0
|
||||
&& (blockdata[8] == 0x03 || blockdata[8] == 0x04) && blockdata[15] == 0x90) {
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF08S");
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF08S %02X%02X", blockdata[8], blockdata[15]);
|
||||
expect_static_enc_nonce = true;
|
||||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08s, sizeof(fkey)) == 0
|
||||
&& card.sak == 0x08 && memcmp(blockdata + 5, "\x08\x04\x00", 3) == 0
|
||||
&& (blockdata[8] == 0x03 || blockdata[8] == 0x04) && blockdata[15] == 0x91) {
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF08S %02X%02X without static enc nonce", blockdata[8], blockdata[15]);
|
||||
expect_static_enc_nonce = false;
|
||||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08s, sizeof(fkey)) == 0
|
||||
&& card.sak == 0x08 && memcmp(blockdata + 5, "\x00\x03\x00\x10", 4) == 0
|
||||
&& blockdata[15] == 0x90) {
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF08S-7B");
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF08S-7B %02X%02X", blockdata[8], blockdata[15]);
|
||||
expect_static_enc_nonce = true;
|
||||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08, sizeof(fkey)) == 0
|
||||
&& card.sak == 0x08 && memcmp(blockdata + 5, "\x08\x04\x00", 3) == 0
|
||||
&& blockdata[15] == 0x98) {
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF08S **98");
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF08S %02X%02X", blockdata[8], blockdata[15]);
|
||||
expect_static_enc_nonce = true;
|
||||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08, sizeof(fkey)) == 0
|
||||
&& card.sak == 0x08 && memcmp(blockdata + 5, "\x08\x04\x00", 3) == 0
|
||||
&& (blockdata[8] >= 0x01 && blockdata[8] <= 0x03) && blockdata[15] == 0x1D) {
|
||||
|
@ -10414,9 +10445,12 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
|||
&& card.sak == 0x08 && memcmp(blockdata + 5, "\x00\x01\x00\x10", 4) == 0
|
||||
&& blockdata[15] == 0x1D) {
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF08-7B");
|
||||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k32, sizeof(fkey)) == 0
|
||||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k32n, sizeof(fkey)) == 0
|
||||
&& card.sak == 0x18 && memcmp(blockdata + 5, "\x18\x02\x00\x46\x44\x53\x37\x30\x56\x30\x31", 11) == 0) {
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF32");
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF32N");
|
||||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k32n2, sizeof(fkey)) == 0
|
||||
&& card.sak == 0x18 && memcmp(blockdata + 5, "\x18\x02\x00\x46\x44\x53\x37\x30\x56\x30\x31", 11) == 0) {
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF32N (variant)");
|
||||
} else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08, sizeof(fkey)) == 0
|
||||
&& card.sak == 0x20 && memcmp(blockdata + 8, "\x62\x63\x64\x65\x66\x67\x68\x69", 8) == 0) {
|
||||
PrintAndLogEx(SUCCESS, "Fudan FM11RF32 (SAK=20)");
|
||||
|
@ -10499,6 +10533,9 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
|||
PrintAndLogEx(FAILED, "Prng........ " _RED_("fail"));
|
||||
}
|
||||
|
||||
bool tested_static_nonce = false;
|
||||
int result_static_nonce = 0;
|
||||
|
||||
// detect static encrypted nonce
|
||||
if (keylen == MIFARE_KEY_SIZE) {
|
||||
res = detect_classic_static_encrypted_nonce(blockn, keytype, key);
|
||||
|
@ -10512,6 +10549,8 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
|||
PrintAndLogEx(SUCCESS, "Static enc nonce... " _RED_("yes"));
|
||||
fKeyType = 0xFF; // dont detect twice
|
||||
}
|
||||
result_static_nonce = res;
|
||||
tested_static_nonce = true;
|
||||
}
|
||||
|
||||
if (fKeyType != 0xFF) {
|
||||
|
@ -10523,6 +10562,16 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
|||
} else if (res == NONCE_STATIC_ENC) {
|
||||
PrintAndLogEx(SUCCESS, "Static enc nonce... " _RED_("yes"));
|
||||
}
|
||||
result_static_nonce = res;
|
||||
tested_static_nonce = true;
|
||||
}
|
||||
if (tested_static_nonce) {
|
||||
if ((result_static_nonce == NONCE_STATIC_ENC) && (!expect_static_enc_nonce)) {
|
||||
PrintAndLogEx(WARNING, "Static enc nonce detected on a card not supposed to support it, please report... ");
|
||||
}
|
||||
if ((result_static_nonce != NONCE_STATIC_ENC) && (expect_static_enc_nonce)) {
|
||||
PrintAndLogEx(WARNING, "Static enc nonce not detected on a card supposed to support it, please report... ");
|
||||
}
|
||||
}
|
||||
|
||||
if (do_nack_test) {
|
||||
|
|
|
@ -1418,6 +1418,45 @@ int detect_classic_prng(void) {
|
|||
uint32_t nonce = bytes_to_num(respA.data.asBytes, respA.oldarg[0]);
|
||||
return validate_prng_nonce(nonce);
|
||||
}
|
||||
|
||||
|
||||
/* Detect supported Auth,
|
||||
* function performs a partial AUTH, where it tries to authenticate against block0, but only collects tag nonce.
|
||||
* @returns
|
||||
* TRUE if tag replies with a nonce
|
||||
* FALSE is tag does not reply with a nonce
|
||||
*/
|
||||
int detect_classic_auth(uint8_t key_type) {
|
||||
|
||||
PacketResponseNG resp, respA;
|
||||
uint8_t cmd[] = {MIFARE_AUTH_KEYA + key_type, 0x00};
|
||||
uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, flags, sizeof(cmd), 0, cmd, sizeof(cmd));
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// if select tag failed.
|
||||
if (resp.oldarg[0] == 0) {
|
||||
PrintAndLogEx(ERR, "error: selecting tag failed, can't detect nonce\n");
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
if (WaitForResponseTimeout(CMD_ACK, &respA, 2500) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// check respA
|
||||
if (respA.oldarg[0] != 4) {
|
||||
PrintAndLogEx(ERR, "PRNG data error: Wrong length: %"PRIu64, respA.oldarg[0]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Detect Mifare Classic NACK bug
|
||||
|
||||
returns:
|
||||
|
|
|
@ -110,6 +110,7 @@ int mf_chinese_gen_4_set_block(uint8_t blockNo, uint8_t *block, uint8_t *key);
|
|||
int try_decrypt_word(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
|
||||
|
||||
int detect_classic_prng(void);
|
||||
int detect_classic_auth(uint8_t key_type);
|
||||
int detect_classic_nackbug(bool verbose);
|
||||
uint16_t detect_mf_magic(bool is_mfc, uint8_t key_type, uint64_t key);
|
||||
int detect_classic_static_nonce(void);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue