diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 17c8f68aa..0071601a5 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1321,36 +1321,101 @@ static int CmdHFiClassESetBlk(const char *Cmd) { return PM3_SUCCESS; } +static bool iclass_detect_new_pacs(uint8_t *d) { + uint8_t n = 0; + while (n++ < (PICOPASS_BLOCK_SIZE / 2)) { + if (d[n] && + d[n + 1] == 0xA6) { + return true; + } + } + return false; +} + +// block 7 decoder for PACS +static int iclass_decode_credentials_new_pacs(uint8_t *d) { + + uint8_t offset = 0; + while(d[offset] == 0 && (offset < PICOPASS_BLOCK_SIZE / 2)) { + offset++; + } + + uint8_t pad = d[offset]; + + PrintAndLogEx(INFO, "%u , %u", offset, pad); + + char *binstr = (char *)calloc((PICOPASS_BLOCK_SIZE * 8) + 1, sizeof(uint8_t)); + if (binstr == NULL) { + return PM3_EMALLOC; + } + + uint8_t n = PICOPASS_BLOCK_SIZE - offset - 2; + byte_2_binstr(binstr, d + offset + 2, n); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(d + offset + 2, n)); + PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); + + binstr[strlen(binstr) - pad] = '\0'; + PrintAndLogEx(SUCCESS, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr)); + + size_t hexlen = 0; + uint8_t hex[16] = {0}; + binstr_2_bytes(hex, &hexlen, binstr); + PrintAndLogEx(SUCCESS, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen)); + + uint32_t top = 0, mid = 0, bot = 0; + if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) { + PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); + free(binstr); + return PM3_EINVARG; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Wiegand decode"); + wiegand_message_t packed = initialize_message_object(top, mid, bot, 0); + HIDTryUnpack(&packed); +} + static void iclass_decode_credentials(uint8_t *data) { picopass_hdr_t *hdr = (picopass_hdr_t *)data; - if (memcmp(hdr->app_issuer_area, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", PICOPASS_BLOCK_SIZE)) { + if (memcmp(hdr->app_issuer_area, empty, PICOPASS_BLOCK_SIZE)) { // Not a Legacy or SR card, nothing to do here. return; } - BLOCK79ENCRYPTION encryption = (data[(6 * 8) + 7] & 0x03); - bool has_values = (memcmp(data + (8 * 7), empty, 8) != 0) && (memcmp(data + (8 * 7), zeros, 8) != 0); + BLOCK79ENCRYPTION encryption = (data[(6 * PICOPASS_BLOCK_SIZE) + 7] & 0x03); + + uint8_t *b7 = data + (PICOPASS_BLOCK_SIZE * 7); + + bool has_new_pacs = iclass_detect_new_pacs(b7); + bool has_values = (memcmp(b7, empty, PICOPASS_BLOCK_SIZE) != 0) && (memcmp(b7, zeros, PICOPASS_BLOCK_SIZE) != 0); if (has_values && encryption == None) { - //todo: remove preamble/sentinel - uint32_t top = 0, mid = 0, bot = 0; - + // todo: remove preamble/sentinel PrintAndLogEx(INFO, "Block 7 decoder"); - char hexstr[16 + 1] = {0}; - hex_to_buffer((uint8_t *)hexstr, data + (8 * 7), 8, sizeof(hexstr) - 1, 0, 0, true); - hexstring_to_u96(&top, &mid, &bot, hexstr); + if (has_new_pacs) { + iclass_decode_credentials_new_pacs(b7); + } else { + char hexstr[16 + 1] = {0}; + hex_to_buffer((uint8_t *)hexstr, b7, PICOPASS_BLOCK_SIZE, sizeof(hexstr) - 1, 0, 0, true); - char binstr[64 + 1]; - hextobinstring(binstr, hexstr); - char *pbin = binstr; - while (strlen(pbin) && *(++pbin) == '0'); + uint32_t top = 0, mid = 0, bot = 0; + hexstring_to_u96(&top, &mid, &bot, hexstr); - PrintAndLogEx(SUCCESS, "Binary..................... " _GREEN_("%s"), pbin); + char binstr[64 + 1]; + hextobinstring(binstr, hexstr); + char *pbin = binstr; + while (strlen(pbin) && *(++pbin) == '0'); + + PrintAndLogEx(SUCCESS, "Binary..................... " _GREEN_("%s"), pbin); + + PrintAndLogEx(INFO, "Wiegand decode"); + wiegand_message_t packed = initialize_message_object(top, mid, bot, 0); + HIDTryUnpack(&packed); + } - PrintAndLogEx(INFO, "Wiegand decode"); - wiegand_message_t packed = initialize_message_object(top, mid, bot, 0); - HIDTryUnpack(&packed); } else { PrintAndLogEx(INFO, "No unencrypted legacy credential found"); } diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 52c0a28bf..1ddb66d74 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -87,7 +87,9 @@ DumpFileType_t getfiletype(const char *filename) { } else if (str_endswith(s, "mct")) { o = MCT; } else if (str_endswith(s, "nfc")) { - o = NFC; + o = FLIPPER; + } else if (str_endswith(s, "picopass")) { + o = FLIPPER; } else { // mfd, trc, trace is binary o = BIN; @@ -1020,7 +1022,7 @@ int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, s int retval = PM3_SUCCESS; char *path; - int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, ".nfc", false); + int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false); if (res != PM3_SUCCESS) { return PM3_EFILE; } @@ -1221,14 +1223,18 @@ int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, s uint8_t block[MFBLOCK_SIZE] = {0}; param_gethex_to_eol(p, 0, block, MFBLOCK_SIZE, &n); memcpy(&udata.bytes[(blockno * MFBLOCK_SIZE)], block, MFBLOCK_SIZE); + } else if (ft == NFC_DF_PICOPASS) { + uint8_t block[PICOPASS_BLOCK_SIZE] = {0}; + param_gethex_to_eol(p, 0, block, PICOPASS_BLOCK_SIZE, &n); + memcpy(&udata.bytes[(blockno * PICOPASS_BLOCK_SIZE)], block, PICOPASS_BLOCK_SIZE); } - counter += MFBLOCK_SIZE; + counter += PICOPASS_BLOCK_SIZE; continue; } } // add header length - if (ft == NFC_DF_MFC) { + if (ft == NFC_DF_MFC || ft == NFC_DF_PICOPASS) { *datalen = counter; } else if (ft == NFC_DF_MFU) { *datalen += MFU_DUMP_PREFIX_LENGTH; @@ -1382,6 +1388,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz } udata_t udata = (udata_t)data; + size_t len = 0; char blocks[PATH_MAX_LENGTH] = {0}; @@ -2278,7 +2285,12 @@ nfc_df_e detect_nfc_dump_format(const char *preferredName, bool verbose) { if (str_startswith(line, "device type: iso14443-4a")) { retval = NFC_DF_14_4A; break; - } + } + if (str_startswith(line, "filetype: flipper picopass device")) { + retval = NFC_DF_PICOPASS; + break; + } + } fclose(f); @@ -2302,6 +2314,9 @@ nfc_df_e detect_nfc_dump_format(const char *preferredName, bool verbose) { case NFC_DF_14_4A: PrintAndLogEx(INFO, "detected ISO14443-4A based dump format. No data available"); break; + case NFC_DF_PICOPASS: + PrintAndLogEx(INFO, "detected PICOPASS based dump format"); + break; case NFC_DF_UNKNOWN: PrintAndLogEx(WARNING, "failed to detected dump format"); break; @@ -2757,9 +2772,9 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl res = loadFileMCT_safe(fn, pdump, dumplen); break; } - case NFC: { + case FLIPPER: { nfc_df_e foo = detect_nfc_dump_format(fn, true); - if (foo == NFC_DF_MFC || foo == NFC_DF_MFU) { + if (foo == NFC_DF_MFC || foo == NFC_DF_MFU || foo == NFC_DF_PICOPASS) { if (foo == NFC_DF_MFC) { *pdump = calloc(maxdumplen, sizeof(uint8_t)); diff --git a/client/src/fileutils.h b/client/src/fileutils.h index 4e679be5a..1af72f28d 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -79,7 +79,7 @@ typedef enum { JSON, DICTIONARY, MCT, - NFC, + FLIPPER, } DumpFileType_t; typedef enum { @@ -96,7 +96,8 @@ typedef enum { NFC_DF_MFDES, NFC_DF_14_3A, NFC_DF_14_3B, - NFC_DF_14_4A + NFC_DF_14_4A, + NFC_DF_PICOPASS, } nfc_df_e; int fileExists(const char *filename);