diff --git a/CHANGELOG.md b/CHANGELOG.md index 492c67794..0392833f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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] + - Added `hf mf gen3*`magic gen 3 card operations (@McEloff) - Readded verichip command which seems missing (@iceman1001) - Fix missing t55x7 config block detection (@iceman1001) - Fix missing define on proxspace (@mwalker33) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 26a62bf9b..940d71b32 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1318,6 +1318,19 @@ static void PacketReceived(PacketCommandNG *packet) { MifareCIdent(); break; } + // Gen 3 magic cards + case CMD_HF_MIFARE_GEN3UID: { + MifareGen3UID(packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_HF_MIFARE_GEN3BLK: { + MifareGen3Blk(packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_HF_MIFARE_GEN3FREEZ: { + MifareGen3Freez(); + break; + } // mifare sniffer // case CMD_HF_MIFARE_SNIFF: { // SniffMifare(packet->oldarg[0]); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index ba1f6201a..decaf39fb 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2319,6 +2319,154 @@ void OnErrorMagic(uint8_t reason) { OnSuccessMagic(); } +int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len) { + int retval = PM3_SUCCESS; + uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE); + uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE); + + LED_B_ON(); + uint32_t save_iso14a_timeout = iso14a_get_timeout(); + iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 2000); // 2 seconds timeout + + ReaderTransmit(cmd, cmd_len, NULL); + int res = ReaderReceive(buf, par); + if (res == 4 || memcmp(buf, "\x90\x00\xfd\x07", 4) == 0) { + // timeout for card memory reset + SpinDelay(1000); + } else { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card operation not completed"); + retval = PM3_ESOFT; + } + iso14a_set_timeout(save_iso14a_timeout); + LED_B_OFF(); + + return retval; +} + +void MifareGen3UID(uint8_t uidlen, uint8_t *uid) { + int retval = PM3_SUCCESS; + uint8_t uid_cmd[5] = { 0x90, 0xfb, 0xcc, 0xcc, 0x07 }; + uint8_t *old_uid = BigBuf_malloc(10); + uint8_t *cmd = BigBuf_malloc(sizeof(uid_cmd) + uidlen + 2); + iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t)); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(old_uid, card_info, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected"); + retval = PM3_ESOFT; + goto OUT; + } + if (card_info->uidlen != uidlen) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID length"); + retval = PM3_ESOFT; + goto OUT; + } + + memcpy(cmd, uid_cmd, sizeof(uid_cmd)); + memcpy(&cmd[sizeof(uid_cmd)], uid, uidlen); + AddCrc14A(cmd, sizeof(uid_cmd) + uidlen); + + retval = DoGen3Cmd(cmd, sizeof(uid_cmd) + uidlen + 2); + +OUT: + reply_ng(CMD_HF_MIFARE_GEN3UID, retval, old_uid, uidlen); + // turns off + OnSuccessMagic(); + BigBuf_free(); +} + +void MifareGen3Blk(uint8_t block_len, uint8_t *block) { +#define MIFARE_BLOCK_SIZE (MAX_MIFARE_FRAME_SIZE - 2) + int retval = PM3_SUCCESS; + uint8_t block_cmd[5] = { 0x90, 0xf0, 0xcc, 0xcc, 0x10 }; + uint8_t *uid = BigBuf_malloc(10); + uint8_t *cmd = BigBuf_malloc(sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE); + iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t)); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(uid, card_info, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected"); + retval = PM3_ESOFT; + goto OUT; + } + + bool doReselect = false; + if (block_len < MIFARE_BLOCK_SIZE) { + if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, 0, &cmd[sizeof(block_cmd)], NULL, NULL) != MAX_MIFARE_FRAME_SIZE)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read manufacturer block failed"); + retval = PM3_ESOFT; + goto OUT; + } + doReselect = true; + } + + if (block_len > 0) { + memcpy(cmd, block_cmd, sizeof(block_cmd)); + memcpy(&cmd[sizeof(block_cmd)], block, block_len); + int ofs = sizeof(block_cmd); + if (card_info->uidlen == 4) { + cmd[ofs + 4] = cmd[ofs + 0] ^ cmd[ofs + 1] ^ cmd[ofs + 2] ^ cmd[ofs + 3]; + ofs += 5; + } else if (card_info->uidlen == 7) { + ofs += 7; + } else { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong Card UID length"); + retval = PM3_ESOFT; + goto OUT; + } + cmd[ofs++] = card_info->sak; + cmd[ofs++] = card_info->atqa[0]; + cmd[ofs++] = card_info->atqa[1]; + AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE); + + if (doReselect) { + if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected"); + retval = PM3_ESOFT; + goto OUT; + } + } + + retval = DoGen3Cmd(cmd, sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE); + } + +OUT: + reply_ng(CMD_HF_MIFARE_GEN3BLK, retval, &cmd[sizeof(block_cmd)], MIFARE_BLOCK_SIZE); + // turns off + OnSuccessMagic(); + BigBuf_free(); +} + +void MifareGen3Freez(void) { + int retval = PM3_SUCCESS; + uint8_t freeze_cmd[7] = { 0x90, 0xfd, 0x11, 0x11, 0x00, 0xe7, 0x91 }; + uint8_t *uid = BigBuf_malloc(10); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected"); + retval = PM3_ESOFT; + goto OUT; + } + + retval = DoGen3Cmd(freeze_cmd, sizeof(freeze_cmd)); + +OUT: + reply_ng(CMD_HF_MIFARE_GEN3FREEZ, retval, NULL, 0); + // turns off + OnSuccessMagic(); + BigBuf_free(); +} + void MifareSetMod(uint8_t *datain) { uint8_t mod = datain[0]; diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 3da2b2f00..4adceb4db 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -44,6 +44,11 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); void MifareCIdent(void); // is "magic chinese" card? void MifareHasStaticNonce(void); // Has the tag a static nonce? +int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len); +void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID without manufacturer block +void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overwrite manufacturer block +void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes + void MifareSetMod(uint8_t *datain); void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key); diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index cab2160cc..1af89f0f8 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -500,6 +500,48 @@ static int usage_hf14_nack(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf mf nack")); return PM3_SUCCESS; } +static int usage_hf14_gen3uid(void) { + PrintAndLogEx(NORMAL, "Set UID for magic GEN 3 card without manufacturer block changing"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: hf mf gen3uid [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " UID 8/14 hex symbols"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304050607")); + return PM3_SUCCESS; +} +static int usage_hf14_gen3blk(void) { + PrintAndLogEx(NORMAL, "Overwrite full manufacturer block for magic GEN 3 card"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: hf mf gen3blk [h] [block data (up to 32 hex symbols)]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " [block] manufacturer block data up to 32 hex symbols to write"); + PrintAndLogEx(NORMAL, " - If block data not specified, it prints current"); + PrintAndLogEx(NORMAL, " data without changes"); + PrintAndLogEx(NORMAL, " - You can specify part of manufacturer block as"); + PrintAndLogEx(NORMAL, " 4/7-bytes for UID change only for example"); + PrintAndLogEx(NORMAL, " NOTE: BCC, SAK, ATQA will be calculated automatically"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304FFFFFFFF0102030405060708")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304050607")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk")); + return PM3_SUCCESS; +} +static int usage_hf14_gen3freez(void) { + PrintAndLogEx(NORMAL, "Lock further UID changes. No more UID changes available after operation completed"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: hf mf gen3freez [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " confirm UID locks operation"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3freez Y")); + return PM3_SUCCESS; +} static int GetHFMF14AUID(uint8_t *uid, int *uidlen) { clearCommandBuffer(); @@ -5086,6 +5128,69 @@ static int CmdHF14AMfList(const char *Cmd) { return CmdTraceList("mf"); } +static int CmdHf14AGen3UID(const char *Cmd) { + uint8_t uid[7] = {0x00}; + uint8_t oldUid[10] = {0x00}; + uint8_t uidlen; + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (ctmp == 'h') return usage_hf14_gen3uid(); + + if (param_gethex(Cmd, 0, uid, 8)) + if (param_gethex(Cmd, 0, uid, 14)) + return usage_hf14_gen3uid(); + else + uidlen = 7; + else + uidlen = 4; + + int res = mfGen3UID(uid, uidlen, oldUid); + if (res) { + PrintAndLogEx(ERR, "Can't set UID. Error=%d", res); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, "Old UID : %s", sprint_hex(oldUid, uidlen)); + PrintAndLogEx(SUCCESS, "New UID : %s", sprint_hex(uid, uidlen)); + return PM3_SUCCESS; +} + +static int CmdHf14AGen3Blk(const char *Cmd) { + uint8_t block[16] = {0x00}; + int blocklen = 0; + uint8_t newBlock[16] = {0x00}; + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (ctmp == 'h') return usage_hf14_gen3blk(); + + if (ctmp != '\0' && param_gethex_to_eol(Cmd, 0, block, sizeof(block), &blocklen)) + return usage_hf14_gen3blk(); + + int res = mfGen3Blk(block, blocklen, newBlock); + if (res) { + PrintAndLogEx(ERR, "Can't change manufacturer block data. Error=%d", res); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, "Current Block : %s", sprint_hex(newBlock, 16)); + return PM3_SUCCESS; +} + +static int CmdHf14AGen3Freez(const char *Cmd) { + char ctmp = param_getchar(Cmd, 0); + if (tolower(ctmp) == 'h') return usage_hf14_gen3freez(); + if (ctmp != 'Y') return usage_hf14_gen3freez(); + + int res = mfGen3Freez(); + if (res) { + PrintAndLogEx(ERR, "Can't lock UID changes. Error=%d", res); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, "Gen 3 UID locked"); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"}, @@ -5131,6 +5236,10 @@ static command_t CommandTable[] = { {"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump (magic chinese card)"}, {"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from magic chinese card into file or emulator"}, {"cview", CmdHF14AMfCView, IfPm3Iso14443a, "view card"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3") " -----------------------"}, + {"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without manufacturer block (magic gen3 card)"}, + {"gen3blk", CmdHf14AGen3Blk, IfPm3Iso14443a, "Overwrite full manufacturer block (magic gen 3 card)"}, + {"gen3freez", CmdHf14AGen3Freez, IfPm3Iso14443a, "Lock further UID changes (magic gen 3 card)"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"}, {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"}, diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 31b88bec9..26b25b831 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -944,6 +944,48 @@ int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) { return PM3_SUCCESS; } +int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid) { + clearCommandBuffer(); + SendCommandMIX(CMD_HF_MIFARE_GEN3UID, uidlen, 0, 0, uid, uidlen); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3UID, &resp, 3500)) { + if (resp.status == PM3_SUCCESS && oldUid) { + memcpy(oldUid, resp.data.asBytes, uidlen); + } + return resp.status; + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; + } +} + +int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock) { + clearCommandBuffer(); + SendCommandMIX(CMD_HF_MIFARE_GEN3BLK, blockLen, 0, 0, block, 16); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3BLK, &resp, 3500)) { + if (resp.status == PM3_SUCCESS && newBlock) { + memcpy(newBlock, resp.data.asBytes, 16); + } + return resp.status; + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; + } +} + +int mfGen3Freez(void) { + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_GEN3FREEZ, NULL, 0); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3FREEZ, &resp, 3500)) { + return resp.status; + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; + } +} + // SNIFFER // [iceman] so many global variables.... diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index f8205732f..4864d9357 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -80,6 +80,10 @@ int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak); int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params); int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); +int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid); +int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock); +int mfGen3Freez(void); + int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); int detect_classic_prng(void); diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index b2eff0ddb..21409bbec 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -648,6 +648,11 @@ typedef struct { //For Atmel CryptoRF #define CMD_HF_CRYPTORF_SIM 0x0820 +// Gen 3 magic cards +#define CMD_HF_MIFARE_GEN3UID 0x0850 +#define CMD_HF_MIFARE_GEN3BLK 0x0851 +#define CMD_HF_MIFARE_GEN3FREEZ 0x0852 + #define CMD_UNKNOWN 0xFFFF //Mifare simulation flags