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
parent 4df28b88d3
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;
}
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");
}

View file

@ -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));

View file

@ -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);