Skip to content

Commit

Permalink
add static encrypted nonce detection
Browse files Browse the repository at this point in the history
  • Loading branch information
merlokk committed Dec 11, 2023
1 parent d352f9d commit 91892bc
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 10 deletions.
11 changes: 11 additions & 0 deletions armsrc/appmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -1866,6 +1866,17 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareHasStaticNonce();
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

#ifdef WITH_NFCBARCODE
Expand Down
71 changes: 69 additions & 2 deletions armsrc/mifarecmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ int16_t mifare_cmd_readblocks(uint8_t key_auth_cmd, uint8_t *key, uint8_t read_c
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");
retval = PM3_ESOFT;
goto OUT;
Expand Down Expand Up @@ -158,7 +158,7 @@ int16_t mifare_cmd_writeblocks(uint8_t key_auth_cmd, uint8_t *key, uint8_t write
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");
retval = PM3_ESOFT;
goto OUT;
Expand Down Expand Up @@ -2681,6 +2681,73 @@ void MifareHasStaticNonce(void) {
// 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) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
Expand Down
1 change: 1 addition & 0 deletions armsrc/mifarecmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 MifareCIdent(bool is_mfc); // is "magic chinese" card?
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
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len);
Expand Down
6 changes: 4 additions & 2 deletions armsrc/mifareutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
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:
uint8_t nr[4];
Expand All @@ -159,6 +159,8 @@ int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t bl

// Save the tag nonce (nt)
uint32_t nt = bytes_to_num(receivedAnswer, 4);
if (ntencptr)
*ntencptr = nt;

// ----------------------------- crypto1 create
if (isNested)
Expand Down
2 changes: 1 addition & 1 deletion armsrc/mifareutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
// 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_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_ex(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte);
Expand Down
8 changes: 6 additions & 2 deletions client/src/cmdhfmf.c
Original file line number Diff line number Diff line change
Expand Up @@ -8875,7 +8875,7 @@ static int CmdHF14AMfInfo(const char *Cmd) {
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[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;

PrintAndLogEx(INFO, "--- " _CYAN_("Backdoors Information") "---------------------");
Expand Down Expand Up @@ -8951,7 +8951,11 @@ static int CmdHF14AMfInfo(const char *Cmd) {

// detect static encrypted nonce
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)
Expand Down
27 changes: 27 additions & 0 deletions client/src/mifare/mifarehost.c
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,33 @@ int detect_classic_static_nonce(void) {
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. */
int detect_mf_magic(bool is_mfc) {

Expand Down
1 change: 1 addition & 0 deletions client/src/mifare/mifarehost.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ int detect_classic_prng(void);
int detect_classic_nackbug(bool verbose);
int detect_mf_magic(bool is_mfc);
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);
int read_mfc_ev1_signature(uint8_t *signature);

Expand Down
8 changes: 5 additions & 3 deletions include/pm3_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ typedef struct {

#define CMD_HF_MIFARE_NACK_DETECT 0x0730
#define CMD_HF_MIFARE_STATIC_NONCE 0x0731
#define CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE 0x0732

// MFU OTP TearOff
#define CMD_HF_MFU_OTP_TEAROFF 0x0740
Expand Down Expand Up @@ -740,9 +741,10 @@ typedef struct {
#define MODE_FULLSIM 2

// Static Nonce detection
#define NONCE_FAIL 0x01
#define NONCE_NORMAL 0x02
#define NONCE_STATIC 0x03
#define NONCE_FAIL 0x01
#define NONCE_NORMAL 0x02
#define NONCE_STATIC 0x03
#define NONCE_STATIC_ENC 0x04

// Dbprintf flags
#define FLAG_RAWPRINT 0x00
Expand Down

0 comments on commit 91892bc

Please sign in to comment.