support loading of flipper zero .picopass files. Also adapted to naive detect if PACS w variable length encoded is present

This commit is contained in:
iceman1001 2023-11-05 01:50:32 +01:00
commit 9c1644cd73
3 changed files with 107 additions and 26 deletions

View file

@ -1321,36 +1321,101 @@ static int CmdHFiClassESetBlk(const char *Cmd) {
return PM3_SUCCESS; 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) { static void iclass_decode_credentials(uint8_t *data) {
picopass_hdr_t *hdr = (picopass_hdr_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. // Not a Legacy or SR card, nothing to do here.
return; return;
} }
BLOCK79ENCRYPTION encryption = (data[(6 * 8) + 7] & 0x03); BLOCK79ENCRYPTION encryption = (data[(6 * PICOPASS_BLOCK_SIZE) + 7] & 0x03);
bool has_values = (memcmp(data + (8 * 7), empty, 8) != 0) && (memcmp(data + (8 * 7), zeros, 8) != 0);
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) { if (has_values && encryption == None) {
//todo: remove preamble/sentinel // todo: remove preamble/sentinel
uint32_t top = 0, mid = 0, bot = 0;
PrintAndLogEx(INFO, "Block 7 decoder"); PrintAndLogEx(INFO, "Block 7 decoder");
char hexstr[16 + 1] = {0}; if (has_new_pacs) {
hex_to_buffer((uint8_t *)hexstr, data + (8 * 7), 8, sizeof(hexstr) - 1, 0, 0, true); iclass_decode_credentials_new_pacs(b7);
hexstring_to_u96(&top, &mid, &bot, hexstr); } 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]; uint32_t top = 0, mid = 0, bot = 0;
hextobinstring(binstr, hexstr); hexstring_to_u96(&top, &mid, &bot, hexstr);
char *pbin = binstr;
while (strlen(pbin) && *(++pbin) == '0');
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 { } else {
PrintAndLogEx(INFO, "No unencrypted legacy credential found"); PrintAndLogEx(INFO, "No unencrypted legacy credential found");
} }

View file

@ -87,7 +87,9 @@ DumpFileType_t getfiletype(const char *filename) {
} else if (str_endswith(s, "mct")) { } else if (str_endswith(s, "mct")) {
o = MCT; o = MCT;
} else if (str_endswith(s, "nfc")) { } else if (str_endswith(s, "nfc")) {
o = NFC; o = FLIPPER;
} else if (str_endswith(s, "picopass")) {
o = FLIPPER;
} else { } else {
// mfd, trc, trace is binary // mfd, trc, trace is binary
o = BIN; o = BIN;
@ -1020,7 +1022,7 @@ int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, s
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
char *path; char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, ".nfc", false); int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
return PM3_EFILE; 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}; uint8_t block[MFBLOCK_SIZE] = {0};
param_gethex_to_eol(p, 0, block, MFBLOCK_SIZE, &n); param_gethex_to_eol(p, 0, block, MFBLOCK_SIZE, &n);
memcpy(&udata.bytes[(blockno * MFBLOCK_SIZE)], block, MFBLOCK_SIZE); 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; continue;
} }
} }
// add header length // add header length
if (ft == NFC_DF_MFC) { if (ft == NFC_DF_MFC || ft == NFC_DF_PICOPASS) {
*datalen = counter; *datalen = counter;
} else if (ft == NFC_DF_MFU) { } else if (ft == NFC_DF_MFU) {
*datalen += MFU_DUMP_PREFIX_LENGTH; *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; udata_t udata = (udata_t)data;
size_t len = 0; size_t len = 0;
char blocks[PATH_MAX_LENGTH] = {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")) { if (str_startswith(line, "device type: iso14443-4a")) {
retval = NFC_DF_14_4A; retval = NFC_DF_14_4A;
break; break;
} }
if (str_startswith(line, "filetype: flipper picopass device")) {
retval = NFC_DF_PICOPASS;
break;
}
} }
fclose(f); fclose(f);
@ -2302,6 +2314,9 @@ nfc_df_e detect_nfc_dump_format(const char *preferredName, bool verbose) {
case NFC_DF_14_4A: case NFC_DF_14_4A:
PrintAndLogEx(INFO, "detected ISO14443-4A based dump format. No data available"); PrintAndLogEx(INFO, "detected ISO14443-4A based dump format. No data available");
break; break;
case NFC_DF_PICOPASS:
PrintAndLogEx(INFO, "detected PICOPASS based dump format");
break;
case NFC_DF_UNKNOWN: case NFC_DF_UNKNOWN:
PrintAndLogEx(WARNING, "failed to detected dump format"); PrintAndLogEx(WARNING, "failed to detected dump format");
break; 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); res = loadFileMCT_safe(fn, pdump, dumplen);
break; break;
} }
case NFC: { case FLIPPER: {
nfc_df_e foo = detect_nfc_dump_format(fn, true); 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) { if (foo == NFC_DF_MFC) {
*pdump = calloc(maxdumplen, sizeof(uint8_t)); *pdump = calloc(maxdumplen, sizeof(uint8_t));

View file

@ -79,7 +79,7 @@ typedef enum {
JSON, JSON,
DICTIONARY, DICTIONARY,
MCT, MCT,
NFC, FLIPPER,
} DumpFileType_t; } DumpFileType_t;
typedef enum { typedef enum {
@ -96,7 +96,8 @@ typedef enum {
NFC_DF_MFDES, NFC_DF_MFDES,
NFC_DF_14_3A, NFC_DF_14_3A,
NFC_DF_14_3B, NFC_DF_14_3B,
NFC_DF_14_4A NFC_DF_14_4A,
NFC_DF_PICOPASS,
} nfc_df_e; } nfc_df_e;
int fileExists(const char *filename); int fileExists(const char *filename);