diff --git a/CHANGELOG.md b/CHANGELOG.md index ef2cf914c..dff4bcf59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ 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] + - Changed `nfc decode -f` - now can detect and convert MFC dumpfiles to NDEF byte arrays (@iceman1001) + - Changed `nfc decode` - now handles EXTERNAL RECORDS better (@iceman1001) + - Fixed `nfc decode` - now handles NDEF Signature version1 records better (@iceman1001) + - Added new standalone mode `LF_MULTIHID` - HID26 (H1031) multi simulator (@flamebarke) + - Changed `hf 14b dump --ns` - now supports `no save` of card memory (@iceman1001) + - Changed `hf mfu dump --ns` - now supports `no save` of card memory (@iceman1001) - Changed the PM3 client to honor the preferences dump/trace paths. experimental support (@iceman1001) - Added the possibility to load `.MCT` dump files (@iceman1001) - Changed `lf t55xx dump --ns` - now supports `no save` of memory (@iceman1001) @@ -53,6 +59,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb) - Now `script run hf_mf_ultimatecard.lua -u` supports 10bytes UID (@alejandro12120) - Update documentation for installation on macOS with MacPorts (@linuxgemini) + - Added possible Paxton id to hitag2 tag info output + - Changed `hf mf sim` - reduce 50ms threshold to 6ms for reset to idle #1974 (@net147) ## [Nitride.4.16191][2023-01-29] - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index cb41bc148..da204eaca 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -50,6 +50,9 @@ define KNOWN_STANDALONE_DEFINITIONS | LF_ICEHID | LF HID collector to flashmem | | (RDV4 only) | | +----------------------------------------------------------+ +| LF_MULTIHID | LF HID 26 Bit (H1031) multi simulator | +| | - Shain Lakin | ++----------------------------------------------------------+ | LF_NEDAP_SIM | LF Nedap ID simple simulator | | | | +----------------------------------------------------------+ @@ -126,7 +129,7 @@ endef STANDALONE_MODES := LF_SKELETON -STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE +STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG STANDALONE_MODES += DANKARMULTI STANDALONE_MODES_REQ_BT := HF_REBLAY diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index 48ac2217f..6aeb163bb 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -49,6 +49,10 @@ endif ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS))) SRC_STANDALONE = lf_icehid.c endif +# WITH_STANDALONE_LF_MULTIHID +ifneq (,$(findstring WITH_STANDALONE_LF_MULTIHID,$(APP_CFLAGS))) + SRC_STANDALONE = lf_multihid.c +endif # WITH_STANDALONE_LF_NEDAP_SIM ifneq (,$(findstring WITH_STANDALONE_LF_NEDAP_SIM,$(APP_CFLAGS))) SRC_STANDALONE = lf_nedap_sim.c diff --git a/armsrc/Standalone/lf_multihid.c b/armsrc/Standalone/lf_multihid.c new file mode 100644 index 000000000..d2edd867c --- /dev/null +++ b/armsrc/Standalone/lf_multihid.c @@ -0,0 +1,76 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Shain Lakin, 2023 +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// LF HID 26 Bit (H10301) multi simulator: +// Simple LF HID26 (H10301) tag simulator +// Short click - select next slot and start simulation +// LEDS = LED ON for selected slot +// Add tags (raw) to the hid26_predefined_raw array +//----------------------------------------------------------------------------- + + +#include "standalone.h" +#include "proxmark3_arm.h" +#include "appmain.h" +#include "fpgaloader.h" +#include "util.h" +#include "dbprint.h" +#include "ticks.h" +#include "lfops.h" + +#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0])) +#define MAX_IND 4 + +void LED_Slot(int i); + +static uint64_t hid26_predefined_raw[] = {0x2004ec2e87, 0x2004421807, 0x20064312d6, 0x2006ec0c86}; +static uint8_t hid26_slots_count; + +void ModInfo(void) { + DbpString("LF HID 26 Bit (H10301) multi simulator - aka MultiHID (Shain Lakin)"); +} + +void LED_Slot(int i) { + LEDsoff(); + if (hid26_slots_count > 4) { + LED(i % MAX_IND, 0); + } else { + LED(1 << i, 0); + } +} + +void RunMod(void) { + StandAloneMode(); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + Dbprintf(">> LF HID26 multi simulator started - aka MultiHID (Shain Lakin) <<"); + + int selected = 0; //selected slot after start + hid26_slots_count = ARRAYLEN(hid26_predefined_raw); + for (;;) { + WDT_HIT(); + if (data_available()) { + LEDsoff(); + break; + } + + SpinDelay(100); + SpinUp(100); + LED_Slot(selected); + uint64_t raw_data = hid26_predefined_raw[selected]; + CmdHIDsimTAG(0, raw_data >> 32, raw_data & 0xFFFFFFFF, 0, false); + selected = (selected + 1) % hid26_slots_count; + } +} diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index f38edd00d..f659e6cbd 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2097,8 +2097,8 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { if (timer == 0) { timer = GetTickCount(); } else { - // 50ms no field --> card to idle state - if (GetTickCountDelta(timer) > 50) { + // 6ms no field --> card to idle state + if (GetTickCountDelta(timer) > 6) { return 2; } } diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index 1cd3b0d79..b51989bda 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -2029,9 +2029,8 @@ D144BD193063 8627C10A7014 453857395635 # -# Data from "the more, the marriott" mifare project (colonel borkmundus) -# -# Isn't theirs Saflok ? +# Data from "the more the marriott" mifare project (colonelborkmundus) +# aka The Horde # # 20230125-01, Elite Member Marriott Rewards 43012BD9EB87 @@ -2098,6 +2097,52 @@ C49DAE1C6049 6E029927600D 3E173F64C01C C670A9AD6066 +# 20230413-69, Westin +487339FA02E0 +# 20230413-70, Marriott Bonvoy +DBD5CA4EE467 +A0B1F234006C +180DE12B700E +# 20230413-71, Westin +1352C68F7A56 +# 20230413-76, Ritz Carlton +318BD98C1CEF +# 20230413-77, Marriott +D23C1CB1216E +# 20230413-78, Caesars +A1D92F808CAF +# 20230413-79, The Cosmopolitan, Vegas +# 96A301BCE267 +# 20230413-80, Aria +1153C319B4F8 +# 20230413-81, Aria +110C819BBEF8 +# 20230413-82, Aria +1332117E8756 +# 20230413-83, Kimpton +500AE915F50A +5032E362B484 +8B63AB712753 +# 20230413-85, Kimpton +06106E187106 +2E45C23DC541 +D9FF8BEE7550 +# 20230413-87, Marriott +42F7A186BF87 +# 20230413-88, Meritage Resort +D213B093B79A +# 20230413-89, Meritage Resort +216024C49EDF +# 20230413-90, Gaylord Palms +D201DBB6AB6E +# 20230413-91, Residence Inn +9F4AD875BB30 +# 20230413-92, Marriott +3352DB1E8777 +# 20230413-94, Marriott +09074A146605 +151F3E85EC46 +# # # Food GEM 6686FADE5566 diff --git a/client/resources/aidlist.json b/client/resources/aidlist.json index 81a153bba..ff574dd6a 100644 --- a/client/resources/aidlist.json +++ b/client/resources/aidlist.json @@ -2243,8 +2243,8 @@ "AID": "A0000002480400", "Vendor": "ISO/IEC JTC1/SC17", "Country": "", - "Name": "Personal identification (mDL)", - "Description": "ISO/IEC 18013-5:2021 compliant Mobile driving licence (mDL) application.", + "Name": "Personal identification (mDL) data transfer", + "Description": "ISO/IEC 18013-5:2021 compliant Mobile driving licence (mDL) application data transfer.", "Type": "identity" }, { @@ -2259,10 +2259,26 @@ "AID": "A000000809434343444B467631", "Vendor": "Car Connectivity Consortium (CCC)", "Country": "", + "Name": "Digital Car Key Framework", + "Description": "Used during key provisioning and configuration", + "Type": "access" + }, + { + "AID": "A000000809434343444B417631", + "Vendor": "Car Connectivity Consortium (CCC)", + "Country": "", "Name": "Digital Car Key", "Description": "", "Type": "access" }, + { + "AID": "A0000008580102", + "Vendor": "Apple", + "Country": "", + "Name": "Apple Home Key Framework", + "Description": "Home Key configuration applet. Selected after a first transaction on a newely-invited device (allegedly for mailbox sync/attestation exchange)", + "Type": "" + }, { "AID": "A0000008580101", "Vendor": "Apple", @@ -2270,5 +2286,45 @@ "Name": "Apple Home Key", "Description": "NFC Home Key for select HomeKit-compatible locks", "Type": "access" + }, + { + "AID": "A000000396564341", + "Vendor": "NXP", + "Country": "", + "Name": "MIFARE 2GO", + "Description": "AID prefix used by MIFARE 2GO-based cards", + "Type": "" + }, + { + "AID": "A0000002164954534F2D31", + "Vendor": "ITSO", + "Country": "United Kingdom", + "Name": "ITSO CMD2", + "Description": "AID used by ITSO for smartcard/phone-based transit cards", + "Type": "transit" + }, + { + "AID": "A000000632010105", + "Vendor": "CTTIC", + "Country": "China", + "Name": "China T-Union", + "Description": "Universal transit card used by many big public transit operators", + "Type": "transit" + }, + { + "AID": "D2760000254D010200", + "Vendor": "Zentraler Kreditausschuss (ZKA)", + "Country": "Germany", + "Name": "Girocard Jugendschutz", + "Description": "Age verification", + "Type": "" + }, + { + "AID": "A00000000491", + "Vendor": "MasterCard International", + "Country": "", + "Name": "Mastercard Private Label Transit", + "Description": "AID prefix used by transit cards that use private label mastercards (E.g. Ventra and HOP)", + "Type": "transit" } ] diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 12440c676..d0083fbb5 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1359,6 +1359,7 @@ static int CmdHF14BDump(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str0("f", "file", "", "(optional) filename, if no UID will be used as filename"), + arg_lit0(NULL, "ns", "no save to file"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1366,6 +1367,7 @@ static int CmdHF14BDump(const char *Cmd) { int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + bool nosave = arg_get_lit(ctx, 2); CLIParserFree(ctx); @@ -1514,15 +1516,17 @@ static int CmdHF14BDump(const char *Cmd) { print_sr_blocks(data, cardsize, card.uid); - // save to file - if (fnlen < 1) { - PrintAndLogEx(INFO, "using UID as filename"); - char *fptr = filename + snprintf(filename, sizeof(filename), "hf-14b-"); - FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), "-dump", card.uidlen); - } + if (nosave == false) { + // save to file + if (fnlen < 1) { + PrintAndLogEx(INFO, "using UID as filename"); + char *fptr = filename + snprintf(filename, sizeof(filename), "hf-14b-"); + FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), "-dump", card.uidlen); + } - size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE; - pm3_save_dump(filename, data, datalen, jsf14b, ST25TB_SR_BLOCK_SIZE); + size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE; + pm3_save_dump(filename, data, datalen, jsf14b, ST25TB_SR_BLOCK_SIZE); + } } return switch_off_field_14b(); diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index b328436bb..ba6d984ad 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3836,9 +3836,9 @@ static int CmdHFiClassEncode(const char *Cmd) { CLIParserInit(&ctx, "hf iclass encode", "Encode binary wiegand to block 7,8,9\n" "Use either --bin or --wiegand/--fc/--cn", - "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337\n" - "hf iclass encode --fc 31 --cn 337 --ki 0 -> FC 31 CN 337\n" - "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337, writing w elite key" + "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337 (H10301)\n" + "hf iclass encode -w H10301 --fc 31 --cn 337 --ki 0 -> FC 31 CN 337 (H10301)\n" + "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337 (H10301), writing w elite key" ); void *argtable[] = { diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 765342ec2..a647d90c2 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -2861,6 +2861,9 @@ tryNested: } case PM3_ESTATIC_NONCE: PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); + + e_sector[current_sector_i].Key[current_key_type_i] = 0xffffffffffff;; + e_sector[current_sector_i].foundKey[current_key_type_i] = false; // Show the results to the user PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); @@ -2907,6 +2910,10 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack } case PM3_ESTATIC_NONCE: { PrintAndLogEx(ERR, "\nError: Static encrypted nonce detected. Aborted\n"); + + e_sector[current_sector_i].Key[current_key_type_i] = 0xffffffffffff;; + e_sector[current_sector_i].foundKey[current_key_type_i] = false; + // Show the results to the user PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); @@ -3899,57 +3906,48 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----"); PrintAndLogEx(SUCCESS, " Sec | Blk | key A |res| key B |res"); PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----"); + + bool extended_legend = false; for (uint8_t i = 0; i < sectorscnt; i++) { - snprintf(strA, sizeof(strA), "------------"); - snprintf(strB, sizeof(strB), "------------"); - - if (e_sector[i].foundKey[0]) - snprintf(strA, sizeof(strA), "%012" PRIX64, e_sector[i].Key[0]); - - if (e_sector[i].foundKey[1]) - snprintf(strB, sizeof(strB), "%012" PRIX64, e_sector[i].Key[1]); - - if (e_sector[i].foundKey[0] > 1) { - PrintAndLogEx(SUCCESS, " "_YELLOW_("%03d")" | %03d | " _GREEN_("%s")" | " _BRIGHT_GREEN_("%c")" | " _GREEN_("%s")" | " _BRIGHT_GREEN_("%c") - , i - , mfSectorTrailerOfSector(i) - , strA, e_sector[i].foundKey[0] - , strB, e_sector[i].foundKey[1] - ); - } else { - - // keep track if we use start_sector or i... - uint8_t s = start_sector; - if (start_sector == 0) - s = i; - - if (e_sector[i].foundKey[0]) { - snprintf(strA, sizeof(strA), _GREEN_("%012" PRIX64), e_sector[i].Key[0]); - snprintf(resA, sizeof(resA), _BRIGHT_GREEN_("%d"), 1); - } else { - snprintf(strA, sizeof(strA), _RED_("%s"), "------------"); - snprintf(resA, sizeof(resA), _RED_("%d"), 0); - } - - if (e_sector[i].foundKey[1]) { - snprintf(strB, sizeof(strB), _GREEN_("%012" PRIX64), e_sector[i].Key[1]); - snprintf(resB, sizeof(resB), _BRIGHT_GREEN_("%d"), 1); - } else { - snprintf(strB, sizeof(strB), _RED_("%s"), "------------"); - snprintf(resB, sizeof(resB), _RED_("%d"), 0); - } - - PrintAndLogEx(SUCCESS, " " _YELLOW_("%03d") " | %03d | %s | %s | %s | %s" - , s - , mfSectorTrailerOfSector(s) - , strA, resA - , strB, resB - ); + if ((e_sector[i].foundKey[0] > 1) || (e_sector[i].foundKey[1] > 1)) { + extended_legend = true; } + + if (e_sector[i].foundKey[0]) { + snprintf(strA, sizeof(strA), _GREEN_("%012" PRIX64), e_sector[i].Key[0]); + snprintf(resA, sizeof(resA), _BRIGHT_GREEN_("%c"), e_sector[i].foundKey[0]); + } else { + snprintf(strA, sizeof(strA), _RED_("%s"), "------------"); + snprintf(resA, sizeof(resA), _RED_("%d"), 0); + } + + if (e_sector[i].foundKey[1]) { + snprintf(strB, sizeof(strB), _GREEN_("%012" PRIX64), e_sector[i].Key[1]); + snprintf(resB, sizeof(resB), _BRIGHT_GREEN_("%c"), e_sector[i].foundKey[1]); + } else { + snprintf(strB, sizeof(strB), _RED_("%s"), "------------"); + snprintf(resB, sizeof(resB), _RED_("%d"), 0); + } + + // keep track if we use start_sector or i + // show one sector or all. + uint8_t s = start_sector; + if (start_sector == 0) { + s = i; + } + + PrintAndLogEx(SUCCESS, " " _YELLOW_("%03d") " | %03d | %s | %s | %s | %s" + , s + , mfSectorTrailerOfSector(s) + , strA, resA + , strB, resB + ); } + PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----"); - if (e_sector[0].foundKey[0] > 1) { + + if (extended_legend) { PrintAndLogEx(INFO, "( " _YELLOW_("D") ":Dictionary / " _YELLOW_("S") ":darkSide / " diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 963786ebc..e47a60e7c 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -2439,6 +2439,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { arg_lit0("l", NULL, "Swap entered key's endianness"), arg_int0("p", "page", "", "Manually set start page number to start from"), arg_int0("q", "qty", "", "Manually set number of pages to dump"), + arg_lit0(NULL, "ns", "no save to file"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -2454,6 +2455,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { bool swap_endian = arg_get_lit(ctx, 3); int start_page = arg_get_int_def(ctx, 4, 0); int pages = arg_get_int_def(ctx, 5, 16); + bool nosave = arg_get_lit(ctx, 6); CLIParserFree(ctx); bool has_auth_key = false; @@ -2649,21 +2651,24 @@ static int CmdHF14AMfUDump(const char *Cmd) { printMFUdumpEx(&dump_file_data, pages, start_page); - // user supplied filename? - if (fnlen < 1) { + if (nosave == false) { + // user supplied filename? + if (fnlen < 1) { + PrintAndLogEx(INFO, "Using UID as filename"); + uint8_t uid[7] = {0}; + memcpy(uid, (uint8_t *)&dump_file_data.data, 3); + memcpy(uid + 3, (uint8_t *)&dump_file_data.data + 4, 4); + strcat(filename, "hf-mfu-"); + FillFileNameByUID(filename, uid, "-dump", sizeof(uid)); + } - PrintAndLogEx(INFO, "Using UID as filename"); - uint8_t uid[7] = {0}; - memcpy(uid, (uint8_t *)&dump_file_data.data, 3); - memcpy(uid + 3, (uint8_t *)&dump_file_data.data + 4, 4); - strcat(filename, "hf-mfu-"); - FillFileNameByUID(filename, uid, "-dump", sizeof(uid)); + uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH; + pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory, MFU_BLOCK_SIZE); + + if (is_partial) { + PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size); + } } - uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH; - pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory, MFU_BLOCK_SIZE); - - if (is_partial) - PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size); return PM3_SUCCESS; } diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index 66fb3ea42..23b8ac235 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -324,6 +324,37 @@ static int CmdLFHitagSim(const char *Cmd) { return PM3_SUCCESS; } + +static void printHitag2PaxtonDowngrade(const uint8_t *data) { + + uint64_t bytes = 0; + uint64_t num = 0; + uint64_t paxton_id = 0; + uint16_t skip = 48; + uint16_t digit = 0; + uint64_t mask = 0xF80000000000; + + for (int i = 16; i < 22; i++) { + bytes = (bytes * 0x100) + data[i]; + } + + for (int j = 0; j< 8; j++) { + num = bytes & mask; + skip -= 5; + mask = mask >> 5; + digit = (num >> skip & 15); + paxton_id = (paxton_id * 10) + digit; + + if (j == 5) { + skip -= 2; + mask = mask >> 2; + } + } + + PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------"); + PrintAndLogEx(SUCCESS, "Paxton id: %lu | 0x%lx", paxton_id, paxton_id); +} + static void printHitag2Configuration(uint8_t config) { char msg[100]; @@ -630,6 +661,8 @@ static int CmdLFHitagReader(const char *Cmd) { // print data print_hex_break(data, 48, 4); + + printHitag2PaxtonDowngrade(data); } return PM3_SUCCESS; } diff --git a/client/src/cmdnfc.c b/client/src/cmdnfc.c index df87ee6f8..6f9561783 100644 --- a/client/src/cmdnfc.c +++ b/client/src/cmdnfc.c @@ -30,6 +30,8 @@ #include "cmdhftopaz.h" #include "cmdnfc.h" #include "fileutils.h" +#include "mifare/mifaredefault.h" +#include "mifare/mad.h" void print_type4_cc_info(uint8_t *d, uint8_t n) { if (n < 0x0F) { @@ -111,6 +113,17 @@ static int CmdNfcDecode(const char *Cmd) { return res; } + // convert from MFC dump file to a pure NDEF byte array + if (HasMADKey(dump)) { + PrintAndLogEx(SUCCESS, "MFC dump file detected. Converting..."); + uint8_t ndef[4096] = {0}; + uint16_t ndeflen = 0; + uint8_t skip = (4 * MFBLOCK_SIZE); + convert_mfc_2_arr(dump + skip, bytes_read - skip, ndef, &ndeflen); + memcpy(dump, ndef, ndeflen); + bytes_read = ndeflen; + } + res = NDEFDecodeAndPrint(dump, bytes_read, verbose); if (res != PM3_SUCCESS) { PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header"); diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 9e9f674e1..3b37182fe 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -1467,12 +1467,12 @@ int convert_mfc_2_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen) if (mfIsSectorTrailer(blockno) == false) { memcpy(out, in, MFBLOCK_SIZE); + out += MFBLOCK_SIZE; + *olen += MFBLOCK_SIZE; } blockno++; - out += MFBLOCK_SIZE; in += MFBLOCK_SIZE; ilen -= MFBLOCK_SIZE; - *olen += MFBLOCK_SIZE; } return PM3_SUCCESS; } diff --git a/client/src/nfc/ndef.c b/client/src/nfc/ndef.c index b995a3e19..a97d5bb55 100644 --- a/client/src/nfc/ndef.c +++ b/client/src/nfc/ndef.c @@ -39,8 +39,6 @@ #define NDEF_VCARDTEXT "text/vcard" #define NDEF_XVCARDTEXT "text/x-vcard" - - static const char *TypeNameFormat_s[] = { "Empty Record", "Well Known Record", @@ -289,22 +287,35 @@ static int ndef_print_signature(uint8_t *data, uint8_t data_len, uint8_t *signat } static int ndefDecodeSig1(uint8_t *sig, size_t siglen) { - size_t indx = 1; + size_t indx = 1; uint8_t sigType = sig[indx] & 0x7f; bool sigURI = sig[indx] & 0x80; + indx++; - PrintAndLogEx(SUCCESS, "\tsignature type: %s", ((sigType < stNA) ? ndefSigType_s[sigType] : ndefSigType_s[stNA])); - PrintAndLogEx(SUCCESS, "\tsignature uri: %s", (sigURI ? "present" : "not present")); + PrintAndLogEx(SUCCESS, "\tType...... " _YELLOW_("%s"), ((sigType < stNA) ? ndefSigType_s[sigType] : ndefSigType_s[stNA])); + PrintAndLogEx(SUCCESS, "\tURI....... " _YELLOW_("%s"), (sigURI ? "present" : "not present")); + + if (sigType == 0 && sigURI == false) { + PrintAndLogEx(INFO, "\tRecord should be considered a start marker"); + } + if (sigType == 0 && sigURI) { + PrintAndLogEx(INFO, _RED_("\tSignature record is invalid")); + } + + uint16_t intsiglen = MemBeToUint2byte(sig + indx); + indx += 2; - size_t intsiglen = (sig[indx + 1] << 8) + sig[indx + 2]; // ecdsa 0x04 if (sigType == stECDSA_P192 || sigType == stECDSA_P256) { - indx += 3; + int slen = 24; - if (sigType == stECDSA_P256) + if (sigType == stECDSA_P256) { slen = 32; - PrintAndLogEx(SUCCESS, "\tsignature [%zu]: %s", intsiglen, sprint_hex_inrow(&sig[indx], intsiglen)); + } + + PrintAndLogEx(SUCCESS, "\tSignature [%u]...", intsiglen); + print_hex_noascii_break(&sig[indx], intsiglen, 32); uint8_t rval[300] = {0}; uint8_t sval[300] = {0}; @@ -313,38 +324,53 @@ static int ndefDecodeSig1(uint8_t *sig, size_t siglen) { PrintAndLogEx(SUCCESS, "\t\tr: %s", sprint_hex(rval + 32 - slen, slen)); PrintAndLogEx(SUCCESS, "\t\ts: %s", sprint_hex(sval + 32 - slen, slen)); } + } else { + PrintAndLogEx(SUCCESS, "\tData [%u]...", intsiglen); + print_hex_noascii_break(&sig[indx], intsiglen, 32); } + indx += intsiglen; if (sigURI) { - size_t intsigurilen = (sig[indx] << 8) + sig[indx + 1]; + + uint16_t intsigurilen = MemBeToUint2byte(sig + indx); indx += 2; - PrintAndLogEx(SUCCESS, "\tsignature uri [%zu]: %.*s", intsigurilen, (int)intsigurilen, &sig[indx]); + + PrintAndLogEx(SUCCESS, "\tSignature URI... " _YELLOW_("%.*s"), (int)intsigurilen, &sig[indx]); indx += intsigurilen; } + // CERTIFICATE SECTION + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, _CYAN_("Certificate")); + uint8_t certFormat = (sig[indx] >> 4) & 0x07; uint8_t certCount = sig[indx] & 0x0f; bool certURI = sig[indx] & 0x80; + indx++; - PrintAndLogEx(SUCCESS, "\tcertificate format: %s", ((certFormat < sfNA) ? ndefCertificateFormat_s[certFormat] : ndefCertificateFormat_s[sfNA])); - PrintAndLogEx(SUCCESS, "\tcertificates count: %d", certCount); + PrintAndLogEx(SUCCESS, "\tFormat............ " _YELLOW_("%s"), ((certFormat < sfNA) ? ndefCertificateFormat_s[certFormat] : ndefCertificateFormat_s[sfNA])); + if (certCount) { + PrintAndLogEx(SUCCESS, "\tNum of certs#..... " _YELLOW_("%d"), certCount); + } // print certificates - indx++; - for (int i = 0; i < certCount; i++) { - size_t intcertlen = (sig[indx + 1] << 8) + sig[indx + 2]; + for (uint8_t i = 0; i < certCount; i++) { + uint16_t intcertlen = MemBeToUint2byte(sig + indx); indx += 2; - PrintAndLogEx(SUCCESS, "\tcertificate %d [%zu]: %s", i + 1, intcertlen, sprint_hex_inrow(&sig[indx], intcertlen)); + PrintAndLogEx(INFO, ""); + PrintAndLogEx(SUCCESS, "\tCertificate %u [%u]...", i + 1, intcertlen); + print_hex_noascii_break(&sig[indx], intcertlen, 32); + indx += intcertlen; } - // have certificate uri + // print certificate uri if ((indx <= siglen) && certURI) { - size_t inturilen = (sig[indx] << 8) + sig[indx + 1]; + uint16_t inturilen = MemBeToUint2byte(sig + indx); indx += 2; - PrintAndLogEx(SUCCESS, "\tcertificate uri [%zu]: %.*s", inturilen, (int)inturilen, &sig[indx]); + PrintAndLogEx(SUCCESS, "\tCertificate URI... " _YELLOW_("%.*s"), (int)inturilen, &sig[indx]); } return PM3_SUCCESS; @@ -417,9 +443,9 @@ static int ndefDecodeSig2(uint8_t *sig, size_t siglen) { } static int ndefDecodeSig(uint8_t *sig, size_t siglen) { - PrintAndLogEx(SUCCESS, "\tsignature version : \t" _GREEN_("0x%02x"), sig[0]); + PrintAndLogEx(SUCCESS, "\tVersion... " _GREEN_("0x%02x"), sig[0]); if (sig[0] != 0x01 && sig[0] != 0x20) { - PrintAndLogEx(ERR, "signature version unknown."); + PrintAndLogEx(ERR, _RED_("Version unknown")); return PM3_ESOFT; } @@ -789,7 +815,7 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) { return PM3_SUCCESS; } PrintAndLogEx(INFO, "Type............ " _YELLOW_("%.*s"), (int)ndef->TypeLen, ndef->Type); - uint16_t ooblen = (ndef->Payload[1] << 8 | ndef->Payload[0]); + uint16_t ooblen = MemBeToUint2byte(ndef->Payload); PrintAndLogEx(INFO, "OOB data len.... %u", ooblen); PrintAndLogEx(INFO, "BT MAC.......... " _YELLOW_("%s"), sprint_hex(ndef->Payload + 2, 6)); // Let's check payload[8]. Tells us a bit about the UUID's. If 0x07 then it tells us a service UUID is 128bit @@ -828,6 +854,38 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) { return PM3_SUCCESS; } +// https://raw.githubusercontent.com/haldean/ndef/master/docs/NFCForum-TS-RTD_1.0.pdf +static int ndefDecodeExternal_record(NDEFHeader_t *ndef) { + + if (ndef->TypeLen == 0) { + PrintAndLogEx(INFO, "no type"); + return PM3_SUCCESS; + } + + if (ndef->PayloadLen == 0) { + PrintAndLogEx(INFO, "no payload"); + return PM3_SUCCESS; + } + + PrintAndLogEx(INFO + , " URN... " _GREEN_("urn:nfc:ext:%.*s") + , (int)ndef->TypeLen + , ndef->Type + ); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Payload [%u]...", ndef->PayloadLen); + print_hex_noascii_break(ndef->Payload, ndef->PayloadLen, 32); + + // do a character check? + if (!strncmp((char *)ndef->Type, "pilet.ee:ekaart:2", ndef->TypeLen)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("Ekaart detected") " - Trying ASN1 decode..."); + asn1_print(ndef->Payload, ndef->PayloadLen, " "); + } + return PM3_SUCCESS; +} + static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) { PrintAndLogEx(INFO, ""); @@ -835,7 +893,7 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) { case tnfEmptyRecord: PrintAndLogEx(INFO, "Empty Record"); if (ndef->TypeLen != 0 || ndef->IDLen != 0 || ndef->PayloadLen != 0) { - PrintAndLogEx(FAILED, "unexpected data in TNF_EMPTY record"); + PrintAndLogEx(FAILED, "unexpected data in empty record"); break; } break; @@ -931,20 +989,33 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) { } case tnfAbsoluteURIRecord: PrintAndLogEx(INFO, "Absolute URI Record"); - PrintAndLogEx(INFO, " payload : %.*s", (int)ndef->PayloadLen, ndef->Payload); + PrintAndLogEx(INFO, " payload : " _YELLOW_("%.*s"), (int)ndef->PayloadLen, ndef->Payload); break; case tnfExternalRecord: PrintAndLogEx(INFO, "External Record"); - PrintAndLogEx(INFO, "- decoder to be impl -"); + ndefDecodeExternal_record(ndef); break; case tnfUnknownRecord: PrintAndLogEx(INFO, "Unknown Record"); - PrintAndLogEx(INFO, "- decoder to be impl -"); + if (ndef->TypeLen != 0) { + PrintAndLogEx(FAILED, "unexpected type field"); + break; + } break; case tnfUnchangedRecord: PrintAndLogEx(INFO, "Unchanged Record"); PrintAndLogEx(INFO, "- decoder to be impl -"); break; + case tnfReservedRecord: + PrintAndLogEx(INFO, "Reserved Record"); + if (ndef->TypeLen != 0) { + PrintAndLogEx(FAILED, "unexpected type field"); + break; + } + break; + default: + PrintAndLogEx(FAILED, "unexpected tnf value... 0x%02x", ndef->TypeNameFormat); + break; } PrintAndLogEx(INFO, ""); return PM3_SUCCESS; diff --git a/client/src/nfc/ndef.h b/client/src/nfc/ndef.h index 478c28e0a..643bb70a7 100644 --- a/client/src/nfc/ndef.h +++ b/client/src/nfc/ndef.h @@ -31,7 +31,8 @@ typedef enum { tnfAbsoluteURIRecord = 0x03, tnfExternalRecord = 0x04, tnfUnknownRecord = 0x05, - tnfUnchangedRecord = 0x06 + tnfUnchangedRecord = 0x06, + tnfReservedRecord = 0x07, } TypeNameFormat_t; typedef enum { diff --git a/doc/commands.json b/doc/commands.json index 703ff688c..f8712fc47 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3100,9 +3100,9 @@ "command": "hf iclass encode", "description": "Encode binary wiegand to block 7,8,9 Use either --bin or --wiegand/--fc/--cn", "notes": [ - "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337", - "hf iclass encode --fc 31 --cn 337 --ki 0 -> FC 31 CN 337", - "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337, writing w elite key" + "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337 (H10301)", + "hf iclass encode -w H10301 --fc 31 --cn 337 --ki 0 -> FC 31 CN 337 (H10301)", + "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337 (H10301), writing w elite key" ], "offline": true, "options": [ @@ -11991,4 +11991,4 @@ "extracted_by": "PM3Help2JSON v1.00", "extracted_on": "2023-03-26T15:04:49" } -} \ No newline at end of file +} diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index 5ead60b1a..53726b9dd 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -108,6 +108,7 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo | LF_HIDBRUTE | HID corporate 1000 bruteforce - Federico dotta & Maurizio Agazzini | LF_HIDFCBRUTE | LF HID facility code bruteforce - ss23 | LF_ICEHID | LF HID collector to flashmem - Iceman1001 +| LF_MULTIHID | LF HID 26 Bit (H1031) multi simulator - Shain Lakin | LF_NEDAP_SIM | LF Nedap ID simulator | LF_NEXID | Nexwatch credentials detection mode - jrjgjk & Zolorah | LF_PROXBRUTE | HID ProxII bruteforce - Brad Antoniewicz diff --git a/tools/build_all_firmwares.sh b/tools/build_all_firmwares.sh index 644438032..4a0fe5947 100755 --- a/tools/build_all_firmwares.sh +++ b/tools/build_all_firmwares.sh @@ -22,8 +22,7 @@ echo "Destination: ${DEST:=firmware}" echo "Produce stats?: ${STATS:=false}" # Which parts to skip for the 256kb version? -SKIPS256="SKIP_HITAG=1 SKIP_LEGICRF=1 SKIP_FELICA=1 SKIP_EM4x50=1 SKIP_ISO14443b=1 SKIP_NFCBARCODE=1 SKIP_ZX8211=1" - +SKIPS256="SKIP_HITAG=1 SKIP_LEGICRF=1 SKIP_FELICA=1 SKIP_EM4x50=1 SKIP_ISO14443b=1 SKIP_NFCBARCODE=1 SKIP_ZX8211=1 SKIP_LF=1" make $MKFLAGS bootrom || exit 1 chmod 644 bootrom/obj/bootrom.elf @@ -32,7 +31,7 @@ mv bootrom/obj/bootrom.elf "$DEST/PM3BOOTROM.elf" # cf armsrc/Standalone/Makefile.hal STANDALONE_MODES=(LF_SKELETON) -STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE) +STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE) STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG) STANDALONE_MODES+=(DANKARMULTI) STANDALONE_MODES_REQ_BT=(HF_REBLAY)