From 3ec3730183865fa89413032c168e358026884b11 Mon Sep 17 00:00:00 2001 From: "U-CHRIS-PC\\Chris" Date: Thu, 2 Feb 2023 15:53:52 -0700 Subject: [PATCH 01/15] Added XOR extraction and flag to Guardall G-Prox II --- client/src/cmdlfguard.c | 64 +++++++++++++++++++++++++---------------- client/src/cmdlfguard.h | 2 +- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/client/src/cmdlfguard.c b/client/src/cmdlfguard.c index 02bd52eb8..0225b2fef 100644 --- a/client/src/cmdlfguard.c +++ b/client/src/cmdlfguard.c @@ -86,9 +86,9 @@ static int demod_guard_raw(uint8_t *raw, uint8_t rlen) { } if (unknown) - PrintAndLogEx(SUCCESS, "G-Prox-II - Unknown len: " _GREEN_("%u") ", Raw: %s", fmtlen, sprint_hex_inrow(raw, rlen)); + PrintAndLogEx(SUCCESS, "G-Prox-II - xorKey: " _GREEN_("%u")" Unknown len: " _GREEN_("%u") ", Raw: %s", xorKey, fmtlen, sprint_hex_inrow(raw, rlen)); else - PrintAndLogEx(SUCCESS, "G-Prox-II - len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") ", Raw: %s", fmtlen, FC, Card, sprint_hex_inrow(raw, rlen)); + PrintAndLogEx(SUCCESS, "G-Prox-II - xorKey: " _GREEN_("%u")" Len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") ", Raw: %s", xorKey, fmtlen, FC, Card, sprint_hex_inrow(raw, rlen)); return PM3_SUCCESS; } @@ -142,9 +142,11 @@ int demodGuard(bool verbose) { // get key and then get all 8 bytes of payload decoded xorKey = (uint8_t)bytebits_to_byteLSBF(bits_no_spacer, 8); + PrintAndLogEx(DEBUG, "DEBUG: gProxII xorKey: %u", xorKey); + for (size_t idx = 0; idx < 8; idx++) { plain[idx] = ((uint8_t)bytebits_to_byteLSBF(bits_no_spacer + 8 + (idx * 8), 8)) ^ xorKey; - PrintAndLogEx(DEBUG, "DEBUG: gProxII byte %zu after xor: %02x", idx, plain[idx]); + PrintAndLogEx(DEBUG, "DEBUG: gProxII byte %zu after xor: %02x (%02x before xor)", idx, plain[idx], bytebits_to_byteLSBF(bits_no_spacer + 8 + (idx * 8), 8)); } setDemodBuff(g_DemodBuffer, 96, preambleIndex); @@ -161,6 +163,12 @@ int demodGuard(bool verbose) { bool unknown = false; switch (fmtLen) { case 36: + PrintAndLogEx(DEBUG, "DEBUG: FC 1: %x", (plain[3] & 0x7F) << 7); + PrintAndLogEx(DEBUG, "DEBUG: FC 2: %x", plain[4] >> 1); + PrintAndLogEx(DEBUG, "DEBUG: Card 1: %x", (plain[4] & 1) << 19); + PrintAndLogEx(DEBUG, "DEBUG: Card 2: %x", plain[5] << 11); + PrintAndLogEx(DEBUG, "DEBUG: Card 3: %x", plain[6] << 3); + PrintAndLogEx(DEBUG, "DEBUG: Card 4: %x", (plain[7] & 0xE0) >> 5); FC = ((plain[3] & 0x7F) << 7) | (plain[4] >> 1); Card = ((plain[4] & 1) << 19) | (plain[5] << 11) | (plain[6] << 3) | ((plain[7] & 0xE0) >> 5); break; @@ -173,9 +181,9 @@ int demodGuard(bool verbose) { break; } if (!unknown) - PrintAndLogEx(SUCCESS, "G-Prox-II - len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") ", Raw: %08x%08x%08x", fmtLen, FC, Card, raw1, raw2, raw3); + PrintAndLogEx(SUCCESS, "G-Prox-II - xorKey: " _GREEN_("%u") " Len: " _GREEN_("%u")" FC: " _GREEN_("%u") " Card: " _GREEN_("%u") ", Raw: %08x%08x%08x", xorKey, fmtLen, FC, Card, raw1, raw2, raw3); else - PrintAndLogEx(SUCCESS, "G-Prox-II - Unknown len: " _GREEN_("%u") ", Raw: %08x%08x%08x", fmtLen, raw1, raw2, raw3); + PrintAndLogEx(SUCCESS, "G-Prox-II - xorKey: " _GREEN_("%u") " Unknown len: " _GREEN_("%u") ", Raw: %08x%08x%08x", xorKey, fmtLen, raw1, raw2, raw3); return PM3_SUCCESS; } @@ -243,16 +251,17 @@ static int CmdGuardReader(const char *Cmd) { static int CmdGuardClone(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf gproxii clone", - "clone a Guardall tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n" + "Clone a Guardall tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n" "The facility-code is 8-bit and the card number is 20-bit. Larger values are truncated.\n" "Currently work only on 26 | 36 bit format", - "lf gproxii clone --fmt 26 --fc 123 --cn 1337 -> encode for T55x7 tag\n" - "lf gproxii clone --fmt 26 --fc 123 --cn 1337 --q5 -> encode for Q5/T5555 tag\n" - "lf gproxii clone --fmt 26 --fc 123 --cn 1337 --em -> encode for EM4305/4469" + "lf gproxii clone --xor 141 --fmt 26 --fc 123 --cn 1337 -> encode for T55x7 tag\n" + "lf gproxii clone --xor 141 --fmt 26 --fc 123 --cn 1337 --q5 -> encode for Q5/T5555 tag\n" + "lf gproxii clone --xor 141 --fmt 26 --fc 123 --cn 1337 --em -> encode for EM4305/4469" ); void *argtable[] = { arg_param_begin, + arg_u64_1(NULL, "xor", "", "8-bit xor value (installation dependant)"), arg_u64_1(NULL, "fmt", "", "format length 26|32|36|40"), arg_u64_1(NULL, "fc", "", "8-bit value facility code"), arg_u64_1(NULL, "cn", "", "16-bit value card number"), @@ -262,11 +271,13 @@ static int CmdGuardClone(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - uint32_t fmtlen = arg_get_u32_def(ctx, 1, 0); - uint32_t fc = arg_get_u32_def(ctx, 2, 0); - uint32_t cn = arg_get_u32_def(ctx, 3, 0); - bool q5 = arg_get_lit(ctx, 4); - bool em = arg_get_lit(ctx, 5); + uint32_t xorval = arg_get_u32_def(ctx, 1, 0); + uint32_t fmtlen = arg_get_u32_def(ctx, 2, 0); + uint32_t fc = arg_get_u32_def(ctx, 3, 0); + uint32_t cn = arg_get_u32_def(ctx, 4, 0); + + bool q5 = arg_get_lit(ctx, 5); + bool em = arg_get_lit(ctx, 6); CLIParserFree(ctx); if (q5 && em) { @@ -280,7 +291,7 @@ static int CmdGuardClone(const char *Cmd) { //GuardProxII - compat mode, ASK/Biphase, data rate 64, 3 data blocks uint8_t *bs = calloc(96, sizeof(uint8_t)); - if (getGuardBits(fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) { + if (getGuardBits(xorval, fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Error with tag bitstream generation."); free(bs); return PM3_ESOFT; @@ -306,10 +317,11 @@ static int CmdGuardClone(const char *Cmd) { free(bs); - PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u") + PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u") " xorKey: " _GREEN_("%u") , cardtype , facilitycode , cardnumber + , xorval ); print_blocks(blocks, ARRAYLEN(blocks)); @@ -332,11 +344,12 @@ static int CmdGuardSim(const char *Cmd) { "Simulation runs until the button is pressed or another USB command is issued.\n" "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n" "Currently work only on 26 | 36 bit format", - "lf gproxii sim --fmt 26 --fc 123 --cn 1337\n" + "lf gproxii sim --xor 141 --fmt 26 --fc 123 --cn 1337\n" ); void *argtable[] = { arg_param_begin, + arg_u64_1(NULL, "xor", "", "8-bit xor value (installation dependant)"), arg_u64_1(NULL, "fmt", "", "format length 26|32|36|40"), arg_u64_1(NULL, "fc", "", "8-bit value facility code"), arg_u64_1(NULL, "cn", "", "16-bit value card number"), @@ -344,9 +357,10 @@ static int CmdGuardSim(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - uint32_t fmtlen = arg_get_u32_def(ctx, 1, 0); - uint32_t fc = arg_get_u32_def(ctx, 2, 0); - uint32_t cn = arg_get_u32_def(ctx, 3, 0); + uint32_t xorval = arg_get_u32_def(ctx, 1, 0); + uint32_t fmtlen = arg_get_u32_def(ctx, 2, 0); + uint32_t fc = arg_get_u32_def(ctx, 3, 0); + uint32_t cn = arg_get_u32_def(ctx, 4, 0); CLIParserFree(ctx); fmtlen &= 0x7F; @@ -356,12 +370,13 @@ static int CmdGuardSim(const char *Cmd) { uint8_t bs[96]; memset(bs, 0x00, sizeof(bs)); - if (getGuardBits(fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) { + if (getGuardBits(xorval, fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Error with tag bitstream generation."); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u") + PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - xorKey: " _YELLOW_("%u%") " Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u") + , xorval , facilitycode , cardnumber ); @@ -435,9 +450,8 @@ int detectGProxII(uint8_t *bits, size_t *size) { } // Works for 26bits. -int getGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) { +int getGuardBits(uint8_t xorKey, uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) { - uint8_t xorKey = 0x66; uint8_t i; uint8_t pre[96]; uint8_t rawbytes[12]; @@ -448,7 +462,6 @@ int getGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) { switch (fmtlen) { case 32: { rawbytes[1] = (32 << 2); - break; } case 36: { @@ -456,6 +469,7 @@ int getGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) { // Get wiegand from FacilityCode 14bits, CardNumber 20bits uint8_t wiegand[36]; memset(wiegand, 0x00, sizeof(wiegand)); + num_to_bytebits(fc, 14, wiegand); num_to_bytebits(cn, 20, wiegand + 14); diff --git a/client/src/cmdlfguard.h b/client/src/cmdlfguard.h index c68c0d477..cfdf739a4 100644 --- a/client/src/cmdlfguard.h +++ b/client/src/cmdlfguard.h @@ -23,5 +23,5 @@ int CmdLFGuard(const char *Cmd); int detectGProxII(uint8_t *bits, size_t *size); int demodGuard(bool verbose); -int getGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits); +int getGuardBits(uint8_t xorKey, uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits); #endif From 3399cbd4f01d392ab1d5ae86ccd1779c1b9e27e0 Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Sat, 18 Feb 2023 23:48:32 -0600 Subject: [PATCH 02/15] support for NTAG213TT tamper feature --- client/src/cmdhfmfu.c | 298 +++++++++++++++++++++++++++++++- client/src/cmdhfmfu.h | 1 + client/src/pm3line_vocabulory.h | 1 + include/protocols.h | 3 + 4 files changed, 299 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index a59859394..f28c76369 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -392,6 +392,12 @@ static int ul_auth_select(iso14a_card_select_t *card, TagTypeUL_t tagtype, bool return PM3_SUCCESS; } +static int ntagtt_getTamperStatus(uint8_t *response, uint16_t responseLength) { + uint8_t cmd[] = {NTAGTT_CMD_READ_TT, 0x00}; + int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); + return len; +} + static int ulev1_getVersion(uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); @@ -748,8 +754,80 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st PrintAndLogEx(INFO, " cfg0 [%u/0x%02X]: %s", startPage, startPage, sprint_hex(data, 4)); - if ((tagtype & (NTAG_213_F | NTAG_213_TT | NTAG_216_F))) { - uint8_t mirror_conf = (data[0] & 0xC0); + //NTAG213TT has different ASCII mirroring options and config bytes interpretation from other ulev1 class tags + if (tagtype & NTAG_213_TT) { + uint8_t mirror_conf = ((data[0] & 0xE0) >> 5); + uint8_t mirror_byte = ((data[0] & 0x18) >> 3); + uint8_t tt_msg_lock = (data[1] & 0x04); + uint8_t mirror_page = data[2]; + + switch (mirror_conf) { + case 0: + PrintAndLogEx(INFO, " - no ASCII mirror"); + break; + case 1: + PrintAndLogEx(INFO, " - UID ASCII mirror"); + break; + case 2: + PrintAndLogEx(INFO, " - NFC counter ASCII mirror"); + break; + case 3: + PrintAndLogEx(INFO, " - UID and NFC counter ASCII mirror"); + break; + case 4: + PrintAndLogEx(INFO, " - tag tamper ASCII mirror"); + break; + case 5: + PrintAndLogEx(INFO, " - UID and tag tamper ASCII mirror"); + break; + case 6: + PrintAndLogEx(INFO, " - NFC counter and tag tamper ASCII mirror"); + break; + case 7: + PrintAndLogEx(INFO, " - UID, NFC counter, and tag tamper ASCII mirror"); + break; + default: + break; + } + + if(mirror_conf) { + uint8_t mirror_user_mem_start_byte = (4*(mirror_page-4)) + mirror_byte; + uint8_t bytes_required_for_mirror_data = 0; + + switch (mirror_conf) { + case 1: + bytes_required_for_mirror_data = 14; + break; + case 2: + bytes_required_for_mirror_data = 6; + break; + case 3: + bytes_required_for_mirror_data = 8; + break; + case 4: + bytes_required_for_mirror_data = 21; + break; + case 5: + bytes_required_for_mirror_data = 23; + break; + case 6: + bytes_required_for_mirror_data = 15; + break; + case 7: + bytes_required_for_mirror_data = 30; + break; + default: + break; + } + PrintAndLogEx(INFO, " mirror start page %02X | byte pos %02X - %s", mirror_page, mirror_byte, (mirror_page >= 0x4 && ((mirror_user_mem_start_byte + bytes_required_for_mirror_data) <= 144)) ? _GREEN_("OK") : _YELLOW_("Invalid value")); + } + + if(tt_msg_lock) { + PrintAndLogEx(INFO, " - tag tamper message is permanently locked"); + } + + } else if (tagtype & (NTAG_213_F | NTAG_216_F)) { + uint8_t mirror_conf = ((data[0] & 0xC0) >> 6); uint8_t mirror_byte = (data[0] & 0x30); bool sleep_en = (data[0] & 0x08); strg_mod_en = (data[0] & 0x04); @@ -791,7 +869,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st break; } // valid mirror start page and byte position within start page. - if ((tagtype & NTAG_213_F) || (tagtype & NTAG_213_TT)) { + if (tagtype & NTAG_213_F) { switch (mirror_conf) { case 1: { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x24) ? "OK" : "Invalid value"); break;} @@ -822,6 +900,35 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st else PrintAndLogEx(INFO, " - pages don't need authentication"); + uint8_t tt_enabled = 0; + uint8_t tt_message[4] = {0x00}; + uint8_t tt_msg_resp_len; + uint8_t tt_status_resp[5] = {0x00}; + + if(tagtype & NTAG_213_TT) { + tt_enabled = (data[1] & 0x02); + tt_msg_resp_len = ul_read(45, tt_message, 4); + + PrintAndLogEx(INFO, " - tamper detection is %s" + , (tt_enabled) ? _GREEN_("ENABLED") : "disabled" + ); + + switch (data[1] & 0x06) { + case 0x00: + PrintAndLogEx(INFO, " - tamper message is unlocked and read/write enabled"); + break; + case 0x02: + PrintAndLogEx(INFO, " - tamper message is reversibly read/write protected in memory while the tamper feature is enabled"); + break; + case 0x04: + case 0x06: + PrintAndLogEx(INFO, " - tamper message is permanently read/write protected in memory"); + break; + default: + break; + } + } + PrintAndLogEx(INFO, " cfg1 [%u/0x%02X]: %s", startPage + 1, startPage + 1, sprint_hex(data + 4, 4)); if (authlim == 0) PrintAndLogEx(INFO, " - " _GREEN_("Unlimited password attempts")); @@ -837,6 +944,54 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st PrintAndLogEx(INFO, " PWD [%u/0x%02X]: %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data + 8, 4)); PrintAndLogEx(INFO, " PACK [%u/0x%02X]: %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 12, 2)); PrintAndLogEx(INFO, " RFU [%u/0x%02X]: %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 14, 2)); + + if(tagtype & NTAG_213_TT) { + if(data[1] & 0x06) { + PrintAndLogEx(INFO, "TT_MSG [45/0x2D]: %s- (cannot be read)", sprint_hex(tt_message, tt_msg_resp_len)); + PrintAndLogEx(INFO, " - tamper message is masked in memory"); + } else { + PrintAndLogEx(INFO, "TT_MSG [45/0x2D]: %s", sprint_hex(tt_message, tt_msg_resp_len)); + PrintAndLogEx(INFO, " - tamper message is %s", sprint_hex(tt_message, tt_msg_resp_len)); + } + } + + if ((tagtype & NTAG_213_TT) && tt_enabled) { //The tag only returns meaningful information for the fields below if the tamper feature is enabled + + uint8_t tt_status_len = ntagtt_getTamperStatus(tt_status_resp, 5); + + if(tt_status_len != 5) { + PrintAndLogEx(WARNING, "Error requesting tamper status from tag\n"); + return PM3_ESOFT; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tamper Status")); + PrintAndLogEx(INFO, " READ_TT_STATUS: %s", sprint_hex(tt_status_resp, 5)); + + PrintAndLogEx(INFO, " Tamper detection result from this power-up:"); + switch(tt_status_resp[4]) { + case 0x43: + PrintAndLogEx(INFO, " - Tamper wire was detcted as closed during this power-up"); + break; + case 0x4F: + PrintAndLogEx(INFO, " - Tamper wire was detected as open during this power-up"); + break; + case 0x49: + PrintAndLogEx(INFO, " - No tamper wire measurement from this power-up is available"); + break; + default: + break; + } + + PrintAndLogEx(INFO, " Tamper detection permanent memory:"); + if((tt_status_resp[0] | tt_status_resp [1] | tt_status_resp[2] | tt_status_resp[3]) == 0x00) + + PrintAndLogEx(INFO, " - Tamper wire has never been detected as open during power-up"); + else { + PrintAndLogEx(INFO, " - Tamper wire has previously been detected as open during power-up"); + PrintAndLogEx(INFO, " - Tamper message: %s", sprint_hex(tt_status_resp, 4)); + } + } return PM3_SUCCESS; } @@ -1757,7 +1912,6 @@ static int CmdHF14AMfUInfo(const char *Cmd) { uint8_t startconfigblock = 0; uint8_t ulev1_conf[16] = {0x00}; - // config blocks always are last 4 pages for (uint8_t i = 0; i < ARRAYLEN(UL_TYPES_ARRAY); i++) { if (tagtype & UL_TYPES_ARRAY[i]) { startconfigblock = UL_MEMORY_ARRAY[i] - 3; @@ -2529,6 +2683,141 @@ static void wait4response(uint8_t b) { } } +// +//Configure tamper feature of NTAG 213TT +// +int CmdHF14MfUTamper(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu tamper", + "Set the congiguration of the NTAG 213TT tamper feature\n" + "Supports:\n" + "NTAG 213TT\n", + "hf mfu tamper -e -> enable tamper feature\n" + "hf mfu tamper -d -> disable tamper feature\n" + "hf mfu tamper -m 0A0A0A0A -> set the tamper message to 0A0A0A0A\n" + "hf mfu tamper --lockmessage -> permanently lock the tamper message and mask it from memory\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("e", "enable", "Enable the tamper feature"), + arg_lit0("d", "disable", "Disable the tamper feature"), + arg_str0("m", "message", "", "Set the tamper message (4 bytes)"), + arg_lit0(NULL, "lockmessage", "Permanently lock the tamper message and mask it from memory (does not lock tamper feature itself)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int tt_cfg_page = 41; + int tt_msg_page = 45; + int msg_len = 0; + uint8_t msg_data[4] = {0x00}; + CLIGetHexWithReturn(ctx, 3, msg_data, &msg_len); + bool use_msg = (msg_len > 0); + + if(use_msg && msg_len != 4) { + PrintAndLogEx(WARNING, "The tamper message must be 4 hex bytes if provided"); + DropField(); + return PM3_ESOFT; + } + + bool lock_msg = arg_get_lit(ctx, 4); + bool enable = arg_get_lit(ctx, 1); + bool disable = arg_get_lit(ctx, 2); + + TagTypeUL_t tagtype = GetHF14AMfU_Type(); + if (tagtype == UL_ERROR) { + PrintAndLogEx(WARNING, "Tag type not detected"); + DropField(); + return PM3_ESOFT; + } + if(tagtype != NTAG_213_TT) { + PrintAndLogEx(WARNING, "Tag type not NTAG 213TT"); + DropField(); + return PM3_ESOFT; + } + + DropField(); + iso14a_card_select_t card; + + if(enable && disable) { + PrintAndLogEx(WARNING, "You can only select one of the options enable/disable tamper feature"); + DropField(); + return PM3_ESOFT; + } + + if(use_msg) + { + if (ul_select(&card) == false) { + DropField(); + return UL_ERROR; + } + PrintAndLogEx(INFO, "Trying to write tamper message\n"); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, tt_msg_page, 0, 0, msg_data, 4); + + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + uint8_t isOK = resp.oldarg[0] & 0xff; + if (!isOK) + PrintAndLogEx(WARNING, "Failed to write tamper message"); + else + PrintAndLogEx(SUCCESS, "Tamper message written successfully"); + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + } + } + + if(enable | disable | lock_msg) { + + if (ul_select(&card) == false) { + PrintAndLogEx(ERR, "Unable to select tag"); + DropField(); + return UL_ERROR; + } + + uint8_t cfg_page[4] = {0x00}; + uint8_t cmd[] = {ISO14443A_CMD_READBLOCK, tt_cfg_page}; + int status = ul_send_cmd_raw(cmd, sizeof(cmd), cfg_page, 4); + DropField(); + + if(status <= 0) { + PrintAndLogEx(WARNING, "Problem reading current config from tag"); + DropField(); + return PM3_ESOFT; + } + + if(enable) { + cfg_page[1] = cfg_page[1] | 0x02; + PrintAndLogEx(INFO, "Enabling tamper feature"); + } + if(disable) { + cfg_page[1] = cfg_page[1] & 0xFD; + PrintAndLogEx(INFO, "Disabling tamper feature"); + } + if(lock_msg) { + cfg_page[1] = cfg_page[1] | 0x04; + PrintAndLogEx(INFO, "Locking tamper message"); + } + + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, tt_cfg_page, 0, 0, cfg_page, 4); + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + uint8_t isOK = resp.oldarg[0] & 0xff; + if (!isOK) + PrintAndLogEx(WARNING, "Failed to write tamper configuration"); + else + PrintAndLogEx(SUCCESS, "Tamper configuration written successfully"); + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + } + } + + DropField(); + return PM3_SUCCESS; +} + // // Restore dump file onto tag // @@ -4406,6 +4695,7 @@ static command_t CommandTable[] = { {"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"}, {"view", CmdHF14AMfuView, AlwaysAvailable, "Display content from tag dump file"}, {"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"}, + {"tamper", CmdHF14MfUTamper, IfPm3Iso14443a, "Cofigure the tamper feature on an NTAG 213TT"}, {"---------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, {"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "Load Ultralight dump file into emulator memory"}, {"esave", CmdHF14AMfuESave, IfPm3Iso14443a, "Save Ultralight dump file from emulator memory"}, diff --git a/client/src/cmdhfmfu.h b/client/src/cmdhfmfu.h index 568e3c4a9..1ed652e79 100644 --- a/client/src/cmdhfmfu.h +++ b/client/src/cmdhfmfu.h @@ -50,6 +50,7 @@ int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t ( int CmdHFMFUltra(const char *Cmd); int CmdHF14MfuNDEFRead(const char *Cmd); +int CmdHF14MfUTamper(const char *Cmd); uint16_t ul_ev1_packgen_VCNEW(uint8_t *uid, uint32_t pwd); uint32_t ul_ev1_otpgenA(uint8_t *uid); diff --git a/client/src/pm3line_vocabulory.h b/client/src/pm3line_vocabulory.h index a0e386270..8e775bd3e 100644 --- a/client/src/pm3line_vocabulory.h +++ b/client/src/pm3line_vocabulory.h @@ -384,6 +384,7 @@ const static vocabulory_t vocabulory[] = { { 0, "hf mfu rdbl" }, { 0, "hf mfu restore" }, { 1, "hf mfu view" }, + { 0, "hf mfu tamper" }, { 0, "hf mfu wrbl" }, { 0, "hf mfu eload" }, { 0, "hf mfu esave" }, diff --git a/include/protocols.h b/include/protocols.h index 1417fa71a..e4437d90a 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -223,6 +223,9 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define NTAG_I2C_SELECT_SECTOR 0xC2 #define NTAG_I2C_FASTWRITE 0xA6 +//NTAG 213TT (tamper) command +#define NTAGTT_CMD_READ_TT 0xA4 + // mifare 4bit card answers #define CARD_ACK 0x0A // 1010 - ACK #define CARD_NACK_IV 0x00 // 0000 - NACK, invalid argument (invalid page address) From 147475ab4056c249b800a782c3bc9f0ed47cb8f8 Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Mon, 20 Feb 2023 00:34:06 -0600 Subject: [PATCH 03/15] CHANGELOG.md and text changes --- CHANGELOG.md | 1 + client/src/cmdhfmfu.c | 136 +++++++++++++++++++++--------------------- include/protocols.h | 2 +- 3 files changed, 70 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e865190c1..7c5527897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `--back` option to `clear` command to clear the scrollback buffer (@wh201906) - Mark credentials as decrypted in the dump generated by `hf iclass decrypt` - Show credentials when using `hf iclass view` on a decrypted dump + - Show NTAG213TT tamper info in `hf mfu info` and add commands for configuring it's tamper feature (@mjaksn) ## [Nitride.4.16191][2023-01-29] - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index f28c76369..31823adeb 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -758,7 +758,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st if (tagtype & NTAG_213_TT) { uint8_t mirror_conf = ((data[0] & 0xE0) >> 5); uint8_t mirror_byte = ((data[0] & 0x18) >> 3); - uint8_t tt_msg_lock = (data[1] & 0x04); + uint8_t tt_msg_lock = (data[1] & 0x04); uint8_t mirror_page = data[2]; switch (mirror_conf) { @@ -790,41 +790,41 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st break; } - if(mirror_conf) { - uint8_t mirror_user_mem_start_byte = (4*(mirror_page-4)) + mirror_byte; + if (mirror_conf) { + uint8_t mirror_user_mem_start_byte = (4 * (mirror_page - 4)) + mirror_byte; uint8_t bytes_required_for_mirror_data = 0; switch (mirror_conf) { - case 1: - bytes_required_for_mirror_data = 14; - break; - case 2: - bytes_required_for_mirror_data = 6; - break; - case 3: - bytes_required_for_mirror_data = 8; - break; - case 4: - bytes_required_for_mirror_data = 21; - break; - case 5: - bytes_required_for_mirror_data = 23; - break; - case 6: - bytes_required_for_mirror_data = 15; - break; - case 7: - bytes_required_for_mirror_data = 30; - break; - default: - break; + case 1: + bytes_required_for_mirror_data = 14; + break; + case 2: + bytes_required_for_mirror_data = 6; + break; + case 3: + bytes_required_for_mirror_data = 8; + break; + case 4: + bytes_required_for_mirror_data = 21; + break; + case 5: + bytes_required_for_mirror_data = 23; + break; + case 6: + bytes_required_for_mirror_data = 15; + break; + case 7: + bytes_required_for_mirror_data = 30; + break; + default: + break; } PrintAndLogEx(INFO, " mirror start page %02X | byte pos %02X - %s", mirror_page, mirror_byte, (mirror_page >= 0x4 && ((mirror_user_mem_start_byte + bytes_required_for_mirror_data) <= 144)) ? _GREEN_("OK") : _YELLOW_("Invalid value")); } - if(tt_msg_lock) { - PrintAndLogEx(INFO, " - tag tamper message is permanently locked"); - } + if (tt_msg_lock) { + PrintAndLogEx(INFO, " - tamper message is permanently locked and cannot be written or read from memory"); + } } else if (tagtype & (NTAG_213_F | NTAG_216_F)) { uint8_t mirror_conf = ((data[0] & 0xC0) >> 6); @@ -905,24 +905,24 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st uint8_t tt_msg_resp_len; uint8_t tt_status_resp[5] = {0x00}; - if(tagtype & NTAG_213_TT) { - tt_enabled = (data[1] & 0x02); + if (tagtype & NTAG_213_TT) { + tt_enabled = (data[1] & 0x02); tt_msg_resp_len = ul_read(45, tt_message, 4); - PrintAndLogEx(INFO, " - tamper detection is %s" - , (tt_enabled) ? _GREEN_("ENABLED") : "disabled" - ); + PrintAndLogEx(INFO, " - tamper detection feature is %s" + , (tt_enabled) ? _GREEN_("ENABLED") : "disabled" + ); switch (data[1] & 0x06) { case 0x00: - PrintAndLogEx(INFO, " - tamper message is unlocked and read/write enabled"); + PrintAndLogEx(INFO, " - tamper message is unlocked and read/write enabled"); break; case 0x02: - PrintAndLogEx(INFO, " - tamper message is reversibly read/write protected in memory while the tamper feature is enabled"); + PrintAndLogEx(INFO, " - tamper message is reversibly read/write locked in memory while the tamper feature is enabled"); break; case 0x04: case 0x06: - PrintAndLogEx(INFO, " - tamper message is permanently read/write protected in memory"); + PrintAndLogEx(INFO, " - tamper message is permanently read/write locked in memory"); break; default: break; @@ -944,52 +944,53 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st PrintAndLogEx(INFO, " PWD [%u/0x%02X]: %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data + 8, 4)); PrintAndLogEx(INFO, " PACK [%u/0x%02X]: %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 12, 2)); PrintAndLogEx(INFO, " RFU [%u/0x%02X]: %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 14, 2)); - - if(tagtype & NTAG_213_TT) { - if(data[1] & 0x06) { + + if (tagtype & NTAG_213_TT) { + if (data[1] & 0x06) { PrintAndLogEx(INFO, "TT_MSG [45/0x2D]: %s- (cannot be read)", sprint_hex(tt_message, tt_msg_resp_len)); - PrintAndLogEx(INFO, " - tamper message is masked in memory"); + PrintAndLogEx(INFO, " - tamper message is masked in memory, but can be revealed in the READ_TT_STATUS command response if tampering was detected"); } else { PrintAndLogEx(INFO, "TT_MSG [45/0x2D]: %s", sprint_hex(tt_message, tt_msg_resp_len)); - PrintAndLogEx(INFO, " - tamper message is %s", sprint_hex(tt_message, tt_msg_resp_len)); + PrintAndLogEx(INFO, " - tamper message (read from memory) is %s", sprint_hex(tt_message, tt_msg_resp_len)); } } - if ((tagtype & NTAG_213_TT) && tt_enabled) { //The tag only returns meaningful information for the fields below if the tamper feature is enabled - + //The NTAG213TT only returns meaningful information for the fields below if the tamper feature is enabled + if ((tagtype & NTAG_213_TT) && tt_enabled) { + uint8_t tt_status_len = ntagtt_getTamperStatus(tt_status_resp, 5); - if(tt_status_len != 5) { - PrintAndLogEx(WARNING, "Error requesting tamper status from tag\n"); + if (tt_status_len != 5) { + PrintAndLogEx(WARNING, "Error sending the read TT status command to tag\n"); return PM3_ESOFT; } - + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tamper Status")); PrintAndLogEx(INFO, " READ_TT_STATUS: %s", sprint_hex(tt_status_resp, 5)); - PrintAndLogEx(INFO, " Tamper detection result from this power-up:"); - switch(tt_status_resp[4]) { + PrintAndLogEx(INFO, " Tamper status result from this power-up:"); + switch (tt_status_resp[4]) { case 0x43: - PrintAndLogEx(INFO, " - Tamper wire was detcted as closed during this power-up"); + PrintAndLogEx(INFO, " - Tamper loop was detcted as closed during this power-up"); break; case 0x4F: - PrintAndLogEx(INFO, " - Tamper wire was detected as open during this power-up"); + PrintAndLogEx(INFO, " - Tamper loop was detected as open during this power-up"); break; case 0x49: - PrintAndLogEx(INFO, " - No tamper wire measurement from this power-up is available"); + PrintAndLogEx(INFO, " - Tamper loop measurement from this power-up was not enabled or not valid"); break; default: break; } PrintAndLogEx(INFO, " Tamper detection permanent memory:"); - if((tt_status_resp[0] | tt_status_resp [1] | tt_status_resp[2] | tt_status_resp[3]) == 0x00) + if ((tt_status_resp[0] | tt_status_resp [1] | tt_status_resp[2] | tt_status_resp[3]) == 0x00) - PrintAndLogEx(INFO, " - Tamper wire has never been detected as open during power-up"); + PrintAndLogEx(INFO, " - Tamper loop has never been detected as open during power-up"); else { - PrintAndLogEx(INFO, " - Tamper wire has previously been detected as open during power-up"); - PrintAndLogEx(INFO, " - Tamper message: %s", sprint_hex(tt_status_resp, 4)); + PrintAndLogEx(INFO, " - Tamper loop was detected as open during power-up at least once"); + PrintAndLogEx(INFO, " - Tamper message returned by READ_TT_STATUS command: %s", sprint_hex(tt_status_resp, 4)); } } return PM3_SUCCESS; @@ -2715,7 +2716,7 @@ int CmdHF14MfUTamper(const char *Cmd) { CLIGetHexWithReturn(ctx, 3, msg_data, &msg_len); bool use_msg = (msg_len > 0); - if(use_msg && msg_len != 4) { + if (use_msg && msg_len != 4) { PrintAndLogEx(WARNING, "The tamper message must be 4 hex bytes if provided"); DropField(); return PM3_ESOFT; @@ -2731,7 +2732,7 @@ int CmdHF14MfUTamper(const char *Cmd) { DropField(); return PM3_ESOFT; } - if(tagtype != NTAG_213_TT) { + if (tagtype != NTAG_213_TT) { PrintAndLogEx(WARNING, "Tag type not NTAG 213TT"); DropField(); return PM3_ESOFT; @@ -2740,18 +2741,17 @@ int CmdHF14MfUTamper(const char *Cmd) { DropField(); iso14a_card_select_t card; - if(enable && disable) { + if (enable && disable) { PrintAndLogEx(WARNING, "You can only select one of the options enable/disable tamper feature"); DropField(); return PM3_ESOFT; } - if(use_msg) - { + if (use_msg) { if (ul_select(&card) == false) { DropField(); return UL_ERROR; - } + } PrintAndLogEx(INFO, "Trying to write tamper message\n"); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, tt_msg_page, 0, 0, msg_data, 4); @@ -2768,34 +2768,34 @@ int CmdHF14MfUTamper(const char *Cmd) { } } - if(enable | disable | lock_msg) { + if (enable | disable | lock_msg) { if (ul_select(&card) == false) { PrintAndLogEx(ERR, "Unable to select tag"); DropField(); return UL_ERROR; - } + } uint8_t cfg_page[4] = {0x00}; uint8_t cmd[] = {ISO14443A_CMD_READBLOCK, tt_cfg_page}; int status = ul_send_cmd_raw(cmd, sizeof(cmd), cfg_page, 4); DropField(); - if(status <= 0) { + if (status <= 0) { PrintAndLogEx(WARNING, "Problem reading current config from tag"); DropField(); return PM3_ESOFT; } - if(enable) { + if (enable) { cfg_page[1] = cfg_page[1] | 0x02; PrintAndLogEx(INFO, "Enabling tamper feature"); } - if(disable) { + if (disable) { cfg_page[1] = cfg_page[1] & 0xFD; PrintAndLogEx(INFO, "Disabling tamper feature"); } - if(lock_msg) { + if (lock_msg) { cfg_page[1] = cfg_page[1] | 0x04; PrintAndLogEx(INFO, "Locking tamper message"); } diff --git a/include/protocols.h b/include/protocols.h index e4437d90a..0cc89abb7 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -223,7 +223,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define NTAG_I2C_SELECT_SECTOR 0xC2 #define NTAG_I2C_FASTWRITE 0xA6 -//NTAG 213TT (tamper) command +//NTAG 213TT (tamper) command #define NTAGTT_CMD_READ_TT 0xA4 // mifare 4bit card answers From dc1f302fa2adcd8765f9c2f36a151f3829b79376 Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Mon, 20 Feb 2023 02:20:08 -0600 Subject: [PATCH 04/15] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2f5c1dc4..7321da285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `--back` option to `clear` command to clear the scrollback buffer (@wh201906) - Changed `hf iclass decrypt` - mark credentials as decrypted in the dump (@natesales) - Changed `hf iclass view` - show credentials on a decrypted dump (@natesales) + - Show NTAG213TT tamper info in `hf mfu info` and add commands for configuring it's tamper feature (@mjaksn) ## [Nitride.4.16191][2023-01-29] - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) From 690eb0fc8a4c66f1fd27f66c09900e1c0ca087ed Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Wed, 22 Feb 2023 07:40:04 -0600 Subject: [PATCH 05/15] add missing CLIParserFree(ctx) , init variable to zero, and small text change --- client/src/cmdhfmfu.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 31823adeb..9c8514241 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -758,7 +758,6 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st if (tagtype & NTAG_213_TT) { uint8_t mirror_conf = ((data[0] & 0xE0) >> 5); uint8_t mirror_byte = ((data[0] & 0x18) >> 3); - uint8_t tt_msg_lock = (data[1] & 0x04); uint8_t mirror_page = data[2]; switch (mirror_conf) { @@ -822,10 +821,6 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st PrintAndLogEx(INFO, " mirror start page %02X | byte pos %02X - %s", mirror_page, mirror_byte, (mirror_page >= 0x4 && ((mirror_user_mem_start_byte + bytes_required_for_mirror_data) <= 144)) ? _GREEN_("OK") : _YELLOW_("Invalid value")); } - if (tt_msg_lock) { - PrintAndLogEx(INFO, " - tamper message is permanently locked and cannot be written or read from memory"); - } - } else if (tagtype & (NTAG_213_F | NTAG_216_F)) { uint8_t mirror_conf = ((data[0] & 0xC0) >> 6); uint8_t mirror_byte = (data[0] & 0x30); @@ -902,7 +897,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st uint8_t tt_enabled = 0; uint8_t tt_message[4] = {0x00}; - uint8_t tt_msg_resp_len; + uint8_t tt_msg_resp_len = 0; uint8_t tt_status_resp[5] = {0x00}; if (tagtype & NTAG_213_TT) { @@ -948,10 +943,10 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st if (tagtype & NTAG_213_TT) { if (data[1] & 0x06) { PrintAndLogEx(INFO, "TT_MSG [45/0x2D]: %s- (cannot be read)", sprint_hex(tt_message, tt_msg_resp_len)); - PrintAndLogEx(INFO, " - tamper message is masked in memory, but can be revealed in the READ_TT_STATUS command response if tampering was detected"); + PrintAndLogEx(INFO, " - tamper message is masked in memory"); } else { PrintAndLogEx(INFO, "TT_MSG [45/0x2D]: %s", sprint_hex(tt_message, tt_msg_resp_len)); - PrintAndLogEx(INFO, " - tamper message (read from memory) is %s", sprint_hex(tt_message, tt_msg_resp_len)); + PrintAndLogEx(INFO, " - tamper message is %s and is readable/writablbe in memory", sprint_hex(tt_message, tt_msg_resp_len)); } } @@ -961,7 +956,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st uint8_t tt_status_len = ntagtt_getTamperStatus(tt_status_resp, 5); if (tt_status_len != 5) { - PrintAndLogEx(WARNING, "Error sending the read TT status command to tag\n"); + PrintAndLogEx(WARNING, "Error sending the READ_TT_STATUS command to tag\n"); return PM3_ESOFT; } @@ -978,7 +973,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st PrintAndLogEx(INFO, " - Tamper loop was detected as open during this power-up"); break; case 0x49: - PrintAndLogEx(INFO, " - Tamper loop measurement from this power-up was not enabled or not valid"); + PrintAndLogEx(INFO, " - Tamper loop measurement was not enabled or not valid during this power-up"); break; default: break; @@ -2725,6 +2720,7 @@ int CmdHF14MfUTamper(const char *Cmd) { bool lock_msg = arg_get_lit(ctx, 4); bool enable = arg_get_lit(ctx, 1); bool disable = arg_get_lit(ctx, 2); + CLIParserFree(ctx); TagTypeUL_t tagtype = GetHF14AMfU_Type(); if (tagtype == UL_ERROR) { From 75fd0c2034492ad73baedc474a787da430191831 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <123390480+mjaksn@users.noreply.github.com> Date: Thu, 23 Feb 2023 01:52:07 -0600 Subject: [PATCH 06/15] fixed another missing CLIParserFree(ctx); Signed-off-by: Matthew Jackson <123390480+mjaksn@users.noreply.github.com> --- client/src/cmdhfmfu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 9c8514241..d5ac6537b 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -2714,6 +2714,7 @@ int CmdHF14MfUTamper(const char *Cmd) { if (use_msg && msg_len != 4) { PrintAndLogEx(WARNING, "The tamper message must be 4 hex bytes if provided"); DropField(); + CLIParserFree(ctx); return PM3_ESOFT; } From 9a2e07e1a8d783773169b97d45276261bff7b687 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 23 Feb 2023 12:33:24 +0100 Subject: [PATCH 07/15] should fix time_t printing issues --- tools/mfd_aes_brute/mfd_multi_brute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/mfd_aes_brute/mfd_multi_brute.c b/tools/mfd_aes_brute/mfd_multi_brute.c index 4279fba62..3474d81d9 100644 --- a/tools/mfd_aes_brute/mfd_multi_brute.c +++ b/tools/mfd_aes_brute/mfd_multi_brute.c @@ -169,10 +169,10 @@ static void print_time(uint64_t at) { (void)localtime_r(&t, <); #endif - char res[32]; - strftime(res, sizeof(res), "%Y-%m-%d %H:%M:%S", <); + char res[70]; + strftime(res, sizeof(res), "%s ('%Y-%m-%d %H:%M:%S')", <); - printf("%"PRIu64" ( '%s' )\n", t, res); + printf("%s\n", res); } static void *brute_thread(void *arguments) { From 601b442b6c49ab3df80b17d73fd31c5f130548bf Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 23 Feb 2023 20:35:07 +0100 Subject: [PATCH 08/15] fix warning in GH actions --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d639eebc4..4d971faa6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -98,7 +98,7 @@ jobs: steps: - name: WSL setup - uses: Vampire/setup-wsl@v1 + uses: Vampire/setup-wsl@v2 with: distribution: Ubuntu-20.04 update: "true" From a4bf1c5710c87a44a9d6a22705ae7c802fe37ef7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 23 Feb 2023 20:36:27 +0100 Subject: [PATCH 09/15] update to 22.04 --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 4d971faa6..77c3dc70c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -100,7 +100,7 @@ jobs: - name: WSL setup uses: Vampire/setup-wsl@v2 with: - distribution: Ubuntu-20.04 + distribution: Ubuntu-22.04 update: "true" additional-packages: git ca-certificates From dd7c9daa8d0ee60f1399acbe21cd9489de385cb1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 23 Feb 2023 20:53:53 +0100 Subject: [PATCH 10/15] fix CID #405002 - invalid string formatter --- client/src/cmdlfguard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfguard.c b/client/src/cmdlfguard.c index 0225b2fef..c31629c5a 100644 --- a/client/src/cmdlfguard.c +++ b/client/src/cmdlfguard.c @@ -375,7 +375,7 @@ static int CmdGuardSim(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - xorKey: " _YELLOW_("%u%") " Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u") + PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - xorKey: " _YELLOW_("%u") " Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u") , xorval , facilitycode , cardnumber From 02a801f6655ac82d7a7e168bc7120577e276e668 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 23 Feb 2023 20:58:45 +0100 Subject: [PATCH 11/15] fix CID #404863 printing --- tools/mfd_aes_brute/mfd_aes_brute.c | 7 +++---- tools/mfd_aes_brute/mfd_multi_brute.c | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/mfd_aes_brute/mfd_aes_brute.c b/tools/mfd_aes_brute/mfd_aes_brute.c index b92eee31c..0cf1028b3 100644 --- a/tools/mfd_aes_brute/mfd_aes_brute.c +++ b/tools/mfd_aes_brute/mfd_aes_brute.c @@ -139,10 +139,9 @@ static void print_time(uint64_t at) { (void)localtime_r(&t, <); #endif - char res[32]; - strftime(res, sizeof(res), "%Y-%m-%d %H:%M:%S", <); - - printf("%u ( '%s' )\n", (unsigned)t, res); + char res[70]; + strftime(res, sizeof(res), "%s ('%Y-%m-%d %H:%M:%S')", <); + printf("%s\n", res); } static void *brute_thread(void *arguments) { diff --git a/tools/mfd_aes_brute/mfd_multi_brute.c b/tools/mfd_aes_brute/mfd_multi_brute.c index 3474d81d9..4e7579e8f 100644 --- a/tools/mfd_aes_brute/mfd_multi_brute.c +++ b/tools/mfd_aes_brute/mfd_multi_brute.c @@ -171,7 +171,6 @@ static void print_time(uint64_t at) { char res[70]; strftime(res, sizeof(res), "%s ('%Y-%m-%d %H:%M:%S')", <); - printf("%s\n", res); } From 93d7d46776fc1ca849ba6ccbdafc9b9dadb1a45e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 24 Feb 2023 20:57:42 +0100 Subject: [PATCH 12/15] fix proxspace build --- tools/mfd_aes_brute/mfd_aes_brute.c | 4 ++++ tools/mfd_aes_brute/mfd_multi_brute.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tools/mfd_aes_brute/mfd_aes_brute.c b/tools/mfd_aes_brute/mfd_aes_brute.c index 0cf1028b3..b19885f34 100644 --- a/tools/mfd_aes_brute/mfd_aes_brute.c +++ b/tools/mfd_aes_brute/mfd_aes_brute.c @@ -140,7 +140,11 @@ static void print_time(uint64_t at) { #endif char res[70]; +#if defined(__MINGW32__) || defined(__MINGW64__) + strftime(res, sizeof(res), "('%Y-%m-%d %H:%M:%S')", <); +#else strftime(res, sizeof(res), "%s ('%Y-%m-%d %H:%M:%S')", <); +#endif printf("%s\n", res); } diff --git a/tools/mfd_aes_brute/mfd_multi_brute.c b/tools/mfd_aes_brute/mfd_multi_brute.c index 4e7579e8f..bb2456aa1 100644 --- a/tools/mfd_aes_brute/mfd_multi_brute.c +++ b/tools/mfd_aes_brute/mfd_multi_brute.c @@ -170,7 +170,11 @@ static void print_time(uint64_t at) { #endif char res[70]; +#if defined(__MINGW32__) || defined(__MINGW64__) + strftime(res, sizeof(res), "('%Y-%m-%d %H:%M:%S')", <); +#else strftime(res, sizeof(res), "%s ('%Y-%m-%d %H:%M:%S')", <); +#endif printf("%s\n", res); } From b05a2d4525bbf54f8b3506c934945e7ea9ae251a Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Fri, 24 Feb 2023 00:55:49 +0100 Subject: [PATCH 13/15] Add mfc signature support to gen4 lua script --- client/luascripts/hf_mf_ultimatecard.lua | 34 ++++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/client/luascripts/hf_mf_ultimatecard.lua b/client/luascripts/hf_mf_ultimatecard.lua index 42a5e1887..aca2cccb7 100644 --- a/client/luascripts/hf_mf_ultimatecard.lua +++ b/client/luascripts/hf_mf_ultimatecard.lua @@ -483,17 +483,29 @@ local function write_signature(data) end local info = connect() if not info then return false, "Can't select card" end - if ulprotocol == '00' then return nil, 'Magic Card is not using the Ultralight Protocol' end - print('Writing new signature',data) - local b,c - local cmd = 'A2F%d%s' - local j = 2 - for i = 1, #data, 8 do - b = data:sub(i,i+7) - c = cmd:format(j,b) - local resp = send(c) - if resp ~= '0A' then lib14a.disconnect(); return nil, oops('Failed to write signature') end - j = j + 1 + if ulprotocol == '00' then + print('Writing new MFC signature',data) + send('CF'.._key..'6B48') + lib14a.disconnect() + connect() -- not 100% sure why it's needed, but without this blocks aren't actually written + local sig1 = data:sub(1, 32) + local sig2 = data:sub(33, 64) + + send('CF'.._key..'CD45'..sig1) + send('CF'.._key..'CD46'..sig2) + send('CF'.._key..'CD475C8FF9990DA270F0F8694B791BEA7BCC') + else + print('Writing new MFUL signature',data) + local b,c + local cmd = 'A2F%d%s' + local j = 2 + for i = 1, #data, 8 do + b = data:sub(i,i+7) + c = cmd:format(j,b) + local resp = send(c) + if resp ~= '0A' then lib14a.disconnect(); return nil, oops('Failed to write signature') end + j = j + 1 + end end lib14a.disconnect() return true, 'Ok' From 7834db8be756bbbb944f45bc5e5632a3ecdd6cd5 Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Fri, 24 Feb 2023 00:59:35 +0100 Subject: [PATCH 14/15] Add CHANGELOG.md entry, bump script version --- CHANGELOG.md | 1 + client/luascripts/hf_mf_ultimatecard.lua | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7321da285..c49a7c08e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hf iclass decrypt` - mark credentials as decrypted in the dump (@natesales) - Changed `hf iclass view` - show credentials on a decrypted dump (@natesales) - Show NTAG213TT tamper info in `hf mfu info` and add commands for configuring it's tamper feature (@mjaksn) + - Add Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato) ## [Nitride.4.16191][2023-01-29] - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) diff --git a/client/luascripts/hf_mf_ultimatecard.lua b/client/luascripts/hf_mf_ultimatecard.lua index aca2cccb7..93e64e333 100644 --- a/client/luascripts/hf_mf_ultimatecard.lua +++ b/client/luascripts/hf_mf_ultimatecard.lua @@ -13,7 +13,7 @@ local err_lock = 'use -k or change cfg0 block' local _print = 0 copyright = '' author = 'Nathan Glaser' -version = 'v1.0.4' +version = 'v1.0.5' date = 'Created - Jan 2022' desc = 'This script enables easy programming of an Ultimate Mifare Magic card' example = [[ From b486f3bba4855bf31daee88a126215ddbed7b62c Mon Sep 17 00:00:00 2001 From: weejhsteve <92703857+weejhsteve@users.noreply.github.com> Date: Wed, 1 Mar 2023 11:23:14 +0800 Subject: [PATCH 15/15] Update mfc_default_keys.dic # Food GEM 6686FADE5566 Signed-off-by: weejhsteve <92703857+weejhsteve@users.noreply.github.com> --- client/dictionaries/mfc_default_keys.dic | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index a522b001b..f3118f946 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -2028,3 +2028,5 @@ F72CD208FDF9 # # 1k - waldorf astoria 011C6CF459E8 +# Food GEM +6686FADE5566