diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 5fc43de19..8ee3ae52a 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1541,134 +1541,151 @@ static int CmdHF14aDesDetect(const char *Cmd) { return PM3_SUCCESS; } -/* -static int CmdHF14aDesNDEFRead(const char *Cmd) { - DropFieldDesfire(); - - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mfdes ndefread", - "Prints NFC Data Exchange Format (NDEF)", - "hf mfdes ndefread -> shows NDEF data\n" - "hf mfdes ndefread -v -> shows NDEF parsed and raw data\n" - "hf mfdes ndefread -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data with custom AID and key"); - - void *argtable[] = { - arg_param_begin, - arg_litn("v", "verbose", 0, 2, "show technical data"), - arg_str0(NULL, "aid", "", "replace default aid for NDEF"), - arg_str0("k", "key", "", "replace default key for NDEF"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - bool verbose = arg_get_lit(ctx, 1); - bool verbose2 = arg_get_lit(ctx, 1) > 1; - uint8_t aid[2] = {0}; - int aidlen; - CLIGetHexWithReturn(ctx, 2, aid, &aidlen); - uint8_t key[16] = {0}; - int keylen; - CLIGetHexWithReturn(ctx, 3, key, &keylen); - - CLIParserFree(ctx); - - uint32_t ndefAID = 0xEEEE10; - if (aidlen == 2) { - ndefAID = (aid[0] << 16) | (aid[1] << 8) | aid[2]; - } - - // set default NDEF key - uint8_t ndefkey[16] = {0}; - memcpy(ndefkey, g_mifarep_ndef_key, 16); - - // user supplied key - if (keylen == 16) { - memcpy(ndefkey, key, 16); - } - - int file_ids_len = 0; - - for (int j = (int)file_ids_len - 1; j >= 0; j--) { - PrintAndLogEx(SUCCESS, "\n\n Fileid %d (0x%02x)", file_ids[j], file_ids[j]); - - uint8_t filesettings[20] = {0}; - uint32_t fileset_len = 0; - - int res = handler_desfire_filesettings(file_ids[j], filesettings, &fileset_len); - if (res != PM3_SUCCESS) continue; - - int maclen = 0; // To be implemented - - if (fileset_len == 1 + 1 + 2 + 3 + maclen) { - int filesize = (filesettings[6] << 16) + (filesettings[5] << 8) + filesettings[4]; - mfdes_data_t fdata; - fdata.fileno = file_ids[j]; - memset(fdata.offset, 0, 3); - memset(fdata.length, 0, 3); - - uint8_t *data = (uint8_t *)calloc(filesize, sizeof(uint8_t)); - if (data == NULL) { - DropFieldDesfire(); - return PM3_EMALLOC; - } - - fdata.data = data; - res = handler_desfire_readdata(&fdata, MFDES_DATA_FILE, filesettings[1]); - if (res == PM3_SUCCESS) { - uint32_t len = le24toh(fdata.length); - NDEFDecodeAndPrint(data, datalen, verbose); - - } else { - PrintAndLogEx(ERR, "Couldn't read value. Error %d", res); - res = handler_desfire_select_application(aid); - if (res != PM3_SUCCESS) continue; - } - - free(data); - } - } - - if (!datalen) { - PrintAndLogEx(ERR, "no NDEF data"); - return PM3_SUCCESS; - } - - if (verbose2) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("DESFire NDEF raw") " ----------------"); - print_buffer(data, datalen, 1); - } - - PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes ndefread -vv`") " for more details"); - return PM3_SUCCESS; -} -*/ -/* +// https://www.nxp.com/docs/en/application-note/AN10787.pdf +// MIFARE Application Directory (MAD) +// test cardholder data 0a53616d706c656d616e00475068696c697000826d00d054656c2b312f313233342f3536373800 static int CmdHF14aDesMAD(const char *Cmd) { - DropFieldDesfire(); - CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes mad", - "Prints MIFARE Application directory (MAD)", + "Reads and prints MIFARE Application directory (MAD).", + "MAD consists of one file with issuer info (AID ffffff) and several files with AID in the special format `faaaav` (a - MAD ID, v - multiple AID over one MAD ID)\n" + "The MIFARE DESFire Card Master Key settings have to allow the MIFARE DESFire command GetApplicationIDs without authentication (from datasheet)\n" + "\n" "hf mfdes mad -> shows MAD data\n" "hf mfdes mad -v -> shows MAD parsed and raw data\n" "hf mfdes mad -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows MAD data with custom AID and key"); void *argtable[] = { arg_param_begin, - arg_litn("v", "verbose", 0, 2, "show technical data"), - arg_str0(NULL, "aid", "", "replace default aid for MAD"), - arg_str0("k", "key", "", "replace default key for MAD"), + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyno", "", "Key number"), + arg_str0("t", "algo", "", "Crypt algo: DES, 2TDEA, 3TDEA, AES"), + arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), + arg_str0("f", "kdf", "", "Key Derivation Function (KDF): None, AN10922, Gallagher"), + arg_str0("i", "kdfi", "", "KDF input (HEX 1-31 bytes)"), + arg_str0("m", "cmode", "", "Communicaton mode: plain/mac/encrypt"), + arg_str0("c", "ccset", "", "Communicaton command set: native/niso/iso"), + arg_str0("s", "schann", "", "Secure channel: d40/ev1/ev2"), + arg_str0(NULL, "aid", "", "Application ID of issuer info file, (non-standard feature!) (3 hex bytes, big endian)"), + arg_lit0(NULL, "auth", "Authenticate to get info from GetApplicationIDs command (non-standard feature!)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + + DesfireContext dctx; + int securechann = defaultSecureChannel; + uint32_t appid = 0x000000; + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, &securechann, DCMPlain, &appid); + if (res) { + CLIParserFree(ctx); + return res; + } + + bool authen = arg_get_lit(ctx, 12); + + SetAPDULogging(APDULogging); CLIParserFree(ctx); - PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfdes mad -v`") " for more details"); + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, appid, !authen, verbose); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } + + PICCInfoS PICCInfo = {0}; + AppListS AppList = {0}; + DesfireFillAppList(&dctx, &PICCInfo, AppList, false, false, false); // no deep scan, no scan files + + if (PICCInfo.freemem == 0xffffffff) + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _YELLOW_("n/a"), PICCInfo.appCount); + else + PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d") " bytes", PICCInfo.appCount, PICCInfo.freemem); + + if ((PICCInfo.keySettings & (1 << 1)) == 0) + PrintAndLogEx(WARNING, "Directory list access with CMK : " _RED_("Enabled") ". Try to read mad with Card Master Key("); + + PrintAndLogEx(SUCCESS, "----------------------------------------- " _CYAN_("MAD") " ------------------------------------------"); + bool foundFFFFFF = false; + for (int i = 0; i < PICCInfo.appCount; i++) { + if (AppList[i].appNum == 0xffffff) { + foundFFFFFF = true; + break; + } + } + + if (foundFFFFFF) { + res = DesfireSelectAIDHexNoFieldOn(&dctx, 0xffffff); + if (res == PM3_SUCCESS) { + uint32_t madver = 0; + res = DesfireValueFileOperations(&dctx, 0x00, MFDES_GET_VALUE, &madver); + if (res != PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "MAD version : " _RED_("n/a")); + } else { + if (madver == 3) + PrintAndLogEx(SUCCESS, "MAD version : " _GREEN_("3")); + else + PrintAndLogEx(WARNING, "MAD version : " _YELLOW_("%d"), madver); + } + + uint8_t data[250] = {0}; + size_t datalen = 0; + + res = DesfireReadFile(&dctx, 01, 0x000000, 0, data, &datalen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Card Holder : " _RED_("n/a")); + } else { + if (datalen > 0) { + PrintAndLogEx(SUCCESS, "Card Holder : "); + if (verbose) { + print_buffer_with_offset(data, datalen, 0, true); + PrintAndLogEx(NORMAL, ""); + } + MADCardHolderInfoDecode(data, datalen, verbose); + PrintAndLogEx(NORMAL, ""); + } else { + PrintAndLogEx(SUCCESS, "Card Holder : " _YELLOW_("none")); + } + } + + res = DesfireReadFile(&dctx, 02, 0x000000, 0, data, &datalen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Card Publisher: " _RED_("n/a")); + } else { + if (datalen > 0) { + PrintAndLogEx(SUCCESS, "Card Publisher: "); + print_buffer_with_offset(data, datalen, 0, true); + PrintAndLogEx(NORMAL, ""); + } else { + PrintAndLogEx(SUCCESS, "Card Publisher: " _YELLOW_("none")); + } + } + } else { + PrintAndLogEx(WARNING, _RED_("Can't select") " issuer information app (0xffffff)."); + } + } else { + PrintAndLogEx(WARNING, "Issuer information " _RED_("not found") " on the card."); + } + + size_t madappcount = 0; + PrintAndLogEx(SUCCESS, "Applications : "); + for (int i = 0; i < PICCInfo.appCount; i++) { + if ((AppList[i].appNum & 0xf00000) == 0xf00000) { + DesfirePrintMADAID(AppList[i].appNum, verbose); + madappcount++; + } + } + + if (madappcount == 0) + PrintAndLogEx(SUCCESS, "There is no MAD applications on the card"); + + DropField(); return PM3_SUCCESS; } -*/ static int CmdHF14ADesSelectApp(const char *Cmd) { CLIParserContext *ctx; @@ -3489,6 +3506,7 @@ static int CmdHF14ADesCreateFile(const char *Cmd) { "--rawtype/--rawdata have priority over the other settings. and with these parameters you can create any file. file id comes from parameters, all the rest data must be in the --rawdata parameter\n" "--rawrights have priority over the separate rights settings.\n" "Key/mode/etc of the authentication depends on application settings\n" + "hf mfdes createfile --aid 123456 --fid 01 --isofid 0001 --size 000010 -> create file with iso id. Authentication with defaults from `default` command\n" "hf mfdes createfile --aid 123456 --fid 01 --rawtype 01 --rawdata 000100EEEE000100 -> create file via sending rawdata to the card. Can be used to create any type of file. Authentication with defaults from `default` command\n" "hf mfdes createfile --aid 123456 --fid 01 --amode plain --rrights free --wrights free --rwrights free --chrights key0 -> create file app=123456, file=01 and mentioned rights with defaults from `default` command\n" "hf mfdes createfile -n 0 -t des -k 0000000000000000 -f none --aid 123456 --fid 01 --rawtype 00 --rawdata 00EEEE000100 -> execute with default factory setup"); @@ -5102,7 +5120,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) { PICCInfoS PICCInfo = {0}; AppListS AppList = {0}; - DesfireFillAppList(&dctx, &PICCInfo, AppList, !nodeep, scanfiles); + DesfireFillAppList(&dctx, &PICCInfo, AppList, !nodeep, scanfiles, true); printf("\33[2K\r"); // clear current line before printing PrintAndLogEx(NORMAL, ""); @@ -5228,8 +5246,7 @@ static command_t CommandTable[] = { {"setconfig", CmdHF14ADesSetConfiguration, IfPm3Iso14443a, "Set card configuration"}, {"formatpicc", CmdHF14ADesFormatPICC, IfPm3Iso14443a, "Format PICC"}, {"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"}, -// {"ndefread", CmdHF14aDesNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"}, -// {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"}, + {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records / files from the card"}, {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Applications") " -------------------"}, {"lsapp", CmdHF14ADesLsApp, IfPm3Iso14443a, "Show all applications with files list"}, {"getaids", CmdHF14ADesGetAIDs, IfPm3Iso14443a, "Get Application IDs list"}, diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index b44fb22cd..09e52948b 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -837,6 +837,28 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid) { return res; } +void DesfirePrintMADAID(uint32_t appid, bool verbose) { + uint8_t aid[3] = {0}; + DesfireAIDUintToByte(appid, aid); + if ((aid[2] >> 4) != 0xF) + return; + + uint16_t short_aid = ((aid[2] & 0xF) << 12) | (aid[1] << 4) | (aid[0] >> 4); + + PrintAndLogEx(SUCCESS, "MIFARE Classic ID (MAD): " _YELLOW_("%04X") " ver: " _YELLOW_("%01X") " AID: " _YELLOW_("%06x") " MAD AID Cluster[0x%02X]: " _YELLOW_("%s"), + short_aid, + appid & 0x0f, + appid, + short_aid >> 8, + nxp_cluster_to_text(short_aid >> 8)); + if (verbose) { + if (appid == 0xffffff) + PrintAndLogEx(SUCCESS, " Card issuer information application"); + else + MADDFDecodeAndPrint(short_aid); + } +} + void DesfirePrintAIDFunctions(uint32_t appid) { uint8_t aid[3] = {0}; DesfireAIDUintToByte(appid, aid); @@ -1460,7 +1482,7 @@ static int AppListSearchAID(uint32_t appNum, AppListS AppList, size_t appcount) return -1; } -int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles) { +int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles, bool fillAppSettings) { uint8_t buf[250] = {0}; size_t buflen = 0; @@ -1492,7 +1514,7 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi // field on-off zone DesfireFillPICCInfo(dctx, PICCInfo, deepmode); - if (PICCInfo->appCount > 0) { + if (fillAppSettings && PICCInfo->appCount > 0) { for (int i = 0; i < PICCInfo->appCount; i++) { if (i == 0) res = DesfireSelectAIDHex(dctx, appList[i].appNum, false, 0); @@ -1527,7 +1549,7 @@ int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appLi } // field on-off zone - if (PICCInfo->appCount > 0 && deepmode) { + if (fillAppSettings && PICCInfo->appCount > 0 && deepmode) { for (int i = 0; i < PICCInfo->appCount; i++) { DesfireCheckAuthCommands(appList[i].appNum, appList[i].appDFName, 0, &appList[i].authCmdCheck); } @@ -1542,9 +1564,10 @@ void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo) { PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _YELLOW_("n/a"), PICCInfo->appCount); else PrintAndLogEx(SUCCESS, "Applications count: " _GREEN_("%zu") " free memory " _GREEN_("%d") " bytes", PICCInfo->appCount, PICCInfo->freemem); - PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); - if (PICCInfo->authCmdCheck.checked) + if (PICCInfo->authCmdCheck.checked) { + PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF); DesfireCheckAuthCommandsPrint(&PICCInfo->authCmdCheck); + } if (PICCInfo->numberOfKeys > 0) { PrintKeySettings(PICCInfo->keySettings, PICCInfo->numKeysRaw, false, true); PrintAndLogEx(SUCCESS, "PICC key 0 version: %d (0x%02x)", PICCInfo->keyVersion0, PICCInfo->keyVersion0); diff --git a/client/src/mifare/desfirecore.h b/client/src/mifare/desfirecore.h index c912f6239..c19e19d1d 100644 --- a/client/src/mifare/desfirecore.h +++ b/client/src/mifare/desfirecore.h @@ -165,6 +165,7 @@ int DesfireSelectAID(DesfireContext *ctx, uint8_t *aid1, uint8_t *aid2); int DesfireSelectAIDHex(DesfireContext *ctx, uint32_t aid1, bool select_two, uint32_t aid2); int DesfireSelectAIDHexNoFieldOn(DesfireContext *ctx, uint32_t aid); void DesfirePrintAIDFunctions(uint32_t appid); +void DesfirePrintMADAID(uint32_t appid, bool verbose); int DesfireGetCardUID(DesfireContext *ctx); @@ -185,7 +186,7 @@ int DesfireGetUID(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetAIDList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireGetDFList(DesfireContext *dctx, uint8_t *resp, size_t *resplen); int DesfireFillPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo, bool deepmode); -int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles); +int DesfireFillAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList, bool deepmode, bool readFiles, bool fillAppSettings); void DesfirePrintPICCInfo(DesfireContext *dctx, PICCInfoS *PICCInfo); void DesfirePrintAppList(DesfireContext *dctx, PICCInfoS *PICCInfo, AppListS appList);