mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Add hf gallagher delete
command
This commit is contained in:
parent
28437f018b
commit
81da8a1317
1 changed files with 169 additions and 9 deletions
|
@ -116,6 +116,7 @@ static int authenticate(DesfireContext_t *ctx, bool verbose) {
|
||||||
// TODO: do these both need to be set?
|
// TODO: do these both need to be set?
|
||||||
DesfireSetCommMode(ctx, DCMPlain);
|
DesfireSetCommMode(ctx, DCMPlain);
|
||||||
DesfireSetCommandSet(ctx, DCCNativeISO);
|
DesfireSetCommandSet(ctx, DCCNativeISO);
|
||||||
|
DesfireClearSession(ctx);
|
||||||
|
|
||||||
int res = DesfireAuthenticate(ctx, DACEV1, false);
|
int res = DesfireAuthenticate(ctx, DACEV1, false);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
|
@ -295,7 +296,7 @@ static int readCard(uint32_t aid, uint8_t *sitekey, bool verbose, bool quiet) {
|
||||||
numEntries = 1;
|
numEntries = 1;
|
||||||
} else {
|
} else {
|
||||||
res = readCardApplicationDirectory(&dctx, cad, ARRAYLEN(cad), &numEntries, verbose);
|
res = readCardApplicationDirectory(&dctx, cad, ARRAYLEN(cad), &numEntries, verbose);
|
||||||
HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading card application directory");
|
HFGAL_RET_IF_ERR_MAYBE_MSG(res, !quiet, "Failed reading Card Application Directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through each application in the CAD
|
// Loop through each application in the CAD
|
||||||
|
@ -375,6 +376,28 @@ static int CmdGallagherReader(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete the CAD or an application that contains cardholder credentials.
|
||||||
|
*
|
||||||
|
* @param sitekey MIFARE site key.
|
||||||
|
* @param aid Application ID to remove.
|
||||||
|
*/
|
||||||
|
static int deleteGallagherApplication(DesfireContext_t *ctx, uint8_t *sitekey, uint32_t aid, bool verbose) {
|
||||||
|
// Select application & authenticate
|
||||||
|
DesfireSetKeyNoClear(ctx, 0, T_AES, sitekey);
|
||||||
|
DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0);
|
||||||
|
int res = selectAidAndAuthenticate(ctx, aid, verbose);
|
||||||
|
HFGAL_RET_IF_ERR(res);
|
||||||
|
|
||||||
|
// Delete application
|
||||||
|
DesfireSetCommMode(ctx, DCMMACed);
|
||||||
|
res = DesfireDeleteApplication(ctx, aid);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed deleting AID %06X", aid);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Successfully deleted AID %06X", aid);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new application to store Gallagher cardholder credentials.
|
* @brief Create a new application to store Gallagher cardholder credentials.
|
||||||
*
|
*
|
||||||
|
@ -556,7 +579,7 @@ static int createGallagherCAD(DesfireContext_t *ctx, uint8_t *sitekey, bool verb
|
||||||
* @param aid Application ID to add to the CAD.
|
* @param aid Application ID to add to the CAD.
|
||||||
* @param creds Gallagher cardholder credentials (region_code & facility_code are required).
|
* @param creds Gallagher cardholder credentials (region_code & facility_code are required).
|
||||||
*/
|
*/
|
||||||
static int updateGallagherCAD(DesfireContext_t *ctx, uint8_t *sitekey, uint32_t aid, GallagherCredentials_t *creds, bool verbose) {
|
static int addToGallagherCAD(DesfireContext_t *ctx, uint8_t *sitekey, uint32_t aid, GallagherCredentials_t *creds, bool verbose) {
|
||||||
// Check if CAD exists
|
// Check if CAD exists
|
||||||
uint8_t cad[36 * 3] = {0};
|
uint8_t cad[36 * 3] = {0};
|
||||||
uint8_t numEntries = 0;
|
uint8_t numEntries = 0;
|
||||||
|
@ -630,17 +653,87 @@ static int updateGallagherCAD(DesfireContext_t *ctx, uint8_t *sitekey, uint32_t
|
||||||
PrintAndLogEx(INFO, "Created file %d in CAD (currently has empty contents)", fileId);
|
PrintAndLogEx(INFO, "Created file %d in CAD (currently has empty contents)", fileId);
|
||||||
|
|
||||||
// Write file
|
// Write file
|
||||||
res = DesfireWriteFile(ctx, fileId, 0, 36, entry);
|
res = DesfireWriteFile(ctx, fileId, 0, 36, &cad[fileId * 36]);
|
||||||
} else {
|
} else
|
||||||
// Write file
|
// Write file
|
||||||
res = DesfireWriteFile(ctx, fileId, entryNum * 6, 6, entry);
|
res = DesfireWriteFile(ctx, fileId, entryNum * 6, 6, entry);
|
||||||
}
|
|
||||||
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed writing data to file %d in CAD (AID %06X)", fileId, CAD_AID);
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed writing data to file %d in CAD (AID %06X)", fileId, CAD_AID);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Successfully added new entry for %06X to the Card Application Directory", aid);
|
PrintAndLogEx(INFO, "Successfully added new entry for %06X to the Card Application Directory", aid);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove an entry from the Gallagher Card Application Directory.
|
||||||
|
*
|
||||||
|
* @param sitekey MIFARE site key.
|
||||||
|
* @param aid Application ID to add to the CAD.
|
||||||
|
*/
|
||||||
|
static int removeFromGallagherCAD(DesfireContext_t *ctx, uint8_t *sitekey, uint32_t aid, bool verbose) {
|
||||||
|
// Check if CAD exists
|
||||||
|
uint8_t cad[36 * 3] = {0};
|
||||||
|
uint8_t numEntries = 0;
|
||||||
|
|
||||||
|
int res = readCardApplicationDirectory(ctx, cad, ARRAYLEN(cad), &numEntries, verbose);
|
||||||
|
HFGAL_RET_IF_ERR(res);
|
||||||
|
|
||||||
|
// Check if facility already exists in CAD
|
||||||
|
uint8_t entryNum = 0;
|
||||||
|
for (; entryNum < numEntries; entryNum++) {
|
||||||
|
if (aid > 0 && aid == cadAidByteToUint(&cad[entryNum * 6 + 3]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (entryNum >= numEntries)
|
||||||
|
HFGAL_RET_ERR(PM3_EINVARG, "Specified facility or AID does not exist in the Card Application Directory");
|
||||||
|
|
||||||
|
// Remove entry (shift all entries left, then clear the last entry)
|
||||||
|
memmove(&cad[entryNum * 6], &cad[(entryNum + 1) * 6], ARRAYLEN(cad) - (entryNum + 1) * 6);
|
||||||
|
memset(&cad[ARRAYLEN(cad) - 6], 0, 6);
|
||||||
|
|
||||||
|
// Select application & authenticate
|
||||||
|
DesfireSetKeyNoClear(ctx, 0, T_AES, sitekey);
|
||||||
|
DesfireSetKdf(ctx, MFDES_KDF_ALGO_GALLAGHER, NULL, 0);
|
||||||
|
res = selectAidAndAuthenticate(ctx, CAD_AID, verbose);
|
||||||
|
HFGAL_RET_IF_ERR(res);
|
||||||
|
|
||||||
|
// Determine what files we need to update
|
||||||
|
uint8_t fileIdStart = (entryNum - 1) / 6;
|
||||||
|
uint8_t fileIdStop = (numEntries - 1) / 6;
|
||||||
|
|
||||||
|
for (uint8_t fileId = fileIdStart; fileId <= fileIdStop; fileId++) {
|
||||||
|
// Write file
|
||||||
|
res = DesfireWriteFile(ctx, fileId, 0, 36, &cad[fileId * 36]);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed writing data to file %d in CAD (AID %06X)", fileId, CAD_AID);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(INFO, "Updated file %d in CAD", fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete empty files if necessary
|
||||||
|
if (fileIdStart != fileIdStop) {
|
||||||
|
uint8_t fileId = fileIdStop;
|
||||||
|
|
||||||
|
DesfireSetCommMode(ctx, DCMMACed);
|
||||||
|
res = DesfireDeleteFile(ctx, fileId);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed deleting file %d from CAD (AID %06X)", fileId, CAD_AID);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(INFO, "Deleted unnecessary file %d from CAD (AID %06X)", fileId, CAD_AID);
|
||||||
|
|
||||||
|
// Delete the Card Application Directory if necessary (if we just deleted the last file in it)
|
||||||
|
if (fileId == 0) {
|
||||||
|
res = deleteGallagherApplication(ctx, sitekey, CAD_AID, verbose);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed deleting file %d from CAD (AID %06X)", fileId, CAD_AID);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(INFO, "Removed CAD because it was empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Successfully removed %06X from the Card Application Directory", aid);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdGallagherClone(const char *Cmd) {
|
static int CmdGallagherClone(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf gallagher clone",
|
CLIParserInit(&ctx, "hf gallagher clone",
|
||||||
|
@ -737,11 +830,11 @@ static int CmdGallagherClone(const char *Cmd) {
|
||||||
HFGAL_RET_ERR(PM3_EFATAL, "Could not find an available AID, card is full");
|
HFGAL_RET_ERR(PM3_EFATAL, "Could not find an available AID, card is full");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update card application directory
|
// Update Card Application Directory
|
||||||
DesfireSetKeyNoClear(&dctx, keyNum, algo, key);
|
DesfireSetKeyNoClear(&dctx, keyNum, algo, key);
|
||||||
DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0);
|
DesfireSetKdf(&dctx, MFDES_KDF_ALGO_NONE, NULL, 0);
|
||||||
res = updateGallagherCAD(&dctx, sitekey, aid, &creds, verbose);
|
res = addToGallagherCAD(&dctx, sitekey, aid, &creds, verbose);
|
||||||
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed updating Gallagher card application directory");
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed updating Gallagher Card Application Directory");
|
||||||
|
|
||||||
// Create application
|
// Create application
|
||||||
DesfireSetKeyNoClear(&dctx, keyNum, algo, key);
|
DesfireSetKeyNoClear(&dctx, keyNum, algo, key);
|
||||||
|
@ -759,6 +852,72 @@ static int CmdGallagherClone(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CmdGallagherDelete(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf gallagher delete",
|
||||||
|
"delete Gallagher application from a DESFire card",
|
||||||
|
"hf gallagher delete --aid 2081f4 --sitekey 00112233445566778899aabbccddeeff"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0(NULL, "apdu", "show APDU requests and responses"),
|
||||||
|
arg_lit0("v", "verbose", "Verbose mode"),
|
||||||
|
|
||||||
|
arg_str1(NULL, "aid", "<hex>", "Application ID to delete (3 bytes)"),
|
||||||
|
arg_str0(NULL, "sitekey", "<hex>", "Master site key to compute diversified keys (16 bytes) [default=3112B738D8862CCD34302EB299AAB456]"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
SetAPDULogging(arg_get_lit(ctx, 1));
|
||||||
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
|
|
||||||
|
int aidLen = 0;
|
||||||
|
uint8_t aidBuf[3] = {0};
|
||||||
|
uint32_t aid = 0;
|
||||||
|
CLIGetHexWithReturn(ctx, 3, aidBuf, &aidLen);
|
||||||
|
|
||||||
|
if (aidLen != 3)
|
||||||
|
HFGAL_RET_ERR(PM3_EINVARG, "--aid must be 3 bytes");
|
||||||
|
reverseAid(aidBuf); // PM3 displays AIDs backwards
|
||||||
|
aid = DesfireAIDByteToUint(aidBuf);
|
||||||
|
|
||||||
|
// Check that the AID is in the expected range
|
||||||
|
if (memcmp(aidBuf, "\xF4\x81", 2) != 0 || aidBuf[2] < 0x20 || aidBuf[2] > 0x2B)
|
||||||
|
// TODO: this should probably be a warning, but key diversification will throw an error later even if we don't
|
||||||
|
HFGAL_RET_ERR(PM3_EINVARG, "Invalid Gallagher AID %06X, expected 2?81F4, where 0 <= ? <= 0xB", aid);
|
||||||
|
|
||||||
|
int sitekeyLen = 0;
|
||||||
|
uint8_t sitekey[16] = {0};
|
||||||
|
memcpy(sitekey, DEFAULT_SITE_KEY, ARRAYLEN(sitekey));
|
||||||
|
CLIGetHexWithReturn(ctx, 4, sitekey, &sitekeyLen);
|
||||||
|
if (sitekeyLen > 0 && sitekeyLen != 16)
|
||||||
|
HFGAL_RET_ERR(PM3_EINVARG, "--sitekey must be 16 bytes");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// Set up context
|
||||||
|
DropField();
|
||||||
|
DesfireContext_t dctx = {0};
|
||||||
|
DesfireClearContext(&dctx);
|
||||||
|
|
||||||
|
// Get card UID (for key diversification)
|
||||||
|
int res = DesfireGetCardUID(&dctx);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed retrieving card UID");
|
||||||
|
|
||||||
|
// Update Card Application Directory
|
||||||
|
res = removeFromGallagherCAD(&dctx, sitekey, aid, verbose);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed removing %06X from the Card Application Directory");
|
||||||
|
|
||||||
|
// Delete application
|
||||||
|
res = deleteGallagherApplication(&dctx, sitekey, aid, verbose);
|
||||||
|
HFGAL_RET_IF_ERR_WITH_MSG(res, "Failed deleting Gallagher application");
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "Done");
|
||||||
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf gallagher reader`") " to verify");
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdGallagherSim(const char *Cmd) {
|
static int CmdGallagherSim(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf gallagher sim",
|
CLIParserInit(&ctx, "hf gallagher sim",
|
||||||
|
@ -798,7 +957,8 @@ static int CmdHelp(const char *Cmd);
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
{"reader", CmdGallagherReader, IfPm3Iso14443, "attempt to read and extract tag data"},
|
{"reader", CmdGallagherReader, IfPm3Iso14443, "attempt to read and extract tag data"},
|
||||||
{"clone", CmdGallagherClone, IfPm3Iso14443, "clone GALLAGHER tag to a blank DESFire card"},
|
{"clone", CmdGallagherClone, IfPm3Iso14443, "add Gallagher credentials to a DESFire card"},
|
||||||
|
{"delete", CmdGallagherDelete, IfPm3Iso14443, "delete Gallagher application from a DESFire card"},
|
||||||
{"sim", CmdGallagherSim, IfPm3Iso14443, "simulate GALLAGHER tag"},
|
{"sim", CmdGallagherSim, IfPm3Iso14443, "simulate GALLAGHER tag"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue