Merge pull request #1448 from merlokk/desf_mad

Desfire mad command
This commit is contained in:
Oleg Moiseenko 2021-08-12 15:58:33 +03:00 committed by GitHub
commit c0603c98be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 161 additions and 120 deletions

View file

@ -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", "<aid>", "replace default aid for NDEF"),
arg_str0("k", "key", "<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", "<aid>", "replace default aid for MAD"),
arg_str0("k", "key", "<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", "<keyno>", "Key number"),
arg_str0("t", "algo", "<DES/2TDEA/3TDEA/AES>", "Crypt algo: DES, 2TDEA, 3TDEA, AES"),
arg_str0("k", "key", "<Key>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"),
arg_str0("f", "kdf", "<none/AN10922/gallagher>", "Key Derivation Function (KDF): None, AN10922, Gallagher"),
arg_str0("i", "kdfi", "<kdfi>", "KDF input (HEX 1-31 bytes)"),
arg_str0("m", "cmode", "<plain/mac/encrypt>", "Communicaton mode: plain/mac/encrypt"),
arg_str0("c", "ccset", "<native/niso/iso>", "Communicaton command set: native/niso/iso"),
arg_str0("s", "schann", "<d40/ev1/ev2>", "Secure channel: d40/ev1/ev2"),
arg_str0(NULL, "aid", "<app id hex>", "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"},

View file

@ -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);
if (PICCInfo->authCmdCheck.checked) {
PrintAndLogEx(SUCCESS, "PICC level auth commands: " NOLF);
if (PICCInfo->authCmdCheck.checked)
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);

View file

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