mfp changes...

This commit is contained in:
iceman1001 2023-06-23 17:51:39 +02:00
commit 85d4e99ae9
2 changed files with 204 additions and 94 deletions

View file

@ -34,19 +34,12 @@
#include "protocols.h" #include "protocols.h"
#include "crypto/libpcrypto.h" #include "crypto/libpcrypto.h"
#include "cmdhfmf.h" // printblock, header #include "cmdhfmf.h" // printblock, header
#include "cmdtrace.h"
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const uint8_t mfp_default_key[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; static uint16_t mfp_card_adresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
typedef enum { #define MFP_KEY_FILE_SIZE 14 + (2 * 64 * (AES_KEY_LEN + 1))
MFP_UNKNOWN = 0,
DESFIRE_MF3ICD40,
DESFIRE_EV1,
DESFIRE_EV2,
DESFIRE_EV3,
DESFIRE_LIGHT,
PLUS_EV1,
} nxp_cardtype_t;
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -233,9 +226,10 @@ static int get_plus_signature(uint8_t *signature, int *signature_len) {
*signature_len = 0; *signature_len = 0;
retval = PM3_ESOFT; retval = PM3_ESOFT;
} }
mfpSetVerboseMode(false);
return retval; return retval;
} }
// GET VERSION // GET VERSION
static int plus_print_version(uint8_t *version) { static int plus_print_version(uint8_t *version) {
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(version + 14, 7)); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(version + 14, 7));
@ -261,12 +255,12 @@ static int plus_print_version(uint8_t *version) {
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false)); PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int get_plus_version(uint8_t *version, int *version_len) { static int get_plus_version(uint8_t *version, int *version_len) {
int resplen = 0, retval = PM3_SUCCESS; int resplen = 0, retval = PM3_SUCCESS;
mfpSetVerboseMode(false); mfpSetVerboseMode(false);
MFPGetVersion(true, false, version, *version_len, &resplen); MFPGetVersion(true, false, version, *version_len, &resplen);
mfpSetVerboseMode(false);
*version_len = resplen; *version_len = resplen;
if (resplen != 28) { if (resplen != 28) {
@ -484,16 +478,16 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keyLen) { if (!keyLen) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, 16);
keyLen = 16; keyLen = 16;
} }
if (keyNumLen != 2) { if (keyNumLen != 2) {
PrintAndLogEx(ERR, "Key number length must be 2 bytes instead of: %d", keyNumLen); PrintAndLogEx(ERR, "Key number length must be 2 bytes. Got %d", keyNumLen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keyLen != 16) { if (keyLen != 16) {
PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen); PrintAndLogEx(ERR, "Key length must be 16 bytes. Got %d", keyLen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -507,7 +501,7 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
} }
if (datalen != 3) { if (datalen != 3) {
PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen); PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -539,17 +533,18 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
bool verbose2 = arg_get_lit(ctx, 1) > 1; bool verbose2 = arg_get_lit(ctx, 1) > 1;
uint8_t key[256] = {0}; uint8_t key[256] = {0};
int keyLen = 0; int keylen = 0;
CLIGetHexWithReturn(ctx, 2, key, &keyLen); CLIGetHexWithReturn(ctx, 2, key, &keylen);
CLIParserFree(ctx); CLIParserFree(ctx);
if (keyLen && keyLen != 16) { if (keylen && keylen != 16) {
PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen); PrintAndLogEx(FAILED, "Key length must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (!keyLen) if (keylen == 0) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, sizeof(mfp_default_key));
}
uint8_t keyNum[2] = {0}; uint8_t keyNum[2] = {0};
uint8_t data[250] = {0}; uint8_t data[250] = {0};
@ -572,15 +567,15 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
} }
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
for (int i = 0; i < ARRAYLEN(CardAddresses); i++) { for (int i = 0; i < ARRAYLEN(mfp_card_adresses); i++) {
keyNum[0] = CardAddresses[i] >> 8; keyNum[0] = mfp_card_adresses[i] >> 8;
keyNum[1] = CardAddresses[i] & 0xff; keyNum[1] = mfp_card_adresses[i] & 0xff;
res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen); res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen);
if (!res && (datalen == 3) && data[0] == 0x09) { if (!res && (datalen == 3) && data[0] == 0x09) {
PrintAndLogEx(WARNING, "Skipped[%04x]...", CardAddresses[i]); PrintAndLogEx(WARNING, "Skipped[%04x]...", mfp_card_adresses[i]);
} else { } else {
if (res || (datalen != 3) || data[0] != 0x90) { if (res || (datalen != 3) || data[0] != 0x90) {
PrintAndLogEx(ERR, "Write error on address %04x", CardAddresses[i]); PrintAndLogEx(ERR, "Write error on address %04x", mfp_card_adresses[i]);
break; break;
} }
} }
@ -597,7 +592,9 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
static int CmdHFMFPCommitPerso(const char *Cmd) { static int CmdHFMFPCommitPerso(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp commitp", CLIParserInit(&ctx, "hf mfp commitp",
"Executes Commit Perso command. Can be used in SL0 mode only.\nOBS! This command will not be executed if CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.", "Executes Commit Perso command. Can be used in SL0 mode only.\n"
"OBS! This command will not be executed if \n"
"CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.",
"hf mfp commitp\n" "hf mfp commitp\n"
// "hf mfp commitp --sl 1" // "hf mfp commitp --sl 1"
); );
@ -625,7 +622,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
} }
if (datalen != 3) { if (datalen != 3) {
PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen); PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -633,7 +630,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0])); PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
return PM3_EINVARG; return PM3_EINVARG;
} }
PrintAndLogEx(INFO, "Switch level ( " _GREEN_("ok") " )"); PrintAndLogEx(INFO, "Switched security level ( " _GREEN_("ok") " )");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -645,7 +642,7 @@ static int CmdHFMFPAuth(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp auth", CLIParserInit(&ctx, "hf mfp auth",
"Executes AES authentication command for Mifare Plus card", "Executes AES authentication command for MIFARE Plus card",
"hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n" "hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
"hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data"); "hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data");
@ -664,12 +661,12 @@ static int CmdHFMFPAuth(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
if (keynlen != 2) { if (keynlen != 2) {
PrintAndLogEx(ERR, "ERROR: <key number> must be 2 bytes long instead of: %d", keynlen); PrintAndLogEx(ERR, "ERROR: <key number> must be 2 bytes. Got %d", keynlen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 16) { if (keylen != 16) {
PrintAndLogEx(ERR, "ERROR: <key> must be 16 bytes long instead of: %d", keylen); PrintAndLogEx(ERR, "ERROR: <key> must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -679,7 +676,7 @@ static int CmdHFMFPAuth(const char *Cmd) {
static int CmdHFMFPRdbl(const char *Cmd) { static int CmdHFMFPRdbl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp rdbl", CLIParserInit(&ctx, "hf mfp rdbl",
"Reads several blocks from Mifare Plus card", "Reads blocks from MIFARE Plus card",
"hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n" "hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
"hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF"); "hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF");
@ -710,23 +707,23 @@ static int CmdHFMFPRdbl(const char *Cmd) {
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, 16);
keylen = 16; keylen = 16;
} }
if (blockn > 255) { if (blockn > 255) {
PrintAndLogEx(ERR, "<block number> must be in range [0..255] got: %d", blockn); PrintAndLogEx(ERR, "<block number> must be in range [0..255]. got %d", blockn);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 16) { if (keylen != 16) {
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen); PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
// 3 blocks - wo iso14443-4 chaining // 3 blocks - wo iso14443-4 chaining
if (blocksCount > 3) { if (blocksCount > 3) {
PrintAndLogEx(ERR, "blocks count must be less than 3. got: %d", blocksCount); PrintAndLogEx(ERR, "blocks count must be less than 3. Got %d", blocksCount);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -763,7 +760,7 @@ static int CmdHFMFPRdbl(const char *Cmd) {
} }
if (datalen != 1 + blocksCount * 16 + 8 + 2) { if (datalen != 1 + blocksCount * 16 + 8 + 2) {
PrintAndLogEx(ERR, "Error return length:%d", datalen); PrintAndLogEx(ERR, "Error return length: %d", datalen);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -820,17 +817,17 @@ static int CmdHFMFPRdsc(const char *Cmd) {
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, 16);
keylen = 16; keylen = 16;
} }
if (sectorNum > 39) { if (sectorNum > 39) {
PrintAndLogEx(ERR, "<sector number> must be in range [0..39] got: %d", sectorNum); PrintAndLogEx(ERR, "<sector number> must be in range [0..39]. Got %d", sectorNum);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 16) { if (keylen != 16) {
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen); PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -894,7 +891,7 @@ static int CmdHFMFPRdsc(const char *Cmd) {
static int CmdHFMFPWrbl(const char *Cmd) { static int CmdHFMFPWrbl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp wrbl", CLIParserInit(&ctx, "hf mfp wrbl",
"Writes one block to Mifare Plus card", "Writes one block to MIFARE Plus card",
"hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data\n" "hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data\n"
"hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF" "hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF"
); );
@ -928,22 +925,22 @@ static int CmdHFMFPWrbl(const char *Cmd) {
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, 16);
keylen = 16; keylen = 16;
} }
if (blockNum > 255) { if (blockNum > 255) {
PrintAndLogEx(ERR, "<block number> must be in range [0..255] got: %d", blockNum); PrintAndLogEx(ERR, "<block number> must be in range [0..255]. Got %d", blockNum);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 16) { if (keylen != 16) {
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen); PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (datainlen != 16) { if (datainlen != 16) {
PrintAndLogEx(ERR, "<data> must be 16 bytes long. got: %d", datainlen); PrintAndLogEx(ERR, "<data> must be 16 bytes. Got %d", datainlen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -997,11 +994,8 @@ static int CmdHFMFPWrbl(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
#define AES_KEY_LEN 16
#define MAX_KEYS_LIST_LEN 1024
static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB,
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1],
bool verbose) { bool verbose) {
int res; int res;
bool selectCard = true; bool selectCard = true;
@ -1088,7 +1082,7 @@ static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startK
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) { static void Fill2bPattern(uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) {
for (uint32_t pt = *startPattern; pt < 0x10000; pt++) { for (uint32_t pt = *startPattern; pt < 0x10000; pt++) {
keyList[*keyListLen][0] = (pt >> 8) & 0xff; keyList[*keyListLen][0] = (pt >> 8) & 0xff;
keyList[*keyListLen][1] = pt & 0xff; keyList[*keyListLen][1] = pt & 0xff;
@ -1097,7 +1091,7 @@ static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint3
memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8); memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8);
(*keyListLen)++; (*keyListLen)++;
*startPattern = pt; *startPattern = pt;
if (*keyListLen == MAX_KEYS_LIST_LEN) if (*keyListLen == MAX_AES_KEYS_LIST_LEN)
break; break;
} }
(*startPattern)++; (*startPattern)++;
@ -1111,7 +1105,7 @@ static int CmdHFMFPChk(const char *Cmd) {
"hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" "hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n"
"hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n" "hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n"
"hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n" "hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n"
"hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n" "hf mfp chk --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file\n"
"hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00"); "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00");
void *argtable[] = { void *argtable[] = {
@ -1125,7 +1119,7 @@ static int CmdHFMFPChk(const char *Cmd) {
arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
arg_str0(NULL, "startp2b", "<pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), arg_str0(NULL, "startp2b", "<pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
arg_str0("j", "json", "<fn>", "Json filename to save keys"), arg_lit0(NULL, "dump", "Dump found keys to JSON file"),
arg_lit0("v", "verbose", "Verbose mode"), arg_lit0("v", "verbose", "Verbose mode"),
arg_param_end arg_param_end
}; };
@ -1136,7 +1130,7 @@ static int CmdHFMFPChk(const char *Cmd) {
uint8_t startSector = arg_get_int_def(ctx, 3, 0); uint8_t startSector = arg_get_int_def(ctx, 3, 0);
uint8_t endSector = arg_get_int_def(ctx, 4, 0); uint8_t endSector = arg_get_int_def(ctx, 4, 0);
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
uint32_t keyListLen = 0; uint32_t keyListLen = 0;
uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}};
@ -1148,7 +1142,7 @@ static int CmdHFMFPChk(const char *Cmd) {
memcpy(&keyList[keyListLen], vkey, 16); memcpy(&keyList[keyListLen], vkey, 16);
keyListLen++; keyListLen++;
} else { } else {
PrintAndLogEx(ERR, "Specified key must have 16 bytes length."); PrintAndLogEx(ERR, "Specified key must have 16 bytes. Got %d", vkeylen);
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -1185,7 +1179,7 @@ static int CmdHFMFPChk(const char *Cmd) {
if (vpatternlen <= 2) { if (vpatternlen <= 2) {
startPattern = (vpattern[0] << 8) + vpattern[1]; startPattern = (vpattern[0] << 8) + vpattern[1];
} else { } else {
PrintAndLogEx(ERR, "Pattern must be 2-byte length."); PrintAndLogEx(ERR, "Pattern must be 2-bytes. Got %d", vpatternlen);
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -1193,17 +1187,8 @@ static int CmdHFMFPChk(const char *Cmd) {
PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search.");
} }
uint8_t jsonname[250] = {0}; bool create_dumpfile = arg_get_lit(ctx, 10);
int jsonnamelen = 0;
if (CLIParamStrToBuf(arg_get_str(ctx, 10), jsonname, sizeof(jsonname), &jsonnamelen)) {
PrintAndLogEx(ERR, "Invalid json name.");
CLIParserFree(ctx);
return PM3_EINVARG;
}
jsonname[jsonnamelen] = 0;
bool verbose = arg_get_lit(ctx, 11); bool verbose = arg_get_lit(ctx, 11);
CLIParserFree(ctx); CLIParserFree(ctx);
uint8_t startKeyAB = 0; uint8_t startKeyAB = 0;
@ -1227,8 +1212,9 @@ static int CmdHFMFPChk(const char *Cmd) {
} }
// 2-byte pattern search mode // 2-byte pattern search mode
if (pattern2b) if (pattern2b) {
Fill2bPattern(keyList, &keyListLen, &startPattern); Fill2bPattern(keyList, &keyListLen, &startPattern);
}
int res = PM3_SUCCESS; int res = PM3_SUCCESS;
@ -1291,19 +1277,30 @@ static int CmdHFMFPChk(const char *Cmd) {
keyListLen = keycnt; keyListLen = keycnt;
} }
PrintAndLogEx(INFO, "ICE pos... %zu - %zu", old_pos, endFilePosition);
continue; continue;
} }
break; break;
} }
if (verbose == false)
if (verbose == false) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
}
// print result // print result
char strA[46 + 1] = {0}; char strA[46 + 1] = {0};
char strB[46 + 1] = {0}; char strB[46 + 1] = {0};
uint8_t ndef_key[] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
bool has_ndef_key = false;
bool printedHeader = false; bool printedHeader = false;
for (uint8_t s = startSector; s <= endSector; s++) { for (uint8_t s = startSector; s <= endSector; s++) {
if ((memcmp(&foundKeys[0][s][1], ndef_key, AES_KEY_LEN) == 0) ||
(memcmp(&foundKeys[1][s][1], ndef_key, AES_KEY_LEN) == 0)) {
has_ndef_key = true;
}
if (printedHeader == false) { if (printedHeader == false) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------"); PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------");
@ -1333,7 +1330,13 @@ static int CmdHFMFPChk(const char *Cmd) {
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n"); PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n");
// save keys to json // save keys to json
if ((jsonnamelen > 0) && printedHeader) { if (create_dumpfile && printedHeader) {
size_t keys_len = (2 * 64 * (AES_KEY_LEN + 1));
uint8_t data[10 + 1 + 2 + 1 + 256 + keys_len];
memset(data, 0, sizeof(data));
// Mifare Plus info // Mifare Plus info
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
@ -1344,8 +1347,6 @@ static int CmdHFMFPChk(const char *Cmd) {
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
uint8_t data[10 + 1 + 2 + 1 + 256 + 2 * 64 * (AES_KEY_LEN + 1)] = {0};
uint8_t atslen = 0; uint8_t atslen = 0;
if (select_status == 1 || select_status == 2) { if (select_status == 1 || select_status == 2) {
memcpy(data, card.uid, card.uidlen); memcpy(data, card.uid, card.uidlen);
@ -1357,9 +1358,16 @@ static int CmdHFMFPChk(const char *Cmd) {
memcpy(&data[14], card.ats, atslen); memcpy(&data[14], card.ats, atslen);
} }
char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-key")) + card.uidlen * 2 + 1, sizeof(uint8_t));
strcpy(fptr, "hf-mfp-");
FillFileNameByUID(fptr, card.uid, "-key", card.uidlen);
// length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1] // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1]
memcpy(&data[14 + atslen], foundKeys, 2 * 64 * (AES_KEY_LEN + 1)); memcpy(&data[14 + atslen], foundKeys, keys_len);
saveFileJSON((char *)jsonname, jsfMfPlusKeys, data, 64, NULL); // 64 here is for how many "rows" there is in the data array. A bit confusing
saveFileJSON(fptr, jsfMfPlusKeys, data, 64, NULL);
free(fptr);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
@ -1369,7 +1377,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp mad", CLIParserInit(&ctx, "hf mfp mad",
"Checks and prints Mifare Application Directory (MAD)", "Checks and prints MIFARE Application Directory (MAD)",
"hf mfp mad\n" "hf mfp mad\n"
"hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid"); "hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid");
@ -1411,9 +1419,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, ""); MADPrintHeader();
PrintAndLogEx(INFO, "--- " _CYAN_("Mifare App Directory Information") " ----------------");
PrintAndLogEx(INFO, "-----------------------------------------------------");
if (verbose) { if (verbose) {
PrintAndLogEx(SUCCESS, "Raw:"); PrintAndLogEx(SUCCESS, "Raw:");
@ -1427,7 +1433,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
if (haveMAD2) { if (haveMAD2) {
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) { if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys"); PrintAndLogEx(ERR, "error, read sector " _YELLOW_("0x10") ". Card doesn't have MAD or doesn't have MAD on default keys");
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -1505,6 +1511,36 @@ static int CmdHFMFPMAD(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHFMFPNDEFFormat(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp ndefformat",
"format MIFARE Plus Tag as a NFC tag with Data Exchange Format (NDEF)\n"
"If no <name> given, UID will be used as filename. \n"
"It will try default keys and MAD keys to detect if tag is already formatted in order to write.\n"
"\n"
"If not, it will try finding a key file based on your UID. ie, if you ran autopwn before",
"hf mfp ndefformat\n"
"hf mfp ndefformat --keys hf-mf-01020304-key.bin --> with keys from specified file\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0("k", "keys", "<fn>", "filename of keys"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int keyfnlen = 0;
char keyFilename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)keyFilename, FILE_PATH_SIZE, &keyfnlen);
CLIParserFree(ctx);
PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
int CmdHFMFPNDEFRead(const char *Cmd) { int CmdHFMFPNDEFRead(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
@ -1641,19 +1677,73 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHFMFPNDEFWrite(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp ndefwrite",
"Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n",
"hf mfp ndefwrite -d 0300FE -> write empty record to tag\n"
"hf mfp ndefwrite -f myfilename\n"
"hf mfp ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0("d", NULL, "<hex>", "raw NDEF hex bytes"),
arg_str0("f", "file", "<fn>", "write raw NDEF file to tag"),
arg_lit0("p", NULL, "fix NDEF record headers / terminator block if missing"),
arg_lit0("v", "verbose", "verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t raw[4096] = {0};
int rawlen;
CLIGetHexWithReturn(ctx, 1, raw, &rawlen);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool fix_msg = arg_get_lit(ctx, 3);
bool verbose = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
if (fix_msg) {
PrintAndLogEx(NORMAL, "called with fix NDEF message param");
}
if (verbose) {
PrintAndLogEx(NORMAL, "");
}
PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int CmdHFMFPList(const char *Cmd) {
return CmdTraceListAlias(Cmd, "hf mf", "mf");
}
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about Mifare Plus tag"}, {"list", CmdHFMFPList, AlwaysAvailable, "List MIFARE Plus history"},
{"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"}, {"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("operations") " ---------------------"},
{"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"},
{"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Move card to SL1 or SL3 mode"},
{"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"}, {"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"},
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"},
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"},
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"},
{"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"}, {"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"},
{"dump", CmdHFMFPDump, IfPm3Iso14443a, "Dump MIFARE Classic tag to binary file"},
{"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about MIFARE Plus tag"},
{"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"}, {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"},
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks from card"},
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors from card"},
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write block to card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------- " _CYAN_("personalization") " -------------------"},
{"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Move card to SL1 or SL3 mode"},
{"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"},
{"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"},
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("ndef") " ------------------------"},
{"ndefformat", CmdHFMFPNDEFFormat, IfPm3Iso14443a, "Format MIFARE Plus Tag as NFC Tag"},
{"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"}, {"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
{"ndefwrite", CmdHFMFPNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View file

@ -24,6 +24,26 @@
#define AES_KEY_LEN 16 #define AES_KEY_LEN 16
#define MAX_AES_KEYS_LIST_LEN 1024 #define MAX_AES_KEYS_LIST_LEN 1024
typedef enum {
MFP_UNKNOWN = 0,
DESFIRE_MF3ICD40,
DESFIRE_EV1,
DESFIRE_EV2,
DESFIRE_EV3,
DESFIRE_LIGHT,
PLUS_EV1,
} nxp_cardtype_t;
typedef struct mfp_key_item {
uint8_t a[16];
uint8_t b[16];
} mfp_key_item_t;
typedef struct mfp_keys {
uint8_t success;
mfp_key_item_t *keys;
} mfp_keys_t;
int CmdHFMFP(const char *Cmd); int CmdHFMFP(const char *Cmd);
int CmdHFMFPNDEFRead(const char *Cmd); int CmdHFMFPNDEFRead(const char *Cmd);