mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
add static encrypted nonce detection
This commit is contained in:
parent
d352f9d44e
commit
91892bc1bf
9 changed files with 125 additions and 10 deletions
|
@ -1866,6 +1866,17 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
MifareHasStaticNonce();
|
MifareHasStaticNonce();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE: {
|
||||||
|
struct p {
|
||||||
|
uint8_t block_no;
|
||||||
|
uint8_t key_type;
|
||||||
|
uint8_t key[6];
|
||||||
|
} PACKED;
|
||||||
|
struct p *payload = (struct p *) packet->data.asBytes;
|
||||||
|
|
||||||
|
MifareHasStaticEncryptedNonce(payload->block_no, payload->key_type, payload->key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_NFCBARCODE
|
#ifdef WITH_NFCBARCODE
|
||||||
|
|
|
@ -90,7 +90,7 @@ int16_t mifare_cmd_readblocks(uint8_t key_auth_cmd, uint8_t *key, uint8_t read_c
|
||||||
goto OUT;
|
goto OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mifare_classic_authex_cmd(pcs, cuid, block_no, key_auth_cmd, ui64key, AUTH_FIRST, NULL, NULL)) {
|
if (mifare_classic_authex_cmd(pcs, cuid, block_no, key_auth_cmd, ui64key, AUTH_FIRST, NULL, NULL, NULL)) {
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
|
||||||
retval = PM3_ESOFT;
|
retval = PM3_ESOFT;
|
||||||
goto OUT;
|
goto OUT;
|
||||||
|
@ -158,7 +158,7 @@ int16_t mifare_cmd_writeblocks(uint8_t key_auth_cmd, uint8_t *key, uint8_t write
|
||||||
goto OUT;
|
goto OUT;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mifare_classic_authex_cmd(pcs, cuid, block_no, key_auth_cmd, ui64key, AUTH_FIRST, NULL, NULL)) {
|
if (mifare_classic_authex_cmd(pcs, cuid, block_no, key_auth_cmd, ui64key, AUTH_FIRST, NULL, NULL, NULL)) {
|
||||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
|
||||||
retval = PM3_ESOFT;
|
retval = PM3_ESOFT;
|
||||||
goto OUT;
|
goto OUT;
|
||||||
|
@ -2681,6 +2681,73 @@ OUT:
|
||||||
// 2B F9 1C 1B D5 08 48 48 03 A4 B1 B1 75 FF 2D 90
|
// 2B F9 1C 1B D5 08 48 48 03 A4 B1 B1 75 FF 2D 90
|
||||||
// ^^ ^^
|
// ^^ ^^
|
||||||
|
|
||||||
|
void MifareHasStaticEncryptedNonce(uint8_t block_no, uint8_t key_type, uint8_t *key) {
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
|
||||||
|
clear_trace();
|
||||||
|
set_tracing(true);
|
||||||
|
|
||||||
|
int retval = PM3_SUCCESS;
|
||||||
|
uint8_t *uid = BigBuf_malloc(10);
|
||||||
|
memset(uid, 0x00, 10);
|
||||||
|
|
||||||
|
uint8_t data[1] = { NONCE_FAIL };
|
||||||
|
struct Crypto1State mpcs = {0, 0};
|
||||||
|
struct Crypto1State *pcs;
|
||||||
|
pcs = &mpcs;
|
||||||
|
uint64_t ui64key = bytes_to_num(key, 6);
|
||||||
|
|
||||||
|
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||||
|
|
||||||
|
iso14a_card_select_t card_info;
|
||||||
|
uint32_t cuid = 0;
|
||||||
|
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||||
|
retval = PM3_ESOFT;
|
||||||
|
goto OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t key_auth_cmd = MIFARE_AUTH_KEYA + (key_type & 1);
|
||||||
|
if (mifare_classic_authex_cmd(pcs, cuid, block_no, key_auth_cmd, ui64key, AUTH_FIRST, NULL, NULL, NULL)) {
|
||||||
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
|
||||||
|
retval = PM3_ESOFT;
|
||||||
|
goto OUT;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t nt = 0;
|
||||||
|
uint8_t enc_counter = 0;
|
||||||
|
uint32_t ntenc = 0;
|
||||||
|
uint32_t oldntenc = 0;
|
||||||
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
|
if (mifare_classic_authex_cmd(pcs, cuid, block_no, key_auth_cmd, ui64key, AUTH_NESTED, &nt, &ntenc, NULL)) {
|
||||||
|
if (g_dbglevel >= DBG_ERROR) Dbprintf("Auth error");
|
||||||
|
retval = PM3_ESOFT;
|
||||||
|
goto OUT;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (g_dbglevel >= DBG_INFO)
|
||||||
|
Dbprintf("nt: %x, nt encoded: %x", nt, ntenc);
|
||||||
|
|
||||||
|
if (oldntenc == 0)
|
||||||
|
oldntenc = ntenc;
|
||||||
|
else if (ntenc == oldntenc)
|
||||||
|
enc_counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc_counter) {
|
||||||
|
data[0] = NONCE_STATIC_ENC;
|
||||||
|
} else {
|
||||||
|
data[0] = NONCE_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
OUT:
|
||||||
|
crypto1_deinit(pcs);
|
||||||
|
|
||||||
|
reply_ng(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE, retval, data, sizeof(data));
|
||||||
|
// turns off
|
||||||
|
OnSuccessMagic();
|
||||||
|
BigBuf_free();
|
||||||
|
}
|
||||||
|
|
||||||
void OnSuccessMagic(void) {
|
void OnSuccessMagic(void) {
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
|
|
|
@ -49,6 +49,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work wi
|
||||||
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
|
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
|
||||||
void MifareCIdent(bool is_mfc); // is "magic chinese" card?
|
void MifareCIdent(bool is_mfc); // is "magic chinese" card?
|
||||||
void MifareHasStaticNonce(void); // Has the tag a static nonce?
|
void MifareHasStaticNonce(void); // Has the tag a static nonce?
|
||||||
|
void MifareHasStaticEncryptedNonce(uint8_t block_no, uint8_t key_type, uint8_t *key); // Has the tag a static encrypted nonce?
|
||||||
|
|
||||||
// MFC GEN3
|
// MFC GEN3
|
||||||
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len);
|
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len);
|
||||||
|
|
|
@ -142,9 +142,9 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo,
|
||||||
return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL);
|
return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL);
|
||||||
}
|
}
|
||||||
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) {
|
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) {
|
||||||
return mifare_classic_authex_cmd(pcs, uid, blockNo, (keyType & 1) ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, ui64Key, isNested, ntptr, timing);
|
return mifare_classic_authex_cmd(pcs, uid, blockNo, (keyType & 1) ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, ui64Key, isNested, ntptr, NULL, timing);
|
||||||
}
|
}
|
||||||
int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t cmd, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) {
|
int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t cmd, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *ntencptr, uint32_t *timing) {
|
||||||
|
|
||||||
// "random" reader nonce:
|
// "random" reader nonce:
|
||||||
uint8_t nr[4];
|
uint8_t nr[4];
|
||||||
|
@ -159,6 +159,8 @@ int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
|
||||||
|
|
||||||
// Save the tag nonce (nt)
|
// Save the tag nonce (nt)
|
||||||
uint32_t nt = bytes_to_num(receivedAnswer, 4);
|
uint32_t nt = bytes_to_num(receivedAnswer, 4);
|
||||||
|
if (ntencptr)
|
||||||
|
*ntencptr = nt;
|
||||||
|
|
||||||
// ----------------------------- crypto1 create
|
// ----------------------------- crypto1 create
|
||||||
if (isNested)
|
if (isNested)
|
||||||
|
|
|
@ -72,7 +72,7 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
|
||||||
// mifare classic
|
// mifare classic
|
||||||
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
|
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
|
||||||
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing);
|
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing);
|
||||||
int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t cmd, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing);
|
int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t cmd, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *ntencptr, uint32_t *timing);
|
||||||
|
|
||||||
int mifare_classic_readblock(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData);
|
int mifare_classic_readblock(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData);
|
||||||
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte);
|
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte);
|
||||||
|
|
|
@ -8875,7 +8875,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
||||||
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]);
|
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]);
|
||||||
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
|
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
|
||||||
|
|
||||||
if (setDeviceDebugLevel(DBG_NONE, false) != PM3_SUCCESS)
|
if (setDeviceDebugLevel(verbose ? DBG_INFO : DBG_NONE, false) != PM3_SUCCESS)
|
||||||
return PM3_EFAILED;
|
return PM3_EFAILED;
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Backdoors Information") "---------------------");
|
PrintAndLogEx(INFO, "--- " _CYAN_("Backdoors Information") "---------------------");
|
||||||
|
@ -8951,7 +8951,11 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
||||||
|
|
||||||
// detect static encrypted nonce
|
// detect static encrypted nonce
|
||||||
if (keyType != 0xff) {
|
if (keyType != 0xff) {
|
||||||
|
res = detect_classic_static_encrypted_nonce(0, keyType, key); // TODO: add block number to the config
|
||||||
|
if (res == NONCE_STATIC)
|
||||||
|
PrintAndLogEx(SUCCESS, "Static nested nonce: " _YELLOW_("yes"));
|
||||||
|
if (res == NONCE_STATIC_ENC)
|
||||||
|
PrintAndLogEx(SUCCESS, "Static encrypted nonce: " _YELLOW_("yes"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_nack_test)
|
if (do_nack_test)
|
||||||
|
|
|
@ -1349,6 +1349,33 @@ int detect_classic_static_nonce(void) {
|
||||||
return NONCE_FAIL;
|
return NONCE_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Detect Mifare Classic static encrypted nonce
|
||||||
|
detects special magic cards that has a static / fixed nonce
|
||||||
|
returns:
|
||||||
|
0 = nonce ok
|
||||||
|
1 = has static/fixed nonce
|
||||||
|
2 = cmd failed
|
||||||
|
3 = has encrypted nonce
|
||||||
|
*/
|
||||||
|
int detect_classic_static_encrypted_nonce(uint8_t block_no, uint8_t key_type, uint8_t *key) {
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
uint8_t cdata[1 + 1 + MIFARE_KEY_SIZE] = {0};
|
||||||
|
cdata[0] = block_no;
|
||||||
|
cdata[1] = key_type;
|
||||||
|
memcpy(&cdata[2], key, MIFARE_KEY_SIZE);
|
||||||
|
SendCommandNG(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE, cdata, sizeof(cdata));
|
||||||
|
PacketResponseNG resp;
|
||||||
|
if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE, &resp, 1000)) {
|
||||||
|
|
||||||
|
if (resp.status == PM3_ESOFT)
|
||||||
|
return NONCE_FAIL;
|
||||||
|
|
||||||
|
return resp.data.asBytes[0];
|
||||||
|
}
|
||||||
|
return NONCE_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
/* try to see if card responses to "Chinese magic backdoor" commands. */
|
/* try to see if card responses to "Chinese magic backdoor" commands. */
|
||||||
int detect_mf_magic(bool is_mfc) {
|
int detect_mf_magic(bool is_mfc) {
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@ 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_classic_static_encrypted_nonce(uint8_t block_no, uint8_t key_type, uint8_t *key);
|
||||||
bool detect_mfc_ev1_signature(void);
|
bool detect_mfc_ev1_signature(void);
|
||||||
int read_mfc_ev1_signature(uint8_t *signature);
|
int read_mfc_ev1_signature(uint8_t *signature);
|
||||||
|
|
||||||
|
|
|
@ -675,6 +675,7 @@ typedef struct {
|
||||||
|
|
||||||
#define CMD_HF_MIFARE_NACK_DETECT 0x0730
|
#define CMD_HF_MIFARE_NACK_DETECT 0x0730
|
||||||
#define CMD_HF_MIFARE_STATIC_NONCE 0x0731
|
#define CMD_HF_MIFARE_STATIC_NONCE 0x0731
|
||||||
|
#define CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE 0x0732
|
||||||
|
|
||||||
// MFU OTP TearOff
|
// MFU OTP TearOff
|
||||||
#define CMD_HF_MFU_OTP_TEAROFF 0x0740
|
#define CMD_HF_MFU_OTP_TEAROFF 0x0740
|
||||||
|
@ -743,6 +744,7 @@ typedef struct {
|
||||||
#define NONCE_FAIL 0x01
|
#define NONCE_FAIL 0x01
|
||||||
#define NONCE_NORMAL 0x02
|
#define NONCE_NORMAL 0x02
|
||||||
#define NONCE_STATIC 0x03
|
#define NONCE_STATIC 0x03
|
||||||
|
#define NONCE_STATIC_ENC 0x04
|
||||||
|
|
||||||
// Dbprintf flags
|
// Dbprintf flags
|
||||||
#define FLAG_RAWPRINT 0x00
|
#define FLAG_RAWPRINT 0x00
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue