diff --git a/CHANGELOG.md b/CHANGELOG.md index b71ef48e0..db793db9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ 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 `hf iclass view` to suppress consecutive blocks with repeated contents (@nvx) + - Changed `hf iclass view` and related to suppress consecutive blocks with repeated contents with a `-z` flag, or `prefs set output --dense` (@nvx) + - Changed `hf iclass list` to display matched keys on the CHECK command rather than the card response, and made it check for elite keys too (@nvx) + - Fixed `hf iclass info` and `hf iclass view` key access info looking at the wrong card config bit (@nvx) - Added `hf gallagher decode` command and fix Gallagher diversification for card master key (@nvx) - Added mmbit-002 (kibi-002, kb5004xk1) russian tag to `hf texkom read` command (@merlokk) - Added `hf sniff --smode` skip/group adc data to consume less memory. Now it can sniff very long signals (@merlokk) diff --git a/client/dictionaries/ht2_default.dic b/client/dictionaries/ht2_default.dic index 2dc816512..f503fa543 100644 --- a/client/dictionaries/ht2_default.dic +++ b/client/dictionaries/ht2_default.dic @@ -10,3 +10,4 @@ 25293C2F # # Paxton HT2 +BDF5E846 diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index f1bb638f4..d009bb92d 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -88,7 +88,7 @@ static int cmp_uint32(const void *a, const void *b) { bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key) { - iclass_prekey_t *prekey = calloc(ICLASS_KEYS_MAX, sizeof(iclass_prekey_t)); + iclass_prekey_t *prekey = calloc(ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t)); if (prekey == NULL) { return false; } @@ -98,17 +98,20 @@ bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t * memcpy(ccnr + 8, rmac, 4); GenerateMacKeyFrom(csn, ccnr, false, false, (uint8_t *)iClass_Key_Table, ICLASS_KEYS_MAX, prekey); - qsort(prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32); + GenerateMacKeyFrom(csn, ccnr, false, true, (uint8_t *)iClass_Key_Table, ICLASS_KEYS_MAX, prekey + ICLASS_KEYS_MAX); + qsort(prekey, ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t), cmp_uint32); iclass_prekey_t lookup; memcpy(lookup.mac, tmac, 4); // binsearch - iclass_prekey_t *item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32); + iclass_prekey_t *item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t), cmp_uint32); if (item != NULL) { memcpy(key, item->key, 8); + free(prekey); return true; } + free(prekey); return false; } @@ -589,8 +592,8 @@ static void mem_app_config(const picopass_hdr_t *hdr) { PrintAndLogEx(INFO, "------------------------- " _CYAN_("KeyAccess") " ------------------------"); PrintAndLogEx(INFO, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *"); - uint8_t book = isset(mem, 0x20); - if (book) { + uint8_t keyAccess = isset(mem, 0x01); + if (keyAccess) { PrintAndLogEx(INFO, " Read A....... debit"); PrintAndLogEx(INFO, " Read B....... credit"); PrintAndLogEx(INFO, " Write A...... debit"); @@ -2450,8 +2453,9 @@ static int CmdHFiClass_loclass(const char *Cmd) { } static void detect_credential(uint8_t *data, bool *legacy, bool *se, bool *sr) { - char* r1 = strstr((char*)data + (5 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); - char* r2 = strstr((char*)data + (11 * 8), "\x05\x00\x05\x00"); + bool r1 = !memcmp(data + (5 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8); + uint8_t pattern[] = {0x05, 0x00, 0x05, 0x00}; + bool r2 = byte_strstr(data + (11 * 8), 6 * 8, pattern, sizeof(pattern)) != -1; *legacy = (r1) && (data[6 * 8] != 0x30); *se = (r2) && (data[6 * 8] == 0x30); @@ -2465,40 +2469,31 @@ static void printIclassSIO(uint8_t *iclass_dump) { bool isLegacy, isSE, isSR; detect_credential(iclass_dump, &isLegacy, &isSE, &isSR); - uint8_t pattern[] = {0x05, 0x00, 0x05, 0x00}; + uint8_t *sio_start; if (isSE) { - - int dlen = byte_strstr(iclass_dump + (6 * 8), 8*8, pattern, sizeof(pattern)); - if (dlen) { - - dlen += sizeof(pattern); - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "---------------------------- " _CYAN_("SIO - RAW") " ----------------------------"); - print_hex_noascii_break(iclass_dump + (6*8), dlen, 32); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - ASN1 TLV") " --------------------------"); - asn1_print(iclass_dump + (6 * 8), dlen, " "); - PrintAndLogEx(NORMAL, ""); - } + sio_start = iclass_dump + (6 * 8); + } else if (isSR) { + sio_start = iclass_dump + (10 * 8); + } else { + return; } - if (isSR) { - - int dlen = byte_strstr(iclass_dump + (10 * 8), 8*8, pattern, sizeof(pattern)); - - if (dlen) { - dlen += sizeof(pattern); - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "---------------------------- " _CYAN_("SIO - RAW") " ----------------------------"); - print_hex_noascii_break(iclass_dump + (10*8), dlen, 32); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - ASN1 TLV") " --------------------------"); - asn1_print(iclass_dump + (10 * 8), dlen, " "); - PrintAndLogEx(NORMAL, ""); - } + uint8_t pattern[] = {0x05, 0x00, 0x05, 0x00}; + int dlen = byte_strstr(sio_start, 8 * 8, pattern, sizeof(pattern)); + if (dlen == -1) { + return; } + + dlen += sizeof(pattern); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "---------------------------- " _CYAN_("SIO - RAW") " ----------------------------"); + print_hex_noascii_break(sio_start, dlen, 32); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - ASN1 TLV") " --------------------------"); + asn1_print(sio_start, dlen, " "); + PrintAndLogEx(NORMAL, ""); + } void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize, bool dense_output) { @@ -2543,8 +2538,10 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e */ uint8_t pagemap = get_pagemap(hdr); - bool isLegacy, isSE, isSR; - detect_credential(iclass_dump, &isLegacy, &isSE, &isSR); + bool isLegacy = false, isSE = false, isSR = false; + if (filemaxblock >= 17) { + detect_credential(iclass_dump, &isLegacy, &isSE, &isSR); + } int i = startblock; PrintAndLogEx(NORMAL, ""); @@ -3567,8 +3564,6 @@ void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elit for (int i = 0; i < iclass_tc; i++) pthread_join(threads[i], NULL); - - PrintAndLogEx(NORMAL, ""); } // print diversified keys diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index 7e79b49ee..f326a8abb 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -464,10 +464,17 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool curr_state = PICO_NONE; break; case ICLASS_CMD_CHECK: - snprintf(exp, size, "CHECK"); curr_state = PICO_AUTH_MACS; memcpy(rmac, cmd + 1, 4); memcpy(tmac, cmd + 5, 4); + + uint8_t key[8]; + if (check_known_default(csn, epurse, rmac, tmac, key)) { + snprintf(exp, size, "CHECK ( %s )", sprint_hex_inrow(key, 8)); + } else { + snprintf(exp, size, "CHECK"); + } + break; case ICLASS_CMD_READ4: snprintf(exp, size, "READ4(%d)", cmd[1]); @@ -516,11 +523,7 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool } else if (curr_state == PICO_AUTH_EPURSE) { memcpy(epurse, cmd, 8); } else if (curr_state == PICO_AUTH_MACS) { - - uint8_t key[8]; - if (check_known_default(csn, epurse, rmac, tmac, key)) { - snprintf(exp, size, "( " _GREEN_("%s") " )", sprint_hex_inrow(key, 8)); - } + snprintf(exp, size, _GREEN_("CHECK SUCCESS")); curr_state = PICO_NONE; } } diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index af8726298..2993c8def 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -149,6 +149,15 @@ typedef enum { NTAG413DNA, } nxp_cardtype_t; +typedef enum { + DESFIRE_UNKNOWN_PROD = 0, + DESFIRE_PHYSICAL, + DESFIRE_LIGHT_PHYSICAL, + DESFIRE_MICROCONTROLLER, + DESFIRE_JAVACARD, + DESFIRE_HCE, +} nxp_producttype_t; + typedef struct dfname { uint8_t aid[3]; uint8_t fid[2]; @@ -298,6 +307,43 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) { return DESFIRE_UNKNOWN; } +// ref: https://www.nxp.com/docs/en/application-note/AN12343.pdf p7 +static nxp_producttype_t getProductType(uint8_t *versionhw) { + + uint8_t product = versionhw[2]; + + if (product == 0x01) + return DESFIRE_PHYSICAL; + if (product == 0x08) + return DESFIRE_LIGHT_PHYSICAL; + if (product == 0x81 || product == 0x83) + return DESFIRE_MICROCONTROLLER; + if (product == 0x91) + return DESFIRE_JAVACARD; + if (product == 0xA1) + return DESFIRE_HCE; + return DESFIRE_UNKNOWN_PROD; +} + +static const char* getProductTypeStr(uint8_t *versionhw) { + + uint8_t product = versionhw[2]; + + if (product == 0x01) + return "MIFARE DESFire native IC (physical card)"; + if (product == 0x08) + return "MIFARE DESFire Light native IC (physical card)"; + if (product == 0x81 || product == 0x83) + return "MIFARE DESFire implementation on microcontroller (physical card)"; + if (product == 0x91) + return "MIFARE DESFire applet on Java card / secure element"; + if (product == 0xA1) + return "MIFARE DESFire HCE (MIFARE 2GO)"; + return "UNKNOWN PROD"; +} + + + static int mfdes_get_info(mfdes_info_res_t *info) { SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0); PacketResponseNG resp; @@ -627,6 +673,12 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(info.uid, info.uidlen)); PrintAndLogEx(SUCCESS, " Batch number: " _GREEN_("%s"), sprint_hex(info.details + 7, 5)); PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]); + + nxp_producttype_t prodtype = getProductType(info.versionHW); + if (prodtype != DESFIRE_UNKNOWN_PROD) { + PrintAndLogEx(SUCCESS, " Product type: %s", getProductTypeStr(info.versionHW)); + } + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information")); PrintAndLogEx(INFO, " raw: %s", sprint_hex_inrow(info.versionHW, sizeof(info.versionHW))); @@ -646,7 +698,6 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), info.versionSW[3], info.versionSW[4]); PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(info.versionSW[5])); PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionSW[6], false)); - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--------------------------------- " _CYAN_("Card capabilities") " ---------------------------------"); uint8_t major = info.versionSW[3];