From c5c829bce2efd76140c9163821c87d246a225e2b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 23 Jul 2023 11:57:03 +0200 Subject: [PATCH] a bunch of minor textual changes, hiding things when no compilation support for it, also fixed the loop in keyroll generation. Added the skeleton SAM command --- CHANGELOG.md | 20 ++++---- client/src/cmdhficlass.c | 108 +++++++++++++++++++++++++++------------ common/cardhelper.c | 68 +++++++++++++++++++----- common/cardhelper.h | 1 + 4 files changed, 143 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcd40f863..51a06b0db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ 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] + - Fixed `hf iclass config` - now loops correct in keyroll generation (@iceman1001) + - Added `hf iclass sam` - skeleton command (@iceman1001) - Changed `lf cotag demo` - a new decoder (@iceman1001) - Changed `hf legic view/eview/info` - now in verbose mode will print raw hex dump (@iceman1001) - Added new test for cotag demod using data commands in pm3_test.sh (@iceman1001) @@ -15,7 +17,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf mfp list` - interprets MIFARE Plus commands in traces (@DidierA) - Changed `hf legic sim` - loop and return codes on deviceside updated to DEFINES (@iceman1001) - Changed `hf legic einfo` - now accepts the three different cardsizes as params (@iceman1001) - - Fix `lf cotag reader -1` - now doesn't fail (@iceman1001) + - Fixed `lf cotag reader -1` - now doesn't fail (@iceman1001) - Added support for LZ4 compressed hadnested tables (@doegox) - Changed `emv reader -v` - now tries to print found transactions logs (@iceman1001) - Added ISO4217 currency lookup (@iceman1001) @@ -23,10 +25,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `emv reader -v` - now can decode track1/2 data if found (@iceman1001) - Added `emv reader` - act as a EMV reader (@iceman1001) - Added support for Apple Wallet NFC Passes with the Value Added Services protocol implementation (@gm3197) - - Fix compiling liblua on iOS (@The-SamminAter) + - Fixed compiling liblua on iOS (@The-SamminAter) - Changed `hf_mf_luxeo_dump.lua` - now have list of keys to iterate (@iceman1001) - Fixed the timeout of TCP connections (@wh201906) - - Made the connection timeout configurable (@wh201906) + - Changed the connection timeout configurable (@wh201906) ## [Seven.4.16717][2023-06-25] - Change `hf 14a info` - now identifes QL88 tags (@iceman1001) @@ -43,7 +45,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added more default keys (@iceman1001) Thanks anon! - Fixed `pm3-flash-all` shell script now correctly identify the if running on outdated bootloader (@iceman1001) - Fixed `hf 15693/iclass sniff` trace timings (@nvx) - - Fix LegicCash segment handling in `hf_legic.lua` script (@jmichelp) + - Fixed LegicCash segment handling in `hf_legic.lua` script (@jmichelp) - Fixed `trace list` - now handles marking of crc bytes w color a bit better (@iceman1001) - Changed `hf mfu pwdgen -r` - now generates pwd/pack for Philips Sonicare, thanks @ckuenzi, @atc1441 (@iceman1001) - Changed `hf mfu info` - now detects Philips Sonicare devices (@iceman1001) @@ -133,11 +135,11 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hf mfu info` - now also does a simple OTP fingerprinting (@iceman1001) - Changed `hf mf wrbl` - now checks for strict readonly ACL's in the data to write (@iceman1001) - Changed `hf mf view` - verbose printing if strict readonly ACL's exists in dump file (@iceman1001) - - Add command `piv authsign` to get a buffer signed by the selected key (@jmichelp) - - Add command `piv scan` which tries to read all known containers on PIV (@jmichelp) - - Add support for PIV commands, over wired and contactless interfaces (@jmichelp) - - Add `--shallow` option to `hf iclass` reader commands to do shallow (ASK) reader modulation instead of OOK (@nvx) - - Improved NXP SLI/SLIX series tag identification (@nvx) + - Added command `piv authsign` to get a buffer signed by the selected key (@jmichelp) + - Added command `piv scan` which tries to read all known containers on PIV (@jmichelp) + - Added support for PIV commands, over wired and contactless interfaces (@jmichelp) + - Added `--shallow` option to `hf iclass` reader commands to do shallow (ASK) reader modulation instead of OOK (@nvx) + - Change and improved NXP SLI/SLIX series tag identification (@nvx) - Fixed buffer overflow in "lf em 4x05 sniff" (@HeinrichsH) - Fixed potential NULL array printing (@jmichelp) - Added PIV aid to resource file (@jmichelp) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index a48bbb98e..7ccec1221 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -40,7 +40,6 @@ #include "crypto/asn1utils.h" // ASN1 decoder #include "preferences.h" - #define PICOPASS_BLOCK_SIZE 8 #define NUM_CSNS 9 #define ICLASS_KEYS_MAX 8 @@ -400,9 +399,10 @@ static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *ke // encrypted 0xFF PrintAndLogEx(INFO, "Setting 0xFF's... " NOLF); - for (uint8_t i = 0x16; i <= app1_limit; i++) { + for (uint16_t i = 0x16; i < (app1_limit + 1); i++) { memcpy(data + (i * 8), ffs, sizeof(ffs)); } + PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )"); // revert potential modified app1_limit @@ -443,14 +443,14 @@ static void fuse_config(const picopass_hdr_t *hdr) { uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]); - PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8)); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "..................... app limit", hdr->conf.app_limit); - PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses); + PrintAndLogEx(INFO, " Raw... " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8)); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit); + PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses); uint8_t fuses = hdr->conf.fuses; @@ -594,47 +594,47 @@ static void mem_app_config(const picopass_hdr_t *hdr) { PrintAndLogEx(INFO, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *"); uint8_t keyAccess = isset(mem, 0x01); if (keyAccess) { - PrintAndLogEx(INFO, " Read AA1....... debit"); - PrintAndLogEx(INFO, " Write AA1...... debit"); - PrintAndLogEx(INFO, " Read AA2....... credit"); - PrintAndLogEx(INFO, " Write AA2...... credit"); + PrintAndLogEx(INFO, " Read AA1..... debit"); + PrintAndLogEx(INFO, " Write AA1.... debit"); + PrintAndLogEx(INFO, " Read AA2..... credit"); + PrintAndLogEx(INFO, " Write AA2.... credit"); PrintAndLogEx(INFO, " Debit........ debit or credit"); PrintAndLogEx(INFO, " Credit....... credit"); } else { - PrintAndLogEx(INFO, " Read AA1....... debit or credit"); - PrintAndLogEx(INFO, " Write AA1...... credit"); - PrintAndLogEx(INFO, " Read AA2....... debit or credit"); - PrintAndLogEx(INFO, " Write AA2...... credit"); + PrintAndLogEx(INFO, " Read AA1..... debit or credit"); + PrintAndLogEx(INFO, " Write AA1.... credit"); + PrintAndLogEx(INFO, " Read AA2..... debit or credit"); + PrintAndLogEx(INFO, " Write AA2.... credit"); PrintAndLogEx(INFO, " Debit........ debit or credit"); PrintAndLogEx(INFO, " Credit....... credit"); } } void print_picopass_info(const picopass_hdr_t *hdr) { - PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------"); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("Card configuration") " --------------------"); fuse_config(hdr); mem_app_config(hdr); } void print_picopass_header(const picopass_hdr_t *hdr) { - PrintAndLogEx(INFO, "--------------------------- " _CYAN_("card") " ---------------------------"); - PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); - PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); - PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); + PrintAndLogEx(INFO, "--------------------------- " _CYAN_("Card") " ---------------------------"); + PrintAndLogEx(SUCCESS, " CSN... " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); + PrintAndLogEx(SUCCESS, " Config... %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); + PrintAndLogEx(SUCCESS, "E-purse... %s card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); if (memcmp(hdr->key_d, zeros, sizeof(zeros)) && memcmp(hdr->key_d, empty, sizeof(empty))) { - PrintAndLogEx(SUCCESS, " Kd: " _YELLOW_("%s") " debit key", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); + PrintAndLogEx(SUCCESS, " Kd... " _YELLOW_("%s") " debit key", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); } else { - PrintAndLogEx(SUCCESS, " Kd: %s debit key ( hidden )", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); + PrintAndLogEx(SUCCESS, " Kd... %s debit key ( hidden )", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); } if (memcmp(hdr->key_c, zeros, sizeof(zeros)) && memcmp(hdr->key_c, empty, sizeof(empty))) { - PrintAndLogEx(SUCCESS, " Kc: " _YELLOW_("%s") " credit key", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); + PrintAndLogEx(SUCCESS, " Kc... " _YELLOW_("%s") " credit key", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); } else { - PrintAndLogEx(SUCCESS, " Kc: %s credit key ( hidden )", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); + PrintAndLogEx(SUCCESS, " Kc... %s credit key ( hidden )", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); } - PrintAndLogEx(SUCCESS, " AIA: %s Application Issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); + PrintAndLogEx(SUCCESS, " AIA... %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); } static int CmdHFiClassList(const char *Cmd) { @@ -2469,7 +2469,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { return PM3_SUCCESS; // crypto helper available. - PrintAndLogEx(INFO, "----------------------------- " _CYAN_("cardhelper") " -----------------------------"); + PrintAndLogEx(INFO, "----------------------------- " _CYAN_("Cardhelper") " -----------------------------"); switch (blockno) { case 6: { @@ -2509,7 +2509,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { PrintAndLogEx(SUCCESS, " bin : %s", pbin); PrintAndLogEx(INFO, ""); - PrintAndLogEx(INFO, "------------------------------ " _CYAN_("wiegand") " -------------------------------"); + PrintAndLogEx(INFO, "------------------------------ " _CYAN_("Wiegand") " -------------------------------"); wiegand_message_t packed = initialize_message_object(top, mid, bot, 0); HIDTryUnpack(&packed); } else { @@ -4147,6 +4147,48 @@ static int CmdHFiClassConfigCard(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFiClassSAM(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass sam", + "Manage via SAM\n", + "hf iclass sam\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("d", "data", "", "data"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + int dlen = 0; + uint8_t data[128] = {0}; + CLIGetHexWithReturn(ctx, 1, data, &dlen); + + bool verbose = arg_get_lit(ctx, 2); + CLIParserFree(ctx); + + Iso7816CommandChannel channel = CC_CONTACT; + if (IfPm3Smartcard() == false) { + if (channel == CC_CONTACT) { + PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting"); + return PM3_EDEVNOTSUPP; + } + } + + int res = IsHIDSamPresent(verbose); + if (res != PM3_SUCCESS) { + return res; + } + + SetAPDULogging(verbose); + +// do things with sending apdus.. + + SetAPDULogging(false); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, {"help", CmdHelp, AlwaysAvailable, "This help"}, @@ -4156,7 +4198,7 @@ static command_t CommandTable[] = { {"list", CmdHFiClassList, AlwaysAvailable, "List iclass history"}, {"rdbl", CmdHFiClass_ReadBlock, IfPm3Iclass, "Read Picopass / iCLASS block"}, {"reader", CmdHFiClassReader, IfPm3Iclass, "Act like a Picopass / iCLASS reader"}, - {"restore", CmdHFiClassRestore, IfPm3Iclass, "Restore a dump file onto a Picopass / iCLASS tag"}, + {"restore", CmdHFiClassRestore, IfPm3Iclass, "Restore a dump file onto a Picopass / iCLASS tag"}, {"sniff", CmdHFiClassSniff, IfPm3Iclass, "Eavesdrop Picopass / iCLASS communication"}, {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "Write Picopass / iCLASS block"}, @@ -4165,7 +4207,7 @@ static command_t CommandTable[] = { {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "Check keys"}, {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "Use loclass to perform bruteforce reader attack"}, {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "Uses authentication trace to check for key in dictionary file"}, - {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"}, + {"-----------", CmdHelp, IfPm3Iclass, "--------------------- " _CYAN_("simulation") " ---------------------"}, {"sim", CmdHFiClassSim, IfPm3Iclass, "Simulate iCLASS tag"}, {"eload", CmdHFiClassELoad, IfPm3Iclass, "Load Picopass / iCLASS dump file into emulator memory"}, {"esave", CmdHFiClassESave, IfPm3Iclass, "Save emulator memory to file"}, @@ -4180,6 +4222,8 @@ static command_t CommandTable[] = { {"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "Manage keys to use with iclass commands"}, {"permutekey", CmdHFiClassPermuteKey, AlwaysAvailable, "Permute function from 'heart of darkness' paper"}, {"view", CmdHFiClassView, AlwaysAvailable, "Display content from tag dump file"}, + {"-----------", CmdHelp, IfPm3Smartcard, "--------------------- " _CYAN_("SAM") " ---------------------"}, + {"sam", CmdHFiClassSAM, IfPm3Smartcard, "SAM tests"}, {NULL, NULL, NULL, NULL} }; diff --git a/common/cardhelper.c b/common/cardhelper.c index c8c8b6bd8..fe0f7957f 100644 --- a/common/cardhelper.c +++ b/common/cardhelper.c @@ -35,26 +35,68 @@ // look for CardHelper bool IsCardHelperPresent(bool verbose) { - if (IfPm3Smartcard()) { - int resp_len = 0; - uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00}; - uint8_t resp[30] = {0}; - ExchangeAPDUSC(verbose, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len); + if (IfPm3Smartcard() == false) { + return false; + } - if (resp_len < 8) { - return false; - } + int resp_len = 0; + uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00}; + uint8_t resp[30] = {0}; + ExchangeAPDUSC(verbose, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len); - if (strstr("CryptoHelper", (char *)resp) == 0) { - if (verbose) { - PrintAndLogEx(INFO, "Found smart card helper"); - } - return true; + if (resp_len < 8) { + return false; + } + + if (strstr("CryptoHelper", (char *)resp) == 0) { + if (verbose) { + PrintAndLogEx(INFO, "Found smart card helper"); } + return true; } return false; } +bool IsHIDSamPresent(bool verbose) { + + if (IfPm3Smartcard() == false) { + return false; + } + + // detect SAM + smart_card_atr_t card; + smart_select(verbose, &card); + if (!card.atr_len) { + PrintAndLogEx(ERR, "Can't get ATR from a smart card"); + return false; + } + + // SAM identification + uint8_t sam_atr[] = {0x3B, 0x95, 0x96, 0x80, 0xB1, 0xFE, 0x55, 0x1F, 0xC7, 0x47, 0x72, 0x61, 0x63, 0x65, 0x13}; + if (memcmp(card.atr, sam_atr, card.atr_len) < 0) { + + uint8_t sam_atr2[] = {0x3b, 0x90, 0x96, 0x91, 0x81, 0xb1, 0xfe, 0x55, 0x1f, 0xc7, 0xd4}; + if (memcmp(card.atr, sam_atr2, card.atr_len) < 0) { + if (verbose) { + PrintAndLogEx(SUCCESS, "Not detecting a SAM"); + } + return false; + } + } + + // Suspect some SAMs has version name in their ATR + uint8_t T0 = card.atr[1]; + uint8_t K = T0 & 0x0F; + if (K > 4 && verbose) { + if (byte_strstr(card.atr, card.atr_len, (const uint8_t*)"Grace", 5)> -1) { + PrintAndLogEx(SUCCESS, "SAM (Grace) detected"); + } else if (byte_strstr(card.atr, card.atr_len, (const uint8_t*)"Hopper", 6) > -1) { + PrintAndLogEx(SUCCESS, "SAM (Hopper) detected"); + } + } + return true; +} + static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) { uint8_t cmd[] = {0x96, ins, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(cmd + 5, src, 8); diff --git a/common/cardhelper.h b/common/cardhelper.h index 9574397a1..b88ff1e16 100644 --- a/common/cardhelper.h +++ b/common/cardhelper.h @@ -22,6 +22,7 @@ #include #include "common.h" +bool IsHIDSamPresent(bool verbose); bool IsCardHelperPresent(bool verbose); bool Encrypt(uint8_t *src, uint8_t *dest); bool Decrypt(uint8_t *src, uint8_t *dest);