mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
hf mfu eload/restore/sim/cauth - now uses cliparser
This commit is contained in:
parent
e6d71fafb1
commit
afc4d78d68
1 changed files with 173 additions and 198 deletions
|
@ -42,73 +42,6 @@
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
static int usage_hf_mfu_restore(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Restore dumpfile onto card.");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf mfu restore [h] [l] [s] k <key> n <filename w .bin> ");
|
|
||||||
PrintAndLogEx(NORMAL, " Options :");
|
|
||||||
PrintAndLogEx(NORMAL, " k <key> : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]");
|
|
||||||
PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness");
|
|
||||||
PrintAndLogEx(NORMAL, " s : (optional) enable special write UID " _BLUE_("-MAGIC TAG ONLY-"));
|
|
||||||
PrintAndLogEx(NORMAL, " e : (optional) enable special write version/signature " _BLUE_("-MAGIC NTAG 21* ONLY-"));
|
|
||||||
PrintAndLogEx(NORMAL, " r : (optional) use the password found in dumpfile to configure tag. requires " _YELLOW_("'e'") " parameter to work");
|
|
||||||
PrintAndLogEx(NORMAL, " f <fn> : " _YELLOW_("filename w .bin") " to restore");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore s f myfile"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore k AABBCCDD s f myfile"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore k AABBCCDD s e r f myfile"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usage_hf_mfu_eload(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "It loads emul dump from the file " _YELLOW_("`filename.eml`"));
|
|
||||||
PrintAndLogEx(NORMAL, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to the eml");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf mfu eload u <file name w/o `.eml`> [numblocks]");
|
|
||||||
PrintAndLogEx(NORMAL, " Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h : this help");
|
|
||||||
PrintAndLogEx(NORMAL, " u : UL (required)");
|
|
||||||
PrintAndLogEx(NORMAL, " [filename] : without `.eml` (required)");
|
|
||||||
PrintAndLogEx(NORMAL, " numblocks : number of blocks to load from eml file (optional)");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu eload u filename"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu eload u filename 57"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usage_hf_mfu_sim(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "\nEmulating Ultralight tag from emulator memory\n");
|
|
||||||
PrintAndLogEx(NORMAL, "\nBe sure to load the emulator memory first!\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf mfu sim t 7 u <uid> [n <num>]");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h : this help");
|
|
||||||
PrintAndLogEx(NORMAL, " t 7 : 7 = NTAG or Ultralight sim (required)");
|
|
||||||
PrintAndLogEx(NORMAL, " n <num> : exit simulation after <num> blocks have been read by reader. 0 = infinite (optional)");
|
|
||||||
PrintAndLogEx(NORMAL, " u <uid> : 4 or 7 byte UID (optional)");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7 u 1122344556677"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7 u 1122344556677 n 5"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usage_hf_mfu_ucauth(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Tests 3DES password on Mifare Ultralight-C tag.");
|
|
||||||
PrintAndLogEx(NORMAL, "If password is not specified, a set of known defaults will be tested.");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf mfu cauth [k] <password (32 hex symbols)>");
|
|
||||||
PrintAndLogEx(NORMAL, " k - keep field on (only if a password is provided too)");
|
|
||||||
PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth 000102030405060708090a0b0c0d0e0f"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usage_hf_mfu_ucsetpwd(void) {
|
static int usage_hf_mfu_ucsetpwd(void) {
|
||||||
PrintAndLogEx(NORMAL, "Set 3DES password on Mifare Ultralight-C tag.");
|
PrintAndLogEx(NORMAL, "Set 3DES password on Mifare Ultralight-C tag.");
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd <password (32 hex symbols)>");
|
PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd <password (32 hex symbols)>");
|
||||||
|
@ -349,10 +282,10 @@ static int try_default_3des_keys(uint8_t **correct_key) {
|
||||||
uint8_t *key = default_3des_keys[i];
|
uint8_t *key = default_3des_keys[i];
|
||||||
if (ulc_authentication(key, true)) {
|
if (ulc_authentication(key, true)) {
|
||||||
*correct_key = key;
|
*correct_key = key;
|
||||||
return 1;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) {
|
static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) {
|
||||||
|
@ -615,7 +548,7 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) {
|
||||||
memset(typestr, 0x00, sizeof(typestr));
|
memset(typestr, 0x00, sizeof(typestr));
|
||||||
|
|
||||||
if (tagtype & UL)
|
if (tagtype & UL)
|
||||||
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1)s"), spaces, "");
|
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1)"), spaces, "");
|
||||||
else if (tagtype & UL_C)
|
else if (tagtype & UL_C)
|
||||||
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC)"), spaces, "");
|
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC)"), spaces, "");
|
||||||
else if (tagtype & UL_NANO_40)
|
else if (tagtype & UL_NANO_40)
|
||||||
|
@ -676,7 +609,7 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) {
|
||||||
snprintf(typestr + strlen(typestr), 4, " (");
|
snprintf(typestr + strlen(typestr), 4, " (");
|
||||||
|
|
||||||
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MAGIC) ? _GREEN_("magic") : "");
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MAGIC) ? _GREEN_("magic") : "");
|
||||||
tagtype ^= MAGIC;
|
tagtype &= ~(MAGIC);
|
||||||
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1A) ? _GREEN_("Gen 1a") : "");
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1A) ? _GREEN_("Gen 1a") : "");
|
||||||
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1B) ? _GREEN_("Gen 1b") : "");
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1B) ? _GREEN_("Gen 1b") : "");
|
||||||
|
|
||||||
|
@ -688,11 +621,11 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ulc_print_3deskey(uint8_t *data) {
|
static int ulc_print_3deskey(uint8_t *data) {
|
||||||
PrintAndLogEx(NORMAL, " deskey1 [44/0x2C]: %s [%s]", sprint_hex(data, 4), sprint_ascii(data, 4));
|
PrintAndLogEx(INFO, " deskey1 [44/0x2C]: %s [%s]", sprint_hex(data, 4), sprint_ascii(data, 4));
|
||||||
PrintAndLogEx(NORMAL, " deskey1 [45/0x2D]: %s [%s]", sprint_hex(data + 4, 4), sprint_ascii(data + 4, 4));
|
PrintAndLogEx(INFO, " deskey1 [45/0x2D]: %s [%s]", sprint_hex(data + 4, 4), sprint_ascii(data + 4, 4));
|
||||||
PrintAndLogEx(NORMAL, " deskey2 [46/0x2E]: %s [%s]", sprint_hex(data + 8, 4), sprint_ascii(data + 8, 4));
|
PrintAndLogEx(INFO, " deskey2 [46/0x2E]: %s [%s]", sprint_hex(data + 8, 4), sprint_ascii(data + 8, 4));
|
||||||
PrintAndLogEx(NORMAL, " deskey2 [47/0x2F]: %s [%s]", sprint_hex(data + 12, 4), sprint_ascii(data + 12, 4));
|
PrintAndLogEx(INFO, " deskey2 [47/0x2F]: %s [%s]", sprint_hex(data + 12, 4), sprint_ascii(data + 12, 4));
|
||||||
PrintAndLogEx(NORMAL, "\n 3des key: %s", sprint_hex(SwapEndian64(data, 16, 8), 16));
|
PrintAndLogEx(INFO, "3des key: " _GREEN_("%s"), sprint_hex_inrow(SwapEndian64(data, 16, 8), 16));
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,7 +772,7 @@ static int ulev1_print_counters(void) {
|
||||||
len = ulev1_readCounter(i, counter, sizeof(counter));
|
len = ulev1_readCounter(i, counter, sizeof(counter));
|
||||||
if (len == 3) {
|
if (len == 3) {
|
||||||
PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3));
|
PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3));
|
||||||
PrintAndLogEx(SUCCESS, " - %02X tearing (%s)"
|
PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )"
|
||||||
, tear[0]
|
, tear[0]
|
||||||
, (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
|
, (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
|
||||||
);
|
);
|
||||||
|
@ -930,7 +863,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig
|
||||||
if (is_valid == false || i == ARRAYLEN(nxp_mfu_public_keys)) {
|
if (is_valid == false || i == ARRAYLEN(nxp_mfu_public_keys)) {
|
||||||
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
|
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
|
||||||
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
|
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
|
||||||
PrintAndLogEx(SUCCESS, " Signature verification (" _RED_("fail") ")");
|
PrintAndLogEx(SUCCESS, " Signature verification ( " _RED_("fail") " )");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -938,7 +871,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig
|
||||||
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value);
|
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value);
|
||||||
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
|
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
|
||||||
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
|
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
|
||||||
PrintAndLogEx(SUCCESS, " Signature verification (" _GREEN_("successful") ")");
|
PrintAndLogEx(SUCCESS, " Signature verification ( " _GREEN_("successful") " )");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -968,7 +901,7 @@ static int ntag_print_counter(void) {
|
||||||
len = ulev1_readCounter(0x02, counter, sizeof(counter));
|
len = ulev1_readCounter(0x02, counter, sizeof(counter));
|
||||||
(void)len;
|
(void)len;
|
||||||
PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3));
|
PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3));
|
||||||
PrintAndLogEx(SUCCESS, " - %02X tearing (%s)"
|
PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )"
|
||||||
, tear[0]
|
, tear[0]
|
||||||
, (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
|
, (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail")
|
||||||
);
|
);
|
||||||
|
@ -1038,6 +971,19 @@ static int ul_magic_test(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *GenerateFilename(const char *prefix, const char *suffix) {
|
||||||
|
iso14a_card_select_t card;
|
||||||
|
if (ul_select(&card) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "No tag found.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fptr = calloc(sizeof(char) * (strlen(prefix) + strlen(suffix)) + sizeof(card.uid) * 2 + 1, sizeof(uint8_t));
|
||||||
|
strcpy(fptr, prefix);
|
||||||
|
FillFileNameByUID(fptr, card.uid, suffix, card.uidlen);
|
||||||
|
return fptr;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t GetHF14AMfU_Type(void) {
|
uint32_t GetHF14AMfU_Type(void) {
|
||||||
|
|
||||||
TagTypeUL_t tagtype = UNKNOWN;
|
TagTypeUL_t tagtype = UNKNOWN;
|
||||||
|
@ -1319,7 +1265,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
|
// also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
|
||||||
if (try_default_3des_keys(&key)) {
|
if (try_default_3des_keys(&key) == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(SUCCESS, "Found default 3des key: ");
|
PrintAndLogEx(SUCCESS, "Found default 3des key: ");
|
||||||
uint8_t keySwap[16];
|
uint8_t keySwap[16];
|
||||||
memcpy(keySwap, SwapEndian64(key, 16, 8), 16);
|
memcpy(keySwap, SwapEndian64(key, 16, 8), 16);
|
||||||
|
@ -1425,7 +1371,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
num_to_bytes(ul_ev1_pwdgenA(card.uid), 4, key);
|
num_to_bytes(ul_ev1_pwdgenA(card.uid), 4, key);
|
||||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||||
if (len > -1) {
|
if (len > -1) {
|
||||||
PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
PrintAndLogEx(SUCCESS, "Found default password " _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1437,7 +1383,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
num_to_bytes(ul_ev1_pwdgenB(card.uid), 4, key);
|
num_to_bytes(ul_ev1_pwdgenB(card.uid), 4, key);
|
||||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||||
if (len > -1) {
|
if (len > -1) {
|
||||||
PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
PrintAndLogEx(SUCCESS, "Found default password " _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1449,7 +1395,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
num_to_bytes(ul_ev1_pwdgenC(card.uid), 4, key);
|
num_to_bytes(ul_ev1_pwdgenC(card.uid), 4, key);
|
||||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||||
if (len > -1) {
|
if (len > -1) {
|
||||||
PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
PrintAndLogEx(SUCCESS, "Found default password " _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1461,7 +1407,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
num_to_bytes(ul_ev1_pwdgenD(card.uid), 4, key);
|
num_to_bytes(ul_ev1_pwdgenD(card.uid), 4, key);
|
||||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||||
if (len > -1) {
|
if (len > -1) {
|
||||||
PrintAndLogEx(SUCCESS, "Found a default password:" _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
PrintAndLogEx(SUCCESS, "Found default password" _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1473,7 +1419,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
key = default_pwd_pack[i];
|
key = default_pwd_pack[i];
|
||||||
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
len = ulev1_requestAuthentication(key, pack, sizeof(pack));
|
||||||
if (len > -1) {
|
if (len > -1) {
|
||||||
PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
PrintAndLogEx(SUCCESS, "Found default password " _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
|
||||||
|
@ -1729,7 +1675,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "-----------------------------");
|
PrintAndLogEx(INFO, "-----------------------------");
|
||||||
PrintAndLogEx(INFO, "%02d/0x%02X | %s| %s\n", blockno, blockno, sprint_hex(d, 4), sprint_ascii(d, 4));
|
PrintAndLogEx(INFO, "%02d/0x%02X | %s| %s\n", blockno, blockno, sprint_hex(d, 4), sprint_ascii(d, 4));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Failed reading block: (%02x)", isOK);
|
PrintAndLogEx(WARNING, "Failed reading block: ( %02x )", isOK);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Command execute time-out");
|
PrintAndLogEx(WARNING, "Command execute time-out");
|
||||||
|
@ -2154,82 +2100,58 @@ static void wait4response(uint8_t b) {
|
||||||
// Restore dump file onto tag
|
// Restore dump file onto tag
|
||||||
//
|
//
|
||||||
static int CmdHF14AMfURestore(const char *Cmd) {
|
static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf mfu restore",
|
||||||
|
"Restore dumpfile onto card.",
|
||||||
|
"hf mfu restore -f myfile -s -> user specified filename and special write\n"
|
||||||
|
"hf mfu restore -f myfile -k AABBCCDD -s -> user specified filename, special write and use key\n"
|
||||||
|
"hf mfu restore -f myfile -k AABBCCDD -ser -> user specified filename, special write, use key, ..."
|
||||||
|
);
|
||||||
|
|
||||||
char tempStr[50] = {0};
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1("f", "file", "<fn>", "specify a filename to restore"),
|
||||||
|
arg_str0("k", "key", "<hex>", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
|
||||||
|
arg_lit0("l", NULL, "swap entered key's endianness"),
|
||||||
|
arg_lit0("s", NULL, "enable special write UID -MAGIC TAG ONLY-"),
|
||||||
|
arg_lit0("e", NULL, "enable special write version/signature -MAGIC NTAG 21* ONLY-"),
|
||||||
|
arg_lit0("r", NULL, "use the password found in dumpfile to configure tag. requires " _YELLOW_("'-e'") " parameter to work"),
|
||||||
|
arg_lit0("v", "verbose", "verbose"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
uint8_t authkey[16] = {0};
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
int ak_len = 0;
|
||||||
|
uint8_t authkey[16] = {0x00};
|
||||||
uint8_t *p_authkey = authkey;
|
uint8_t *p_authkey = authkey;
|
||||||
uint8_t cmdp = 0, keylen = 0;
|
CLIGetHexWithReturn(ctx, 2, authkey, &ak_len);
|
||||||
|
|
||||||
|
bool swap_endian = arg_get_lit(ctx, 3);
|
||||||
|
bool write_special = arg_get_lit(ctx, 4);
|
||||||
|
bool write_extra = arg_get_lit(ctx, 5);
|
||||||
|
bool read_key = arg_get_lit(ctx, 6);
|
||||||
|
bool verbose = arg_get_lit(ctx, 7);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
bool hasKey = false;
|
bool hasKey = false;
|
||||||
bool swapEndian = false;
|
|
||||||
bool errors = false;
|
|
||||||
bool write_special = false;
|
|
||||||
bool write_extra = false;
|
|
||||||
bool read_key = false;
|
|
||||||
bool verbose = false;
|
|
||||||
size_t filelen = 0;
|
|
||||||
|
|
||||||
memset(authkey, 0x00, sizeof(authkey));
|
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
|
||||||
case 'h':
|
|
||||||
return usage_hf_mfu_restore();
|
|
||||||
case 'k':
|
|
||||||
keylen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr));
|
|
||||||
if (keylen == 32 || keylen == 8) { //ul-c or ev1/ntag key length
|
|
||||||
errors = param_gethex(tempStr, 0, authkey, keylen);
|
|
||||||
keylen /= 2;
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n");
|
|
||||||
errors = true;
|
|
||||||
}
|
|
||||||
cmdp += 2;
|
|
||||||
hasKey = true;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
swapEndian = true;
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
filelen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
|
||||||
|
|
||||||
if (filelen > FILE_PATH_SIZE - 5)
|
|
||||||
filelen = FILE_PATH_SIZE - 5;
|
|
||||||
|
|
||||||
if (filelen < 1)
|
|
||||||
sprintf(filename, "dumpdata.bin");
|
|
||||||
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
cmdp++;
|
|
||||||
write_special = true;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
cmdp++;
|
|
||||||
write_extra = true;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
cmdp++;
|
|
||||||
read_key = true;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
cmdp++;
|
|
||||||
verbose = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Validations
|
|
||||||
if (errors || cmdp == 0) return usage_hf_mfu_restore();
|
|
||||||
|
|
||||||
uint8_t *dump = NULL;
|
uint8_t *dump = NULL;
|
||||||
size_t bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
|
|
||||||
|
if (fnlen == 0) {
|
||||||
|
char *fptr = GenerateFilename("hf-mfu-", "-dump.bin");
|
||||||
|
if (fptr != NULL) {
|
||||||
|
strcpy(filename, fptr);
|
||||||
|
} else {
|
||||||
|
snprintf(filename, sizeof(filename), "dumpdata.bin");
|
||||||
|
}
|
||||||
|
free(fptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (loadFile_safe(filename, "", (void **)&dump, &bytes_read) != PM3_SUCCESS) {
|
if (loadFile_safe(filename, "", (void **)&dump, &bytes_read) != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), filename);
|
PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), filename);
|
||||||
return PM3_EIO;
|
return PM3_EIO;
|
||||||
|
@ -2263,19 +2185,19 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
printMFUdumpEx(mem, pages, 0);
|
printMFUdumpEx(mem, pages, 0);
|
||||||
|
|
||||||
// Swap endianness
|
// Swap endianness
|
||||||
if (swapEndian && hasKey) {
|
if (swap_endian && hasKey) {
|
||||||
if (keylen == 16)
|
if (ak_len == 16)
|
||||||
p_authkey = SwapEndian64(authkey, keylen, 8);
|
p_authkey = SwapEndian64(authkey, ak_len, 8);
|
||||||
else
|
else
|
||||||
p_authkey = SwapEndian64(authkey, keylen, 4);
|
p_authkey = SwapEndian64(authkey, ak_len, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[20] = {0};
|
uint8_t data[20] = {0};
|
||||||
uint8_t keytype = 0;
|
uint8_t keytype = 0;
|
||||||
// set key - only once
|
// set key - only once
|
||||||
if (hasKey) {
|
if (hasKey) {
|
||||||
keytype = (keylen == 16) ? 1 : 2;
|
keytype = (ak_len == 16) ? 1 : 2;
|
||||||
memcpy(data + 4, p_authkey, keylen);
|
memcpy(data + 4, p_authkey, ak_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write version, signature, pack
|
// write version, signature, pack
|
||||||
|
@ -2379,16 +2301,54 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
// Load emulator with dump file
|
// Load emulator with dump file
|
||||||
//
|
//
|
||||||
static int CmdHF14AMfUeLoad(const char *Cmd) {
|
static int CmdHF14AMfUeLoad(const char *Cmd) {
|
||||||
char c = tolower(param_getchar(Cmd, 0));
|
|
||||||
if (c == 'h' || c == 0x00) return usage_hf_mfu_eload();
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf mfu eload",
|
||||||
|
"It loads emul dump from the file `filename.eml`",
|
||||||
|
"hf mfu eload -u -f myfile\n"
|
||||||
|
"hf mfu eload -u -f myfile -q 57 -> load 57 blocks from myfile"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1("f", "file", "<fn>", "specify a filename w/o `.eml` to load"),
|
||||||
|
arg_lit1("u", NULL, "Ultralight Family type"),
|
||||||
|
arg_int0("q", "qty", "<dec>", "number of blocks to load from eml file"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
PrintAndLogEx(HINT, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to .eml");
|
||||||
return CmdHF14AMfELoad(Cmd);
|
return CmdHF14AMfELoad(Cmd);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Simulate tag
|
// Simulate tag
|
||||||
//
|
//
|
||||||
static int CmdHF14AMfUSim(const char *Cmd) {
|
static int CmdHF14AMfUSim(const char *Cmd) {
|
||||||
char c = tolower(param_getchar(Cmd, 0));
|
CLIParserContext *ctx;
|
||||||
if (c == 'h' || c == 0x00) return usage_hf_mfu_sim();
|
CLIParserInit(&ctx, "hf mfu sim",
|
||||||
|
"Simulate MIFARE Ultralight family type based upon\n"
|
||||||
|
"ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"
|
||||||
|
"from emulator memory. See `hf mfu eload` first",
|
||||||
|
"hf mfu sim -t 2 --uid 1122344556677 -> MIFARE Ultralight\n"
|
||||||
|
"hf mfu sim -t 7 --uid 1122344556677 -n 5 -> AMIIBO (NTAG 215), pack 0x8080"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_int1("t", "type", "<1-10> ", "Simulation type to use"),
|
||||||
|
arg_str0("u", "uid", "<hex>", "4, 7 or 10 byte UID"),
|
||||||
|
arg_int0("n", "num", "<dec>", "Exit simulation after <numreads> blocks have been read by reader. 0 = infinite"),
|
||||||
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
CLIParserFree(ctx);
|
||||||
return CmdHF14ASim(Cmd);
|
return CmdHF14ASim(Cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2396,43 +2356,58 @@ static int CmdHF14AMfUSim(const char *Cmd) {
|
||||||
// Ultralight C Methods
|
// Ultralight C Methods
|
||||||
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
||||||
|
|
||||||
//
|
|
||||||
// Ultralight C Authentication
|
// Ultralight C Authentication
|
||||||
//
|
//
|
||||||
|
|
||||||
static int CmdHF14AMfUCAuth(const char *Cmd) {
|
static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||||
uint8_t cmdp = 0;
|
CLIParserContext *ctx;
|
||||||
char c = tolower(param_getchar(Cmd, 0));
|
CLIParserInit(&ctx, "hf mfu cauth",
|
||||||
if (c == 'h') {
|
"Tests 3DES password on Mifare Ultralight-C tag.\n"
|
||||||
return usage_hf_mfu_ucauth();
|
"If password is not specified, a set of known defaults will be tested.",
|
||||||
}
|
"hf mfu cauth\n"
|
||||||
bool keep_field_on = false;
|
"hf mfu cauth --key 000102030405060708090a0b0c0d0e0f"
|
||||||
if (c == 'k') {
|
);
|
||||||
keep_field_on = true;
|
|
||||||
cmdp++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t key_buf[16];
|
void *argtable[] = {
|
||||||
uint8_t *key;
|
arg_param_begin,
|
||||||
int succeeded;
|
arg_str0("k", "key", "<hex>", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
|
||||||
|
arg_lit0("l", NULL, "swap entered key's endianness"),
|
||||||
|
arg_lit0("k", NULL, "keep field on (only if a password is provided too)"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
// If no hex key is specified, try all known ones
|
int ak_len = 0;
|
||||||
if (strlen(Cmd + cmdp) == 0) {
|
uint8_t authenticationkey[16] = {0x00};
|
||||||
succeeded = try_default_3des_keys(&key);
|
uint8_t *authKeyPtr = authenticationkey;
|
||||||
// Else try user-supplied
|
CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len);
|
||||||
} else {
|
bool swap_endian = arg_get_lit(ctx, 2);
|
||||||
if (param_gethex(Cmd, cmdp, key_buf, 32)) {
|
bool keep_field_on = arg_get_lit(ctx, 3);
|
||||||
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (ak_len != 16 && ak_len != 0) {
|
||||||
|
PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
succeeded = ulc_authentication(key_buf, ! keep_field_on);
|
|
||||||
key = key_buf;
|
// Swap endianness
|
||||||
|
if (swap_endian && ak_len) {
|
||||||
|
authKeyPtr = SwapEndian64(authenticationkey, 16, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (succeeded)
|
bool isok = false;
|
||||||
PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s", sprint_hex(key, 16));
|
|
||||||
|
// If no hex key is specified, try default keys
|
||||||
|
if (ak_len == 0) {
|
||||||
|
isok = (try_default_3des_keys(&authKeyPtr) == PM3_SUCCESS);
|
||||||
|
} else {
|
||||||
|
// try user-supplied
|
||||||
|
isok = ulc_authentication(authKeyPtr, !keep_field_on);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isok)
|
||||||
|
PrintAndLogEx(SUCCESS, "Authentication success. 3des key: " _GREEN_("%s"), sprint_hex_inrow(authKeyPtr, 16));
|
||||||
else
|
else
|
||||||
PrintAndLogEx(WARNING, "Authentication failed");
|
PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " )");
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -3484,7 +3459,7 @@ static int CmdHF14MfuNDEF(const char *Cmd) {
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str0("k", "key", "replace default key for NDEF", NULL),
|
arg_str0("k", "key", "replace default key for NDEF", NULL),
|
||||||
arg_lit0("l", "key", "(optional) swap entered key's endianness"),
|
arg_lit0("l", NULL, "swap entered key's endianness"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue