From 1f4f5febae04c7411333471e4762edb07437e871 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 30 Dec 2023 23:08:58 +0100 Subject: [PATCH] adapt magic detection and textual output. Hf mf info - now uses found keys to send for magic detection --- armsrc/appmain.c | 10 ++- armsrc/iso14443a.c | 5 +- armsrc/mifarecmd.c | 134 ++++++++++++++++----------------- armsrc/mifarecmd.h | 2 +- client/src/cmdhf14a.c | 14 ++-- client/src/cmdhfmf.c | 40 ++++++---- client/src/mifare/mifarehost.c | 32 ++++---- 7 files changed, 122 insertions(+), 115 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 456d721db..263238ff9 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1732,8 +1732,14 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_MIFARE_CIDENT: { - bool is_mfc = packet->data.asBytes[0]; - MifareCIdent(is_mfc); + + + struct p { + uint8_t is_mfc; + uint8_t key[6]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + MifareCIdent(payload->is_mfc, payload->key); break; } // Gen 3 magic cards diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 6efac56e7..b7b6d3852 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2827,8 +2827,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint // RATS, Request for answer to select if (no_rats == false) { - uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0 - AddCrc14A(rats, 2); + uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x31, 0x73 }; // FSD=256, FSDI=8, CID=0 ReaderTransmit(rats, sizeof(rats), NULL); int len = ReaderReceive(resp, parity_array); if (len == 0) { @@ -3055,7 +3054,7 @@ void ReaderIso14443a(PacketCommandNG *c) { uint8_t *cmd = c->data.asBytes; uint32_t arg0; - uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00}; + uint8_t buf[PM3_CMD_DATA_SIZE_MIX] = {0x00}; if ((param & ISO14A_CONNECT)) { iso14_pcb_blocknum = 0; diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index afbe8610a..4174b69ed 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2414,7 +2414,13 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { iso14a_set_timeout(timeout); } -void MifareCIdent(bool is_mfc) { +static void mf_reset_card(void) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(40); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); +} + +void MifareCIdent(bool is_mfc, uint8_t *key) { // variables uint8_t rec[1] = {0x00}; uint8_t recpar[1] = {0x00}; @@ -2428,17 +2434,13 @@ void MifareCIdent(bool is_mfc) { bool isGen2 = false; bool isGen1AGdm = false; - uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE); - uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE); - uint8_t *uid = BigBuf_malloc(10); - - memset(par, 0x00, MAX_PARITY_SIZE); - memset(buf, 0x00, PM3_CMD_DATA_SIZE); - memset(uid, 0x00, 10); + uint8_t *par = BigBuf_calloc(MAX_PARITY_SIZE); + uint8_t *buf = BigBuf_calloc(PM3_CMD_DATA_SIZE); + uint8_t *uid = BigBuf_calloc(10); + uint8_t *data = BigBuf_calloc(16); uint32_t cuid = 0; size_t data_off = 0; - uint8_t data[16] = {0x00}; iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -2460,18 +2462,10 @@ void MifareCIdent(bool is_mfc) { } } - // reset card - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - // reset card - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + mf_reset_card(); int res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); - if (res == 2) { + if (res) { // Check for Magic Gen4 GTU with default password: // Get config should return 30 or 32 bytes AddCrc14A(gen4GetConf, sizeof(gen4GetConf) - 2); @@ -2483,42 +2477,19 @@ void MifareCIdent(bool is_mfc) { } // reset card - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + mf_reset_card(); - res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); - if (res == 2) { + res = iso14443a_select_card(uid, NULL, &cuid, true, 0, false); + if (res) { if (cuid == 0xAA55C396) { data[data_off++] = MAGIC_GEN_UNFUSED; } ReaderTransmit(rats, sizeof(rats), NULL); res = ReaderReceive(buf, par); + if (res) { - // test for super card - ReaderTransmit(superGen1, sizeof(superGen1), NULL); - res = ReaderReceive(buf, par); - if (res == 22) { - uint8_t isGen = MAGIC_SUPER_GEN1; - - // check for super card gen2 - // not available after RATS, reset card before executing - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - iso14443a_select_card(uid, NULL, &cuid, true, 0, true); - ReaderTransmit(rdbl00, sizeof(rdbl00), NULL); - res = ReaderReceive(buf, par); - if (res == 18) { - isGen = MAGIC_SUPER_GEN2; - } - - data[data_off++] = isGen; - } - - if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) { + if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10", 9) == 0) { // test for some MFC gen2 isGen2 = true; data[data_off++] = MAGIC_GEN_2; @@ -2547,13 +2518,34 @@ void MifareCIdent(bool is_mfc) { isGen2 = true; data[data_off++] = MAGIC_GEN_2; } + + // test for super card + ReaderTransmit(superGen1, sizeof(superGen1), NULL); + res = ReaderReceive(buf, par); + if (res == 22) { + uint8_t isGen = MAGIC_SUPER_GEN1; + + // check for super card gen2 + // not available after RATS, reset card before executing + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(40); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + iso14443a_select_card(uid, NULL, &cuid, true, 0, true); + ReaderTransmit(rdbl00, sizeof(rdbl00), NULL); + res = ReaderReceive(buf, par); + if (res == 18) { + isGen = MAGIC_SUPER_GEN2; + } + + data[data_off++] = isGen; + } } if (is_mfc == false) { // magic ntag test - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + mf_reset_card(); + res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); if (res == 2) { ReaderTransmit(rdblf0, sizeof(rdblf0), NULL); @@ -2563,19 +2555,22 @@ void MifareCIdent(bool is_mfc) { } } } else { + + // CUID (with default sector 0 B key) test + // regular cards will NAK the WRITEBLOCK(0) command, while DirectWrite will ACK it + // if we do get an ACK, we immediately abort to ensure nothing is ever actually written + // only perform test if we haven't already identified Gen2. No need test if we have a positive identification already if (!isGen2) { - // CUID (with default sector 0 B key) test - // regular cards will NAK the WRITEBLOCK(0) command, while DirectWrite will ACK it - // if we do get an ACK, we immediately abort to ensure nothing is ever actually written - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + mf_reset_card(); + res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); - if (res == 2) { + if (res) { struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; - if (mifare_classic_authex(pcs, cuid, 0, MF_KEY_B, 0xFFFFFFFFFFFF, AUTH_FIRST, NULL, NULL) == 0) { + + uint64_t tmpkey = bytes_to_num(key, 6); + if (mifare_classic_authex(pcs, cuid, 0, MF_KEY_B, tmpkey, AUTH_FIRST, NULL, NULL) == 0) { uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; if ((mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_WRITEBLOCK, 0, receivedAnswer, receivedAnswerPar, NULL) == 1) && (receivedAnswer[0] == 0x0A)) { @@ -2589,11 +2584,10 @@ void MifareCIdent(bool is_mfc) { } // magic MFC Gen3 test 1 - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + mf_reset_card(); + res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); - if (res == 2) { + if (res) { ReaderTransmit(rdbl00, sizeof(rdbl00), NULL); res = ReaderReceive(buf, par); if (res == 18) { @@ -2602,11 +2596,10 @@ void MifareCIdent(bool is_mfc) { } // magic MFC Gen4 GDM magic auth test - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + mf_reset_card(); + res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); - if (res == 2) { + if (res) { ReaderTransmit(gen4gdmAuth, sizeof(gen4gdmAuth), NULL); res = ReaderReceive(buf, par); if (res == 4) { @@ -2615,11 +2608,10 @@ void MifareCIdent(bool is_mfc) { } // QL88 test - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(40); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + mf_reset_card(); + res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); - if (res == 2) { + if (res) { struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; @@ -2698,7 +2690,7 @@ void MifareHasStaticNonce(void) { } if (counter) { - Dbprintf("%u static nonce %08x", data[0], nt); + Dbprintf("Static nonce......... " _YELLOW_("%08x"), nt); data[0] = NONCE_STATIC; } else { data[0] = NONCE_NORMAL; diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 64df74f97..5a360e221 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -47,7 +47,7 @@ int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype); // MFC GEN1a /1b void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card 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, uint8_t *key); // 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? diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index b4428e01f..061a4f509 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2410,29 +2410,29 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { int isMagic = 0; if (isMifareClassic) { - isMagic = detect_mf_magic(true); + isMagic = detect_mf_magic(true, 0); } if (isMifareUltralight) { - isMagic = (detect_mf_magic(false) == MAGIC_NTAG21X); + isMagic = (detect_mf_magic(false, 0) == MAGIC_NTAG21X); } if (isMifareClassic) { int res = detect_classic_static_nonce(); if (res == NONCE_STATIC) - PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes")); + PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes")); if (res == NONCE_FAIL && verbose) - PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("read failed")); + PrintAndLogEx(SUCCESS, "Static nonce......... " _RED_("read failed")); if (res == NONCE_NORMAL) { // not static res = detect_classic_prng(); if (res == 1) - PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak")); + PrintAndLogEx(SUCCESS, "Prng detection....... " _GREEN_("weak")); else if (res == 0) - PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard")); + PrintAndLogEx(SUCCESS, "Prng detection....... " _YELLOW_("hard")); else - PrintAndLogEx(FAILED, "Prng detection: " _RED_("fail")); + PrintAndLogEx(FAILED, "Prng detection........ " _RED_("fail")); if (do_nack_test) detect_classic_nackbug(false); diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 9e2aeed36..742db52b0 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -8899,12 +8899,6 @@ static int CmdHF14AMfInfo(const char *Cmd) { mfc_ev1_print_signature(card.uid, card.uidlen, signature, sizeof(signature)); } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Magic Tag Information")); - if (detect_mf_magic(true) == 0) { - PrintAndLogEx(INFO, ""); - } - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Keys Information")); @@ -8945,8 +8939,8 @@ static int CmdHF14AMfInfo(const char *Cmd) { if (res == PM3_SUCCESS || res == PM3_EPARTIAL) { uint8_t blockdata[MFBLOCK_SIZE] = {0}; - if (e_sector[0].foundKey[0]) { - PrintAndLogEx(SUCCESS, "Sector 0 key A... " _GREEN_("%12" PRIX64), e_sector[0].Key[0]); + if (e_sector[0].foundKey[MF_KEY_A]) { + PrintAndLogEx(SUCCESS, "Sector 0 key A... " _GREEN_("%12" PRIX64), e_sector[0].Key[MF_KEY_A]); num_to_bytes(e_sector[0].Key[MF_KEY_A], MIFARE_KEY_SIZE, fkey); if (mfReadBlock(0, MF_KEY_A, key, blockdata) == PM3_SUCCESS) { @@ -8954,8 +8948,8 @@ static int CmdHF14AMfInfo(const char *Cmd) { } } - if (e_sector[0].foundKey[1]) { - PrintAndLogEx(SUCCESS, "Sector 0 key B... " _GREEN_("%12" PRIX64), e_sector[0].Key[1]); + if (e_sector[0].foundKey[MF_KEY_B]) { + PrintAndLogEx(SUCCESS, "Sector 0 key B... " _GREEN_("%12" PRIX64), e_sector[0].Key[MF_KEY_B]); if (fKeyType == 0xFF) { num_to_bytes(e_sector[0].Key[MF_KEY_B], MIFARE_KEY_SIZE, fkey); @@ -8968,34 +8962,48 @@ static int CmdHF14AMfInfo(const char *Cmd) { if (fKeyType != 0xFF) { PrintAndLogEx(SUCCESS, "Block 0.......... %s", sprint_hex(blockdata, MFBLOCK_SIZE)); } + + if (memcmp(blockdata + 8, "\x62\x63\x64\x65\x66\x67\x68\x69", 8) == 0) { + PrintAndLogEx(SUCCESS, " indication of Fudan"); + } + } else { PrintAndLogEx(INFO, ""); } + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Magic Tag Information")); + if (detect_mf_magic(true, e_sector[0].Key[MF_KEY_B]) == 0) { + if (detect_mf_magic(true, e_sector[0].Key[MF_KEY_A]) == 0) { + PrintAndLogEx(INFO, ""); + } + } + + free(keyBlock); free(e_sector); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("RNG Information")); + PrintAndLogEx(INFO, "--- " _CYAN_("PRNG Information")); res = detect_classic_static_nonce(); if (res == NONCE_STATIC) { - PrintAndLogEx(SUCCESS, "Static nonce... " _YELLOW_("yes")); + PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes")); } if (res == NONCE_FAIL && verbose) { - PrintAndLogEx(SUCCESS, "Static nonce... " _RED_("read failed")); + PrintAndLogEx(SUCCESS, "Static nonce......... " _RED_("read failed")); } if (res == NONCE_NORMAL) { // not static res = detect_classic_prng(); if (res == 1) - PrintAndLogEx(SUCCESS, "Prng... " _GREEN_("weak")); + PrintAndLogEx(SUCCESS, "Prng................. " _GREEN_("weak")); else if (res == 0) - PrintAndLogEx(SUCCESS, "Prng... " _YELLOW_("hard")); + PrintAndLogEx(SUCCESS, "Prng................. " _YELLOW_("hard")); else - PrintAndLogEx(FAILED, "Prng... " _RED_("fail")); + PrintAndLogEx(FAILED, "Prng................. " _RED_("fail")); // detect static encrypted nonce diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index a4fa8f13d..f487f5900 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -1390,12 +1390,14 @@ int detect_classic_static_encrypted_nonce(uint8_t block_no, uint8_t key_type, ui } /* 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, uint64_t key) { uint8_t isMagic = 0; PacketResponseNG resp; clearCommandBuffer(); - uint8_t payload[] = { is_mfc }; + uint8_t payload[1 + MIFARE_KEY_SIZE] = { is_mfc }; + num_to_bytes(key, MIFARE_KEY_SIZE, payload + 1); + SendCommandNG(CMD_HF_MIFARE_CIDENT, payload, sizeof(payload)); if (WaitForResponseTimeout(CMD_HF_MIFARE_CIDENT, &resp, 1500)) { if (resp.status != PM3_SUCCESS) { @@ -1407,43 +1409,43 @@ int detect_mf_magic(bool is_mfc) { isMagic = 1; switch (resp.data.asBytes[i]) { case MAGIC_GEN_1A: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 1a")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Gen 1a")); break; case MAGIC_GEN_1B: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 1b")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Gen 1b")); break; case MAGIC_GEN_2: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 2 / CUID")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Gen 2 / CUID")); break; case MAGIC_GEN_3: - PrintAndLogEx(SUCCESS, "Magic capabilities : possibly " _GREEN_("Gen 3 / APDU")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Gen 3 / APDU") " ( possibly )"); break; case MAGIC_GEN_4GTU: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 4 GTU")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Gen 4 GTU")); break; case MAGIC_GDM_AUTH: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 4 GDM / USCUID (Magic Auth)")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Gen 4 GDM / USCUID") " ( Magic Auth )"); break; case MAGIC_GDM_WUP_20: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 4 GDM / USCUID (Alt Magic Wakeup)")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Gen 4 GDM / USCUID") " ( Alt Magic Wakeup )"); break; case MAGIC_GDM_WUP_40: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 4 GDM / USCUID (Gen1 Magic Wakeup)")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Gen 4 GDM / USCUID") " ( Gen1 Magic Wakeup )"); break; case MAGIC_GEN_UNFUSED: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Write Once / FUID")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Write Once / FUID")); break; case MAGIC_SUPER_GEN1: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Super card (") _CYAN_("Gen 1") _GREEN_(")")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Super card ( ") _CYAN_("Gen 1") _GREEN_(" )")); break; case MAGIC_SUPER_GEN2: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Super card (") _CYAN_("Gen 2") _GREEN_(")")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("Super card ( ") _CYAN_("Gen 2") _GREEN_(" )")); break; case MAGIC_NTAG21X: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("NTAG21x")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("NTAG21x")); break; case MAGIC_QL88: - PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("QL88")); + PrintAndLogEx(SUCCESS, "Magic capabilities... " _GREEN_("QL88")); default: break; }