mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
fix magic detection for MFU
This commit is contained in:
parent
4ddb417107
commit
5b64df9247
3 changed files with 302 additions and 85 deletions
|
@ -2554,9 +2554,11 @@ void MifareCIdent(bool is_mfc, uint8_t keytype, uint8_t *key) {
|
||||||
// Generation 1 test
|
// Generation 1 test
|
||||||
ReaderTransmitBitsPar(wupC1, 7, NULL, NULL);
|
ReaderTransmitBitsPar(wupC1, 7, NULL, NULL);
|
||||||
if (ReaderReceive(rec, recpar) && (rec[0] == 0x0A)) {
|
if (ReaderReceive(rec, recpar) && (rec[0] == 0x0A)) {
|
||||||
|
|
||||||
flag = MAGIC_FLAG_GEN_1A;
|
flag = MAGIC_FLAG_GEN_1A;
|
||||||
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
|
||||||
if (ReaderReceive(rec, recpar) && (rec[0] != 0x0A)) {
|
uint16_t tmp = ReaderReceive(rec, recpar);
|
||||||
|
if ((tmp && (rec[0] != 0x0A)) || (tmp == 0)) {
|
||||||
flag = MAGIC_FLAG_GEN_1B;
|
flag = MAGIC_FLAG_GEN_1B;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,10 +123,69 @@ static uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = {
|
||||||
MAX_NTAG_210, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_UL_AES
|
MAX_NTAG_210, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_UL_AES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const ul_family_t ul_family[] = {
|
||||||
|
{"UL-C", "UL-C", "\x00\x00\x00\x00\x00\x00\x00\x00"},
|
||||||
|
{"UL", "MF0UL1001DUx", "\x00\x04\x03\x01\x00\x00\x0B\x03"},
|
||||||
|
{"UL EV1 48", "MF0UL1101DUx", "\x00\x04\x03\x01\x01\x00\x0B\x03"},
|
||||||
|
{"UL EV1 48", "MF0ULH1101DUx", "\x00\x04\x03\x02\x01\x00\x0B\x03"},
|
||||||
|
{"UL EV1 48", "MF0UL1141DUF", "\x00\x04\x03\x03\x01\x00\x0B\x03"},
|
||||||
|
{"UL EV1 128", "MF0UL2101Dxy", "\x00\x04\x03\x01\x01\x00\x0E\x03"},
|
||||||
|
{"UL EV1 128", "MF0UL2101DUx", "\x00\x04\x03\x02\x01\x00\x0E\x03"},
|
||||||
|
{"UL Ev1 n/a ", "MF0UL3101DUx", "\x00\x04\x03\x01\x01\x00\x11\x03"},
|
||||||
|
{"UL Ev1 n/a", "MF0ULH3101DUx", "\x00\x04\x03\x02\x01\x00\x11\x03"},
|
||||||
|
{"UL Ev1 n/a", "MF0UL5101DUx", "\x00\x04\x03\x01\x01\x00\x13\x03"},
|
||||||
|
{"NTAG 210", "NT2L1011F0DUx", "\x00\x04\x04\x01\x01\x00\x0B\x03"},
|
||||||
|
{"NTAG 210", "NT2H1011G0DUD", "\x00\x04\x04\x02\x01\x00\x0B\x03"},
|
||||||
|
{"NTAG 212", "NT2L1211F0DUx", "\x00\x04\x04\x01\x01\x00\x0E\x03"},
|
||||||
|
{"NTAG 213", "NT2H1311G0DUx", "\x00\x04\x04\x02\x01\x00\x0F\x03"},
|
||||||
|
{"NTAG", "NT2H1411G0DUx", "\x00\x04\x04\x02\x01\x01\x11\x03"},
|
||||||
|
{"NTAG 215", "NT2H1511G0DUx", "\x00\x04\x04\x02\x01\x00\x11\x03"},
|
||||||
|
{"NTAG 215", "NT2H1511F0Dxy", "\x00\x04\x04\x04\x01\x00\x11\x03"},
|
||||||
|
{"NTAG 216", "NT2H1611G0DUx", "\x00\x04\x04\x02\x01\x00\x13\x03"},
|
||||||
|
{"NTAG 213F", "NT2H1311F0Dxy", "\x00\x04\x04\x04\x01\x00\x0F\x03"},
|
||||||
|
{"NTAG 216F", "NT2H1611F0Dxy", "\x00\x04\x04\x04\x01\x00\x13\x03"},
|
||||||
|
{"NTAG 213C", "NT2H1311C1DTL", "\x00\x04\x04\x02\x01\x01\x0F\x03"},
|
||||||
|
{"NTAG 213TT", "NT2H1311TTDUx", "\x00\x04\x04\x02\x03\x00\x0F\x03"},
|
||||||
|
{"NTAG I2C 1k", "NT3H1101W0FHK", "\x00\x04\x04\x05\x02\x00\x13\x03"},
|
||||||
|
{"NTAG I2C 1k", "NT3H1101W0FHK_Variant", "\x00\x04\x04\x05\x02\x01\x13\x03"},
|
||||||
|
{"NTAG I2C 2k", "NT3H1201W0FHK", "\x00\x04\x04\x05\x02\x00\x15\x03"},
|
||||||
|
{"NTAG I2C 2k", "NT3H1201", "\x00\x04\x04\x05\x02\x01\x15\x03"},
|
||||||
|
{"NTAG I2C 1k Plus", "NT3H2111", "\x00\x04\x04\x05\x02\x02\x13\x03"},
|
||||||
|
{"NTAG I2C 2k Plus", "NT3H2211", "\x00\x04\x04\x05\x02\x02\x15\x03"},
|
||||||
|
{"NTAG unk", "nhs", "\x00\x04\x04\x06\x00\x00\x13\x03"},
|
||||||
|
{"UL NANO 40", "MF0UN0001DUx 17pF", "\x00\x04\x03\x01\x02\x00\x0B\x03"},
|
||||||
|
{"UL NANO", "MF0UN1001DUx 17pF", "\x00\x04\x03\x01\x03\x00\x0B\x03"},
|
||||||
|
{"UL NANO 40", "MF0UNH0001DUx 50pF", "\x00\x04\x03\x02\x02\x00\x0B\x03"},
|
||||||
|
{"UL NANO", "MF0UNH1001DUx 50pF", "\x00\x04\x03\x02\x03\x00\x0B\x03"},
|
||||||
|
{"NTAG 210u", "NT2L1001G0DUx", "\x00\x04\x04\x01\x02\x00\x0B\x03"},
|
||||||
|
{"NTAG 210u", "NT2H1001G0DUx", "\x00\x04\x04\x02\x02\x00\x0B\x03"},
|
||||||
|
{"UL EV1 128", "Mikron JSC Russia EV1", "\x00\x34\x21\x01\x01\x00\x0E\x03"},
|
||||||
|
{"NTAG 213", "Shanghai Feiju NTAG", "\x00\x53\x04\x02\x01\x00\x0F\x03"},
|
||||||
|
{"UL AES", "MF0AES2001DUD", "\x00\x04\x03\x01\x04\x00\x0F\x03"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool compare_ul_family(uint8_t *d, uint8_t n) {
|
||||||
|
if (d == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 8) {
|
||||||
|
n = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAYLEN(ul_family); ++i) {
|
||||||
|
if (memcmp(d, ul_family[i].version, n) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
// get version nxp product type
|
// get version nxp product type
|
||||||
static const char *getProductTypeStr(uint8_t id) {
|
static const char *getProductTypeStr(uint8_t id) {
|
||||||
static char buf[20];
|
static char buf[20];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -271,6 +330,47 @@ static bool ul_select(iso14a_card_select_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ul_select_rats(iso14a_card_select_t *card) {
|
||||||
|
|
||||||
|
ul_switch_on_field();
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||||
|
PrintAndLogEx(DEBUG, "iso14443a card select timeout");
|
||||||
|
DropField();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
uint16_t len = (resp.oldarg[1] & 0xFFFF);
|
||||||
|
if (len == 0) {
|
||||||
|
PrintAndLogEx(DEBUG, "iso14443a card select failed");
|
||||||
|
DropField();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (card) {
|
||||||
|
memcpy(card, resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||||
|
// get ATS
|
||||||
|
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
|
||||||
|
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, sizeof(rats), 0, rats, sizeof(rats));
|
||||||
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (card) {
|
||||||
|
card->ats_len = resp.oldarg[0];
|
||||||
|
memcpy(card->ats, resp.data.asBytes, card->ats_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// This read command will at least return 16bytes.
|
// This read command will at least return 16bytes.
|
||||||
static int ul_read(uint8_t page, uint8_t *response, uint16_t responseLength) {
|
static int ul_read(uint8_t page, uint8_t *response, uint16_t responseLength) {
|
||||||
|
|
||||||
|
@ -801,7 +901,7 @@ int ul_print_type(uint64_t tagtype, uint8_t spaces) {
|
||||||
spaces = 10;
|
spaces = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
char typestr[100];
|
char typestr[140];
|
||||||
memset(typestr, 0x00, sizeof(typestr));
|
memset(typestr, 0x00, sizeof(typestr));
|
||||||
|
|
||||||
if (tagtype & MFU_TT_UL)
|
if (tagtype & MFU_TT_UL)
|
||||||
|
@ -865,17 +965,23 @@ int ul_print_type(uint64_t tagtype, uint8_t spaces) {
|
||||||
else
|
else
|
||||||
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("Unknown %06" PRIx64), spaces, "", tagtype);
|
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("Unknown %06" PRIx64), spaces, "", tagtype);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool ismagic = ((tagtype & MFU_TT_MAGIC) == MFU_TT_MAGIC);
|
bool ismagic = ((tagtype & MFU_TT_MAGIC) == MFU_TT_MAGIC);
|
||||||
|
// clear magic flag
|
||||||
|
tagtype &= ~(MFU_TT_MAGIC);
|
||||||
|
|
||||||
if (ismagic) {
|
if (ismagic) {
|
||||||
snprintf(typestr + strlen(typestr), 4, " (");
|
snprintf(typestr + strlen(typestr), 4, " (");
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MFU_TT_MAGIC) ? _GREEN_("magic") : "");
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", ((tagtype & MFU_TT_MAGIC_1A) == MFU_TT_MAGIC_1A) ? _GREEN_("Gen 1a") : "");
|
||||||
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", ((tagtype & MFU_TT_MAGIC_1B) == MFU_TT_MAGIC_1B) ? _GREEN_("Gen 1b") : "");
|
||||||
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", ((tagtype & MFU_TT_MAGIC_2) == MFU_TT_MAGIC_2) ? _GREEN_("Gen 2 / CUID") : "");
|
||||||
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", ((tagtype & MFU_TT_MAGIC_4) == MFU_TT_MAGIC_4) ? _GREEN_("USCUID-UL") : "");
|
||||||
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", ((tagtype & MFU_TT_MAGIC_NTAG) == MFU_TT_MAGIC_NTAG) ? _GREEN_("NTAG CUID") : "");
|
||||||
|
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", ((tagtype & MFU_TT_MAGIC_NTAG21X) == MFU_TT_MAGIC_NTAG21X) ? _GREEN_("NTAG21x") : "");
|
||||||
|
|
||||||
tagtype &= ~(MFU_TT_MAGIC);
|
|
||||||
|
|
||||||
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MFU_TT_MAGIC_1A) ? _GREEN_("Gen 1a") : "");
|
|
||||||
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MFU_TT_MAGIC_1B) ? _GREEN_("Gen 1b") : "");
|
|
||||||
|
|
||||||
if (ismagic) {
|
if (ismagic) {
|
||||||
snprintf(typestr + strlen(typestr), 4, " )");
|
snprintf(typestr + strlen(typestr), 4, " )");
|
||||||
|
@ -894,6 +1000,7 @@ static int ulc_print_3deskey(uint8_t *data) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only takes 16 bytes of data. Now key data available here
|
||||||
static int ulc_print_configuration(uint8_t *data) {
|
static int ulc_print_configuration(uint8_t *data) {
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
@ -904,13 +1011,13 @@ static int ulc_print_configuration(uint8_t *data) {
|
||||||
PrintAndLogEx(INFO, "41 / 0x29 | %s - %s Counter", sprint_hex(data + 4, 4), sprint_bin(data + 4, 2));
|
PrintAndLogEx(INFO, "41 / 0x29 | %s - %s Counter", sprint_hex(data + 4, 4), sprint_bin(data + 4, 2));
|
||||||
|
|
||||||
bool validAuth = (data[8] >= 0x03 && data[8] < 0x30);
|
bool validAuth = (data[8] >= 0x03 && data[8] < 0x30);
|
||||||
if (validAuth)
|
if (validAuth) {
|
||||||
PrintAndLogEx(INFO, "42 / 0x2A | Auth0, %s Page " _YELLOW_("%d") "/" _YELLOW_("0x%02X") " and above need authentication"
|
PrintAndLogEx(INFO, "42 / 0x2A | %s Auth0 Page " _YELLOW_("%d") "/" _YELLOW_("0x%02X") " and above need authentication"
|
||||||
, sprint_hex(data + 8, 4)
|
, sprint_hex(data + 8, 4)
|
||||||
, data[8]
|
, data[8]
|
||||||
, data[8]
|
, data[8]
|
||||||
);
|
);
|
||||||
else {
|
} else {
|
||||||
if (data[8] == 0) {
|
if (data[8] == 0) {
|
||||||
PrintAndLogEx(INFO, "42 / 0x2A | %s Auth0 default", sprint_hex(data + 8, 4));
|
PrintAndLogEx(INFO, "42 / 0x2A | %s Auth0 default", sprint_hex(data + 8, 4));
|
||||||
} else if (data[8] == 0x30) {
|
} else if (data[8] == 0x30) {
|
||||||
|
@ -919,10 +1026,12 @@ static int ulc_print_configuration(uint8_t *data) {
|
||||||
PrintAndLogEx(INFO, "42 / 0x2A | %s Auth0 " _RED_("byte is out-of-range"), sprint_hex(data + 8, 4));
|
PrintAndLogEx(INFO, "42 / 0x2A | %s Auth0 " _RED_("byte is out-of-range"), sprint_hex(data + 8, 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "43 / 0x2B | %s Auth1 %s",
|
PrintAndLogEx(INFO, "43 / 0x2B | %s Auth1 %s",
|
||||||
sprint_hex(data + 12, 4),
|
sprint_hex(data + 12, 4),
|
||||||
(data[12] & 1) ? "write access restricted" : _RED_("R/W access restricted")
|
(data[12] & 1) ? "write access restricted" : _RED_("R/W access restricted")
|
||||||
);
|
);
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1426,20 +1535,71 @@ static int ulc_magic_test(){
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
static int ul_magic_test(void) {
|
static uint64_t ul_magic_test(void) {
|
||||||
// Magic Ultralight tests
|
// Magic Ultralight tests
|
||||||
// 1) take present UID, and try to write it back. OBSOLETE
|
// 1) take present UID, and try to write it back. OBSOLETE
|
||||||
// 2) make a wrong length write to page0, and see if tag answers with ACK/NACK:
|
// 2) make a wrong length write to page0, and see if tag answers with ACK/NACK:
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
iso14a_card_select_t card;
|
iso14a_card_select_t card;
|
||||||
if (ul_select(&card) == false) {
|
if (ul_select_rats(&card) == false) {
|
||||||
return MFU_TT_UL_ERROR;
|
return MFU_TT_UL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// iceman: how to proper identify RU based UID cards
|
||||||
|
if (
|
||||||
|
(memcmp(card.uid, "\xAA\x55\x39", 3) == 0) ||
|
||||||
|
(memcmp(card.uid, "\xAA\x55\xC3", 3) == 0)
|
||||||
|
) {
|
||||||
|
// Ul-5 MFU Ev1 FUID,
|
||||||
|
return MFU_TT_UL_EV1_MAGIC;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
PrintAndLogEx(DEBUG, "%u - %s", card.ats_len, sprint_hex_inrow(card.ats, card.ats_len));
|
||||||
|
|
||||||
|
// USCUID-UL cards
|
||||||
|
if (card.ats_len == 18) {
|
||||||
|
|
||||||
|
// USCUID-UL configuration
|
||||||
|
// https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md#uscuid-ul-configuration-guide
|
||||||
|
// identify: ATS len 18,
|
||||||
|
// First 8 bytes can vary depending on setup. next 8 bytes is GET VERSION data and finally 2 byte crc
|
||||||
|
//
|
||||||
|
// \x85\x00\x00\xA0\x0A\x00\x0A\xC3 \x00\x04\x03\x01\x01\x00\x0B\x03 \xZZ\xZZ
|
||||||
|
//
|
||||||
|
// 7AFF - back door enabled
|
||||||
|
// 8500 -
|
||||||
|
// if we ignore first 8 bytes we can identify regardless how card is configured
|
||||||
|
//
|
||||||
|
if (compare_ul_family(card.ats + 8, 8)) {
|
||||||
|
return MFU_TT_MAGIC_4 | MFU_TT_MAGIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct write alternative cards
|
||||||
|
if (card.ats_len == 14) {
|
||||||
|
|
||||||
|
// UL-C Direct write
|
||||||
|
if (memcmp(card.ats, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
|
||||||
|
return MFU_TT_MAGIC_2 | MFU_TT_UL_C_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NTAG 213 Direct write
|
||||||
|
if (memcmp(card.ats, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
|
||||||
|
|
||||||
|
// iceman: should this be the same as NTAg21x?!?
|
||||||
|
return MFU_TT_MAGIC_2 | MFU_TT_MAGIC_NTAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int status = ul_comp_write(0, NULL, 0);
|
int status = ul_comp_write(0, NULL, 0);
|
||||||
DropField();
|
DropField();
|
||||||
if (status == PM3_SUCCESS) {
|
if (status == PM3_SUCCESS) {
|
||||||
return MFU_TT_MAGIC;
|
PrintAndLogEx(INFO, "comp write pass");
|
||||||
|
return MFU_TT_MAGIC_2 | MFU_TT_MAGIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for GEN1A, GEN1B and NTAG21x
|
// check for GEN1A, GEN1B and NTAG21x
|
||||||
|
@ -1456,14 +1616,14 @@ static int ul_magic_test(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((is_generation & MAGIC_FLAG_GEN_1A) == MAGIC_FLAG_GEN_1A) {
|
if ((is_generation & MAGIC_FLAG_GEN_1A) == MAGIC_FLAG_GEN_1A) {
|
||||||
return MFU_TT_MAGIC_1A;
|
return MFU_TT_MAGIC_1A | MFU_TT_MAGIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((is_generation & MAGIC_FLAG_GEN_1B) == MAGIC_FLAG_GEN_1B) {
|
if ((is_generation & MAGIC_FLAG_GEN_1B) == MAGIC_FLAG_GEN_1B) {
|
||||||
return MFU_TT_MAGIC_1B;
|
return MFU_TT_MAGIC_1B | MFU_TT_MAGIC;
|
||||||
}
|
}
|
||||||
if ((is_generation & MAGIC_FLAG_NTAG21X) == MAGIC_FLAG_NTAG21X) {
|
if ((is_generation & MAGIC_FLAG_NTAG21X) == MAGIC_FLAG_NTAG21X) {
|
||||||
return MFU_TT_MAGIC_NTAG;
|
return MFU_TT_MAGIC_NTAG21X | MFU_TT_MAGIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MFU_TT_UNKNOWN;
|
return MFU_TT_UNKNOWN;
|
||||||
|
@ -1482,6 +1642,8 @@ static char *mfu_generate_filename(const char *prefix, const char *suffix) {
|
||||||
return fptr;
|
return fptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used with the Amiibo dumps loading...
|
||||||
|
// Not related to 'hf mfu dump'
|
||||||
static int mfu_dump_tag(uint16_t pages, void **pdata, uint16_t *len) {
|
static int mfu_dump_tag(uint16_t pages, void **pdata, uint16_t *len) {
|
||||||
|
|
||||||
// read uid
|
// read uid
|
||||||
|
@ -1510,7 +1672,7 @@ static int mfu_dump_tag(uint16_t pages, void **pdata, uint16_t *len) {
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_READCARD, 0, pages, keytype, key, 4);
|
SendCommandMIX(CMD_HF_MIFAREU_READCARD, 0, pages, keytype, key, 4);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||||
PrintAndLogEx(WARNING, "Command execute time-out");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
free(*pdata);
|
free(*pdata);
|
||||||
res = PM3_ETIMEOUT;
|
res = PM3_ETIMEOUT;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1566,8 +1728,6 @@ typedef struct {
|
||||||
|
|
||||||
static mfu_otp_identify_t mfu_otp_ident_table[] = {
|
static mfu_otp_identify_t mfu_otp_ident_table[] = {
|
||||||
{ "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA, NULL },
|
{ "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA, NULL },
|
||||||
// { "Assa Abloy Ving Card", 12, 4, NULL, ul_ev1_otpgenA, NULL },
|
|
||||||
// { "MyKey", 12, 4, NULL, ul_mykey_otpgen, NULL },
|
|
||||||
{ NULL, 0, 0, NULL, NULL, NULL }
|
{ NULL, 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1798,7 +1958,7 @@ static int mfu_fingerprint(uint64_t tagtype, bool hasAuthKey, uint8_t *authkey,
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||||
PrintAndLogEx(WARNING, "Command execute time-out");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
res = PM3_ETIMEOUT;
|
res = PM3_ETIMEOUT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -2081,6 +2241,7 @@ uint64_t GetHF14AMfU_Type(void) {
|
||||||
if (tagtype == (MFU_TT_UNKNOWN | MFU_TT_MAGIC)) {
|
if (tagtype == (MFU_TT_UNKNOWN | MFU_TT_MAGIC)) {
|
||||||
tagtype = (MFU_TT_UL_MAGIC);
|
tagtype = (MFU_TT_UL_MAGIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tagtype;
|
return tagtype;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
@ -2205,6 +2366,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
// if we called info with key, just return
|
// if we called info with key, just return
|
||||||
if (has_auth_key) {
|
if (has_auth_key) {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2217,6 +2379,8 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(INFO, "n/a");
|
PrintAndLogEx(INFO, "n/a");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2357,6 +2521,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
if (!authlim && (has_auth_key == false)) {
|
if (!authlim && (has_auth_key == false)) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(SUCCESS, "--- " _CYAN_("Known EV1/NTAG passwords"));
|
PrintAndLogEx(SUCCESS, "--- " _CYAN_("Known EV1/NTAG passwords"));
|
||||||
|
|
||||||
// test pwd gen A
|
// test pwd gen A
|
||||||
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));
|
||||||
|
@ -2677,7 +2842,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
|
||||||
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 timeout");
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2972,7 +3137,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
PrintAndLogEx(SUCCESS, "Reading tag memory...");
|
PrintAndLogEx(SUCCESS, "Reading tag memory...");
|
||||||
uint8_t keytype = 0;
|
uint8_t keytype = 0;
|
||||||
if (has_auth_key || has_pwd) {
|
if (has_auth_key || has_pwd) {
|
||||||
if (tagtype & MFU_TT_UL_C)
|
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C)
|
||||||
keytype = 1; // UL_C auth
|
keytype = 1; // UL_C auth
|
||||||
else
|
else
|
||||||
keytype = 2; // UL_EV1/NTAG auth
|
keytype = 2; // UL_EV1/NTAG auth
|
||||||
|
@ -2991,7 +3156,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_READCARD, start_page, pages, keytype, authKeyPtr, ak_len);
|
SendCommandMIX(CMD_HF_MIFAREU_READCARD, start_page, pages, keytype, authKeyPtr, ak_len);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||||
PrintAndLogEx(WARNING, "Command execute time-out");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3014,13 +3179,25 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetFromDevice(BIG_BUF, data, buffer_size, startindex, NULL, 0, NULL, 2500, false) == false) {
|
if (GetFromDevice(BIG_BUF, data, buffer_size, startindex, NULL, 0, NULL, 2500, false) == false) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_partial = (pages != buffer_size / 4);
|
bool is_partial = (pages != buffer_size / MFU_BLOCK_SIZE);
|
||||||
|
|
||||||
pages = buffer_size / 4;
|
pages = buffer_size / MFU_BLOCK_SIZE;
|
||||||
|
|
||||||
|
if (is_partial) {
|
||||||
|
|
||||||
|
if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) {
|
||||||
|
if (card_mem_size != (pages + 4)) {
|
||||||
|
PrintAndLogEx(INFO, "Partial dump, got " _RED_("%d") " bytes - card mem size is %u bytes", pages * MFU_BLOCK_SIZE, card_mem_size * MFU_BLOCK_SIZE);
|
||||||
|
PrintAndLogEx(HINT, "Try using a key");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(HINT, "Try using a pwd");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iso14a_card_select_t card;
|
iso14a_card_select_t card;
|
||||||
mfu_dump_t dump_file_data;
|
mfu_dump_t dump_file_data;
|
||||||
|
@ -3103,31 +3280,48 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
|
|
||||||
// format and add keys to block dump output
|
// format and add keys to block dump output
|
||||||
// only add keys if not partial read, and complete pages read
|
// only add keys if not partial read, and complete pages read
|
||||||
if (!is_partial && pages == card_mem_size && (has_auth_key || has_pwd)) {
|
|
||||||
|
// UL-C add a working known key
|
||||||
|
if (has_auth_key && (tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) { // add 4 pages of key
|
||||||
|
|
||||||
// if we didn't swapendian before - do it now for the sprint_hex call
|
// if we didn't swapendian before - do it now for the sprint_hex call
|
||||||
// NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
|
// NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
|
||||||
// need to swap to keep it the same
|
// need to swap to keep it the same
|
||||||
if (swap_endian == false) {
|
if (swap_endian == false) {
|
||||||
authKeyPtr = SwapEndian64(authenticationkey, ak_len, (ak_len == 16) ? 8 : 4);
|
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 8);
|
||||||
} else {
|
} else {
|
||||||
authKeyPtr = authenticationkey;
|
authKeyPtr = authenticationkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagtype & MFU_TT_UL_C) { //add 4 pages
|
memcpy(data + pages * MFU_BLOCK_SIZE, authKeyPtr, ak_len);
|
||||||
memcpy(data + pages * 4, authKeyPtr, ak_len);
|
pages += ak_len / MFU_BLOCK_SIZE;
|
||||||
pages += ak_len / 4;
|
|
||||||
} else { // 2nd page from end
|
// fix
|
||||||
memcpy(data + (pages * 4) - 8, authenticationkey, ak_len);
|
if (is_partial && pages == card_mem_size) {
|
||||||
|
is_partial = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_partial && pages == card_mem_size && has_pwd) {
|
||||||
|
// if we didn't swapendian before - do it now for the sprint_hex call
|
||||||
|
// NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
|
||||||
|
// need to swap to keep it the same
|
||||||
|
if (swap_endian == false) {
|
||||||
|
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 4);
|
||||||
|
} else {
|
||||||
|
authKeyPtr = authenticationkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data + (pages * MFU_BLOCK_SIZE) - 8, authenticationkey, ak_len);
|
||||||
|
}
|
||||||
|
|
||||||
//add *special* blocks to dump
|
//add *special* blocks to dump
|
||||||
// pack and pwd saved into last pages of dump, if was not partial read
|
// pack and pwd saved into last pages of dump, if was not partial read
|
||||||
dump_file_data.pages = pages - 1;
|
dump_file_data.pages = pages - 1;
|
||||||
memcpy(dump_file_data.version, get_version, sizeof(dump_file_data.version));
|
memcpy(dump_file_data.version, get_version, sizeof(dump_file_data.version));
|
||||||
memcpy(dump_file_data.signature, get_signature, sizeof(dump_file_data.signature));
|
memcpy(dump_file_data.signature, get_signature, sizeof(dump_file_data.signature));
|
||||||
memcpy(dump_file_data.counter_tearing, get_counter_tearing, sizeof(dump_file_data.counter_tearing));
|
memcpy(dump_file_data.counter_tearing, get_counter_tearing, sizeof(dump_file_data.counter_tearing));
|
||||||
memcpy(dump_file_data.data, data, pages * 4);
|
memcpy(dump_file_data.data, data, pages * MFU_BLOCK_SIZE);
|
||||||
|
|
||||||
mfu_print_dump(&dump_file_data, pages, start_page, dense_output);
|
mfu_print_dump(&dump_file_data, pages, start_page, dense_output);
|
||||||
|
|
||||||
|
@ -3147,7 +3341,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
FillFileNameByUID(filename, uid, "-dump", sizeof(uid));
|
FillFileNameByUID(filename, uid, "-dump", sizeof(uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH;
|
uint16_t datalen = MFU_DUMP_PREFIX_LENGTH + (pages * MFU_BLOCK_SIZE);
|
||||||
pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory);
|
pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory);
|
||||||
|
|
||||||
if (is_partial) {
|
if (is_partial) {
|
||||||
|
@ -3160,8 +3354,9 @@ static void wait4response(uint8_t b) {
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||||
if (!isOK)
|
if (isOK == 0) {
|
||||||
PrintAndLogEx(WARNING, "failed to write block %d", b);
|
PrintAndLogEx(WARNING, "failed to write block %d", b);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
}
|
}
|
||||||
|
@ -3237,7 +3432,7 @@ int CmdHF14MfUTamper(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return MFU_TT_UL_ERROR;
|
return MFU_TT_UL_ERROR;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "Trying to write tamper message\n");
|
PrintAndLogEx(INFO, "Trying to write tamper message");
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, tt_msg_page, 0, 0, msg_data, 4);
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, tt_msg_page, 0, 0, msg_data, 4);
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
@ -3434,7 +3629,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
memcpy(data, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 8), 4);
|
memcpy(data, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 8), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "special PWD block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4));
|
PrintAndLogEx(INFO, "special PWD block written 0x%X - %s", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data));
|
||||||
|
|
||||||
|
@ -3450,7 +3645,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
memcpy(data, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 4), 2);
|
memcpy(data, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 4), 2);
|
||||||
data[2] = 0;
|
data[2] = 0;
|
||||||
data[3] = 0;
|
data[3] = 0;
|
||||||
PrintAndLogEx(INFO, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4));
|
PrintAndLogEx(INFO, "special PACK block written 0x%X - %s", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data));
|
||||||
wait4response(MFU_NTAG_SPECIAL_PACK);
|
wait4response(MFU_NTAG_SPECIAL_PACK);
|
||||||
|
@ -3458,7 +3653,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
// Signature
|
// Signature
|
||||||
for (uint8_t s = MFU_NTAG_SPECIAL_SIGNATURE, i = 0; s < MFU_NTAG_SPECIAL_SIGNATURE + 8; s++, i += 4) {
|
for (uint8_t s = MFU_NTAG_SPECIAL_SIGNATURE, i = 0; s < MFU_NTAG_SPECIAL_SIGNATURE + 8; s++, i += 4) {
|
||||||
memcpy(data, mem->signature + i, 4);
|
memcpy(data, mem->signature + i, 4);
|
||||||
PrintAndLogEx(INFO, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4));
|
PrintAndLogEx(INFO, "special SIG block written 0x%X - %s", s, sprint_hex(data, 4));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data));
|
||||||
wait4response(s);
|
wait4response(s);
|
||||||
|
@ -3467,7 +3662,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
// Version
|
// Version
|
||||||
for (uint8_t s = MFU_NTAG_SPECIAL_VERSION, i = 0; s < MFU_NTAG_SPECIAL_VERSION + 2; s++, i += 4) {
|
for (uint8_t s = MFU_NTAG_SPECIAL_VERSION, i = 0; s < MFU_NTAG_SPECIAL_VERSION + 2; s++, i += 4) {
|
||||||
memcpy(data, mem->version + i, 4);
|
memcpy(data, mem->version + i, 4);
|
||||||
PrintAndLogEx(INFO, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4));
|
PrintAndLogEx(INFO, "special VERSION block written 0x%X - %s", s, sprint_hex(data, 4));
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data));
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data));
|
||||||
wait4response(s);
|
wait4response(s);
|
||||||
|
@ -3494,7 +3689,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
// write special data last
|
// write special data last
|
||||||
if (write_special) {
|
if (write_special) {
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Restoring configuration blocks.\n");
|
PrintAndLogEx(INFO, "Restoring configuration blocks");
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "authentication with keytype[%x] %s\n", (uint8_t)(keytype & 0xff), sprint_hex(p_authkey, 4));
|
PrintAndLogEx(INFO, "authentication with keytype[%x] %s\n", (uint8_t)(keytype & 0xff), sprint_hex(p_authkey, 4));
|
||||||
|
|
||||||
|
@ -3620,7 +3815,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (ak_len != 16 && ak_len != 0) {
|
if (ak_len != 16 && ak_len != 0) {
|
||||||
PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n");
|
PrintAndLogEx(WARNING, "ERROR: Key is incorrect length");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3640,7 +3835,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isok == PM3_SUCCESS) {
|
if (isok == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(SUCCESS, "Authentication success. 3des key: " _GREEN_("%s"), sprint_hex_inrow(authKeyPtr, 16));
|
PrintAndLogEx(SUCCESS, "Authentication 3DES key... " _GREEN_("%s") " ( " _GREEN_("ok")" )", sprint_hex_inrow(authKeyPtr, 16));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " )");
|
PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " )");
|
||||||
}
|
}
|
||||||
|
@ -3777,13 +3972,13 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) {
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
if ((resp.oldarg[0] & 0xff) == 1) {
|
if ((resp.oldarg[0] & 0xff) == 1) {
|
||||||
PrintAndLogEx(INFO, "Ultralight-C new key: %s", sprint_hex(key, sizeof(key)));
|
PrintAndLogEx(INFO, "Ultralight-C new key... " _GREEN_("%s"), sprint_hex_inrow(key, sizeof(key)));
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
|
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF));
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -3838,7 +4033,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
hf14a_config config;
|
hf14a_config config;
|
||||||
SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG, NULL, 0);
|
SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG, NULL, 0);
|
||||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG, &resp, 2000)) {
|
if (!WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG, &resp, 2000)) {
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
memcpy(&config, resp.data.asBytes, sizeof(hf14a_config));
|
memcpy(&config, resp.data.asBytes, sizeof(hf14a_config));
|
||||||
|
@ -3896,7 +4091,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
||||||
static int CmdHF14AMfUKeyGen(const char *Cmd) {
|
static int CmdHF14AMfUKeyGen(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf mfu keygen",
|
CLIParserInit(&ctx, "hf mfu keygen",
|
||||||
"Set the DES/3DES/AES key on MIFARE Ultralight-C tag. ",
|
"Calculate MFC keys based ",
|
||||||
"hf mfu keygen -r\n"
|
"hf mfu keygen -r\n"
|
||||||
"hf mfu keygen --uid 11223344556677"
|
"hf mfu keygen --uid 11223344556677"
|
||||||
);
|
);
|
||||||
|
@ -4045,15 +4240,15 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
|
||||||
CLIParserInit(&ctx, "hf mfu pwdgen",
|
CLIParserInit(&ctx, "hf mfu pwdgen",
|
||||||
"Generate different passwords from known pwdgen algos",
|
"Generate different passwords from known pwdgen algos",
|
||||||
"hf mfu pwdgen -r\n"
|
"hf mfu pwdgen -r\n"
|
||||||
"hf mfu pwdgen -t\n"
|
"hf mfu pwdgen --uid 11223344556677\n"
|
||||||
"hf mfu pwdgen --uid 11223344556677"
|
"hf mfu pwdgen --test"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str0("u", "uid", "<hex>", "UID (7 hex bytes)"),
|
arg_str0("u", "uid", "<hex>", "UID (7 hex bytes)"),
|
||||||
arg_lit0("r", NULL, "Read UID from tag"),
|
arg_lit0("r", NULL, "Read UID from tag"),
|
||||||
arg_lit0("t", NULL, "Selftest"),
|
arg_lit0(NULL, "test", "self test"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
@ -4065,14 +4260,21 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
|
||||||
bool selftest = arg_get_lit(ctx, 3);
|
bool selftest = arg_get_lit(ctx, 3);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (selftest)
|
if (selftest) {
|
||||||
return generator_selftest();
|
return generator_selftest();
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t philips_mfg[10] = {0};
|
uint8_t philips_mfg[10] = {0};
|
||||||
|
|
||||||
if (use_tag) {
|
if (use_tag) {
|
||||||
// read uid from tag
|
// read uid from tag
|
||||||
int res = ul_read_uid(uid);
|
int res = ul_read_uid(uid);
|
||||||
|
if (res == PM3_ELENGTH) {
|
||||||
|
// got 4 byte UID, lets adapt to 7 bytes :)
|
||||||
|
memset(uid + 4, 0x00, 3);
|
||||||
|
u_len = 7;
|
||||||
|
} else {
|
||||||
|
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -4089,31 +4291,35 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
|
||||||
}
|
}
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (u_len != 7) {
|
if (u_len != 7 && u_len != 4) {
|
||||||
PrintAndLogEx(WARNING, "Key must be 7 hex bytes");
|
PrintAndLogEx(WARNING, "Key must be 7 hex bytes");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
} else {
|
||||||
|
// adapt to 7 bytes :)
|
||||||
|
memset(uid + 4, 0x00, 3);
|
||||||
|
u_len = 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "------------------.------------------");
|
PrintAndLogEx(INFO, "-----------------------------------");
|
||||||
PrintAndLogEx(INFO, " Using UID 4b: " _YELLOW_("%s"), sprint_hex(uid, 4));
|
PrintAndLogEx(INFO, " UID 4b... " _YELLOW_("%s"), sprint_hex(uid, 4));
|
||||||
PrintAndLogEx(INFO, " Using UID 7b: " _YELLOW_("%s"), sprint_hex(uid, 7));
|
PrintAndLogEx(INFO, " UID 7b... " _YELLOW_("%s"), sprint_hex(uid, 7));
|
||||||
PrintAndLogEx(INFO, "-------------------------------------");
|
PrintAndLogEx(INFO, "-----------------------------------");
|
||||||
PrintAndLogEx(INFO, " algo | pwd | pack");
|
PrintAndLogEx(INFO, " algo pwd pack");
|
||||||
PrintAndLogEx(INFO, "--------------------+----------+-----");
|
PrintAndLogEx(INFO, "-----------------------------+-----");
|
||||||
PrintAndLogEx(INFO, " Transport EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid));
|
PrintAndLogEx(INFO, " Transport EV1..... %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid));
|
||||||
PrintAndLogEx(INFO, " Amiibo | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid));
|
PrintAndLogEx(INFO, " Amiibo............ %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid));
|
||||||
PrintAndLogEx(INFO, " Lego Dimension | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid));
|
PrintAndLogEx(INFO, " Lego Dimension.... %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid));
|
||||||
PrintAndLogEx(INFO, " XYZ 3D printer | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid));
|
PrintAndLogEx(INFO, " XYZ 3D printer.... %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid));
|
||||||
PrintAndLogEx(INFO, " Xiaomi purifier | %08X | %04X", ul_ev1_pwdgenE(uid), ul_ev1_packgenE(uid));
|
PrintAndLogEx(INFO, " Xiaomi purifier... %08X | %04X", ul_ev1_pwdgenE(uid), ul_ev1_packgenE(uid));
|
||||||
PrintAndLogEx(INFO, " NTAG tools | %08X | %04X", ul_ev1_pwdgenF(uid), ul_ev1_packgen_def(uid));
|
PrintAndLogEx(INFO, " NTAG tools........ %08X | %04X", ul_ev1_pwdgenF(uid), ul_ev1_packgen_def(uid));
|
||||||
if (philips_mfg[0] != 0) {
|
if (philips_mfg[0] != 0) {
|
||||||
PrintAndLogEx(INFO, " Philips Toothbrush | %08X | %04X", ul_ev1_pwdgenG(uid, philips_mfg), ul_ev1_packgenG(uid, philips_mfg));
|
PrintAndLogEx(INFO, " Philips Toothbrush | %08X | %04X", ul_ev1_pwdgenG(uid, philips_mfg), ul_ev1_packgenG(uid, philips_mfg));
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "--------------------+----------+-----");
|
PrintAndLogEx(INFO, "-----------------------------+-----");
|
||||||
PrintAndLogEx(INFO, " Vingcard algo");
|
PrintAndLogEx(INFO, _CYAN_("Vingcard"));
|
||||||
uint64_t key = 0;
|
uint64_t key = 0;
|
||||||
mfc_algo_saflok_one(uid, 0, 0, &key);
|
mfc_algo_saflok_one(uid, 0, 0, &key);
|
||||||
PrintAndLogEx(INFO, " Saflok algo | %012" PRIX64, key);
|
PrintAndLogEx(INFO, " Saflok algo | %012" PRIX64, key);
|
||||||
|
@ -5014,7 +5220,7 @@ static int CmdHF14AMfuEView(const char *Cmd) {
|
||||||
bool override_end = (end != -1) ;
|
bool override_end = (end != -1) ;
|
||||||
|
|
||||||
if (override_end && (end < 0 || end > MFU_MAX_BLOCKS)) {
|
if (override_end && (end < 0 || end > MFU_MAX_BLOCKS)) {
|
||||||
PrintAndLogEx(WARNING, "Invalid value for end:%d. Must be be positive integer < %d.", end, MFU_MAX_BLOCKS);
|
PrintAndLogEx(WARNING, "Invalid value for end: %d Must be be positive integer < %d", end, MFU_MAX_BLOCKS);
|
||||||
return PM3_EINVARG ;
|
return PM3_EINVARG ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,12 @@ typedef struct {
|
||||||
uint8_t data[1024];
|
uint8_t data[1024];
|
||||||
} PACKED old_mfu_dump_t;
|
} PACKED old_mfu_dump_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
const char *model;
|
||||||
|
const char *version;
|
||||||
|
} ul_family_t;
|
||||||
|
|
||||||
uint64_t GetHF14AMfU_Type(void);
|
uint64_t GetHF14AMfU_Type(void);
|
||||||
int ul_print_type(uint64_t tagtype, uint8_t spaces);
|
int ul_print_type(uint64_t tagtype, uint8_t spaces);
|
||||||
void mfu_print_dump(mfu_dump_t *card, uint16_t pages, uint8_t startpage, bool dense_output);
|
void mfu_print_dump(mfu_dump_t *card, uint16_t pages, uint8_t startpage, bool dense_output);
|
||||||
|
@ -81,11 +87,14 @@ int CmdHF14MfUTamper(const char *Cmd);
|
||||||
#define MFU_TT_UL_NANO_40 0x2000000ULL
|
#define MFU_TT_UL_NANO_40 0x2000000ULL
|
||||||
#define MFU_TT_NTAG_213_TT 0x4000000ULL
|
#define MFU_TT_NTAG_213_TT 0x4000000ULL
|
||||||
#define MFU_TT_NTAG_213_C 0x8000000ULL
|
#define MFU_TT_NTAG_213_C 0x8000000ULL
|
||||||
#define MFU_TT_MAGIC_1A (0x10000000ULL | MFU_TT_MAGIC)
|
#define MFU_TT_MAGIC_1A 0x10000000ULL
|
||||||
#define MFU_TT_MAGIC_1B (0x20000000ULL | MFU_TT_MAGIC)
|
#define MFU_TT_MAGIC_1B 0x20000000ULL
|
||||||
#define MFU_TT_MAGIC_NTAG (0x40000000ULL | MFU_TT_MAGIC)
|
#define MFU_TT_MAGIC_NTAG 0x40000000ULL
|
||||||
#define MFU_TT_NTAG_210u 0x80000000ULL
|
#define MFU_TT_NTAG_210u 0x80000000ULL
|
||||||
#define MFU_TT_UL_AES 0x100000000ULL
|
#define MFU_TT_UL_AES 0x100000000ULL
|
||||||
|
#define MFU_TT_MAGIC_2 0x200000000ULL
|
||||||
|
#define MFU_TT_MAGIC_4 0x400000000ULL
|
||||||
|
#define MFU_TT_MAGIC_NTAG21X 0x800000000ULL
|
||||||
#define MFU_TT_UL_MAGIC (MFU_TT_UL | MFU_TT_MAGIC)
|
#define MFU_TT_UL_MAGIC (MFU_TT_UL | MFU_TT_MAGIC)
|
||||||
#define MFU_TT_UL_C_MAGIC (MFU_TT_UL_C | MFU_TT_MAGIC)
|
#define MFU_TT_UL_C_MAGIC (MFU_TT_UL_C | MFU_TT_MAGIC)
|
||||||
// Don't forget to fill UL_TYPES_ARRAY and UL_MEMORY_ARRAY if new types are added
|
// Don't forget to fill UL_TYPES_ARRAY and UL_MEMORY_ARRAY if new types are added
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue