From 074f6c374ee0122076476531df5a3bde4aa6ca7f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 9 Mar 2020 11:02:26 +0100 Subject: [PATCH] add: hf mf personlize - Personalize the UID of a Mifare Classic EV1 card (@pwpiwi) see https://github.com/Proxmark/proxmark3/commit/0b4efbdef20ccf33ba7b5f6dbe36ab80cfe5477a --- armsrc/appmain.c | 12 ++++++ armsrc/mifarecmd.c | 66 +++++++++++++++++++++++++++++--- armsrc/mifarecmd.h | 2 + client/cmdhfmf.c | 91 ++++++++++++++++++++++++++++++++++++++++++++- include/pm3_cmd.h | 2 + include/protocols.h | 4 ++ 6 files changed, 171 insertions(+), 6 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 1c76fad7d..5464d7ddb 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -42,6 +42,7 @@ #include "Standalone/standalone.h" #include "util.h" #include "ticks.h" +#include "commonutil.h" #ifdef WITH_LCD #include "LCD.h" @@ -1247,6 +1248,17 @@ static void PacketReceived(PacketCommandNG *packet) { // SniffMifare(packet->oldarg[0]); // break; // } + case CMD_HF_MIFARE_PERSONALIZE_UID: { + struct p { + uint8_t keytype; + uint8_t pers_option; + uint8_t key[6]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + uint64_t authkey = bytes_to_num(payload->key, 6); + MifarePersonalizeUID(payload->keytype, payload->pers_option, authkey); + break; + } case CMD_HF_MIFARE_SETMOD: { MifareSetMod(packet->data.asBytes); break; diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index b869489ab..3669e13ea 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1805,6 +1805,63 @@ void MifareChkKeys_file(uint8_t *fn) { #endif } +//----------------------------------------------------------------------------- +// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID +//----------------------------------------------------------------------------- +void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) { + + uint16_t isOK = PM3_EUNDEF; + uint8_t uid[10]; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + LED_A_ON(); + + while (true) { + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); + break; + } + + uint8_t block_number = 0; + if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error"); + break; + } + + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; + int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL); + if (len != 1 || receivedAnswer[0] != CARD_ACK) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + break;; + } + + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); + break; + } + isOK = PM3_SUCCESS; + break; + } + + crypto1_deinit(pcs); + + LED_B_ON(); + reply_ng(CMD_HF_MIFARE_PERSONALIZE_UID, isOK, NULL, 0); + LED_B_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + + //----------------------------------------------------------------------------- // Work with emulator memory // @@ -2276,23 +2333,23 @@ void MifareSetMod(uint8_t *datain) { while (true) { if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); break; } if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) { - if (DBGLEVEL >= 1) Dbprintf("Auth error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error"); break; } int respLen; if (((respLen = mifare_sendcmd_short(pcs, CRYPT_ALL, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) { - if (DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen); break; } if (mifare_classic_halt(pcs, cuid)) { - if (DBGLEVEL >= 1) Dbprintf("Halt error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); break; } @@ -2304,7 +2361,6 @@ void MifareSetMod(uint8_t *datain) { LED_B_ON(); reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0); - LED_B_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 1f5ee63a4..91adba3b1 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -45,6 +45,8 @@ void MifareCIdent(); // is "magic chinese" card? void MifareHasStaticNonce(); // Has the tag a static nonce? void MifareSetMod(uint8_t *datain); +void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key); + void MifareUSetPwd(uint8_t arg0, uint8_t *datain); void OnSuccessMagic(); void OnErrorMagic(uint8_t reason); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 24296b31d..6a57491fc 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -4798,6 +4798,95 @@ static int CmdHFMFNDEF(const char *Cmd) { return PM3_SUCCESS; } +int CmdHFMFPersonalize(const char *cmd) { + + CLIParserInit("hf mf personalize", + "Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.", + "Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n" + "\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n" + "\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n" + "\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n" + "\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n"); + + void *argtable[] = { + arg_param_begin, + arg_str0("tT", "keytype", "", "key type (A or B) to authenticate sector 0 (default: A)"), + arg_str0("kK", "key", "", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"), + arg_str1(NULL, NULL, "", "Personalization Option"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + char keytypestr[2] = "a"; + uint8_t keytype = 0x00; + int keytypestr_len; + int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t*)keytypestr, 1, &keytypestr_len); + str_lower(keytypestr); + + if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'b')) { + PrintAndLogEx(ERR, "ERROR: not a valid key type. Key type must be A or B"); + CLIParserFree(); + return PM3_EINVARG; + } + if (keytypestr[0] == 'b') { + keytype = 0x01; + } + + uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + int key_len; + res = CLIParamHexToBuf(arg_get_str(2), key, 6, &key_len); + if (res || (!res && key_len > 0 && key_len != 6)) { + PrintAndLogEx(ERR, "ERROR: not a valid key. Key must be 12 hex digits"); + CLIParserFree(); + return PM3_EINVARG; + } + + char pers_optionstr[6]; + int opt_len; + uint8_t pers_option; + res = CLIParamStrToBuf(arg_get_str(3), (uint8_t*)pers_optionstr, 5, &opt_len); + str_lower(pers_optionstr); + + if (res || (!res && opt_len > 0 && opt_len != 5) + || (strncmp(pers_optionstr, "uidf0", 5) && strncmp(pers_optionstr, "uidf1", 5) && strncmp(pers_optionstr, "uidf2", 5) && strncmp(pers_optionstr, "uidf3", 5))) { + PrintAndLogEx(ERR, "ERROR: invalid personalization option. Must be one of UIDF0, UIDF1, UIDF2, or UIDF3"); + CLIParserFree(); + return PM3_EINVARG; + } + if (!strncmp(pers_optionstr, "uidf0", 5)) { + pers_option = MIFARE_EV1_UIDF0; + } else if (!strncmp(pers_optionstr, "uidf1", 5)) { + pers_option = MIFARE_EV1_UIDF1; + } else if (!strncmp(pers_optionstr, "uidf2", 5)) { + pers_option = MIFARE_EV1_UIDF2; + } else { + pers_option = MIFARE_EV1_UIDF3; + } + + CLIParserFree(); + + clearCommandBuffer(); + + struct { + uint8_t keytype; + uint8_t pers_option; + uint8_t key[6]; + } PACKED payload; + payload.keytype = keytype; + payload.pers_option = pers_option; + + memcpy(payload.key, key, 6); + + SendCommandNG(CMD_HF_MIFARE_PERSONALIZE_UID, (uint8_t *)&payload, sizeof(payload)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_HF_MIFARE_PERSONALIZE_UID, &resp, 2500)) return PM3_ETIMEOUT; + + PrintAndLogEx(SUCCESS, "Personalization %s", resp.status == PM3_SUCCESS ? "SUCCEEDED" : "FAILED"); + + return PM3_SUCCESS; +} + static int CmdHF14AMfList(const char *Cmd) { (void)Cmd; // Cmd is not used so far return CmdTraceList("mf"); @@ -4845,7 +4934,7 @@ static command_t CommandTable[] = { {"-----------", CmdHelp, IfPm3Iso14443a, ""}, {"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"}, {"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, - + {"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (Mifare Classic EV1 only)"}, {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"}, {NULL, NULL, NULL, NULL} }; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index cff1f891f..8cffa892a 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -505,6 +505,8 @@ typedef struct { #define CMD_HF_MIFARE_SNIFF 0x0630 #define CMD_HF_MIFARE_MFKEY 0x0631 +#define CMD_HF_MIFARE_PERSONALIZE_UID 0x0632 + //ultralightC #define CMD_HF_MIFAREUC_AUTH 0x0724 //0x0725 and 0x0726 no longer used diff --git a/include/protocols.h b/include/protocols.h index e1d898d53..e992a97ee 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -163,6 +163,10 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MIFARE_EV1_PERSONAL_UID 0x40 #define MIFARE_EV1_SETMODE 0x43 +#define MIFARE_EV1_UIDF0 0x00 +#define MIFARE_EV1_UIDF1 0x40 +#define MIFARE_EV1_UIDF2 0x20 +#define MIFARE_EV1_UIDF3 0x60 #define MIFARE_ULC_WRITE 0xA2 #define MIFARE_ULC_COMP_WRITE 0xA0