adapt some detection of fudan

This commit is contained in:
iceman1001 2024-04-22 19:52:24 +02:00
commit 934a969d41
6 changed files with 156 additions and 44 deletions

View file

@ -435,6 +435,8 @@ static int CmdrevengSearch(const char *Cmd) {
return 0; return 0;
} }
str_lower(inHexStr);
// try each model and get result // try each model and get result
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
/*if (found) { /*if (found) {
@ -479,16 +481,21 @@ static int CmdrevengSearch(const char *Cmd) {
ans = RunModel(Models[i], outHex, false, 0, result); ans = RunModel(Models[i], outHex, false, 0, result);
if (ans) { if (ans) {
str_lower(result);
// test for match // test for match
if (memcmp(result, inCRC, crcChars) == 0) { if (memcmp(result, inCRC, crcChars) == 0) {
PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value: %s\n", Models[i], result); PrintAndLogEx(SUCCESS, "model... " _YELLOW_("%s"), Models[i]);
PrintAndLogEx(SUCCESS, "value... %s\n", result);
//optional - stop searching if found... //optional - stop searching if found...
found = true; found = true;
} else { } else {
if (crcChars > 2) { if (crcChars > 2) {
char *swapEndian = SwapEndianStr(result, crcChars, crcChars); char *swapEndian = SwapEndianStr(result, crcChars, crcChars);
if (memcmp(swapEndian, inCRC, crcChars) == 0) { if (memcmp(swapEndian, inCRC, crcChars) == 0) {
PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value endian swapped: %s\n", Models[i], swapEndian); PrintAndLogEx(SUCCESS, "model... " _YELLOW_("%s"), Models[i]);
PrintAndLogEx(SUCCESS, "value endian swapped... %s\n", swapEndian);
// optional - stop searching if found... // optional - stop searching if found...
found = true; found = true;
} }
@ -498,16 +505,20 @@ static int CmdrevengSearch(const char *Cmd) {
} }
ans = RunModel(Models[i], outHex, true, 0, revResult); ans = RunModel(Models[i], outHex, true, 0, revResult);
if (ans) { if (ans) {
str_lower(revResult);
// test for match // test for match
if (memcmp(revResult, inCRC, crcChars) == 0) { if (memcmp(revResult, inCRC, crcChars) == 0) {
PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value: %s\n", Models[i], revResult); PrintAndLogEx(SUCCESS, "model reversed... " _YELLOW_("%s"), Models[i]);
PrintAndLogEx(SUCCESS, "value... %s\n", revResult);
// optional - stop searching if found... // optional - stop searching if found...
found = true; found = true;
} else { } else {
if (crcChars > 2) { if (crcChars > 2) {
char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars); char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars);
if (memcmp(swapEndian, inCRC, crcChars) == 0) { if (memcmp(swapEndian, inCRC, crcChars) == 0) {
PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value endian swapped: %s\n", Models[i], swapEndian); PrintAndLogEx(SUCCESS, "model reversed... " _YELLOW_("%s"), Models[i]);
PrintAndLogEx(SUCCESS, "value endian swapped... %s\n", swapEndian);
// optional - stop searching if found... // optional - stop searching if found...
found = true; found = true;
} }
@ -520,9 +531,9 @@ static int CmdrevengSearch(const char *Cmd) {
free(Models[i]); free(Models[i]);
} }
if (found == false) if (found == false) {
PrintAndLogEx(FAILED, "\nno matches found\n"); PrintAndLogEx(FAILED, "\nno matches found\n");
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -991,7 +991,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
// CRC Check // CRC Check
if (iLen == -1) { if (iLen == -1) {
if (silentMode == false) { if (silentMode == false) {
PrintAndLogEx(ERR, "ISO 14443A CRC error."); PrintAndLogEx(ERR, "ISO 14443A CRC error");
} }
return PM3_ECRC; return PM3_ECRC;
} }
@ -1665,23 +1665,85 @@ static void printTag(const char *tag) {
PrintAndLogEx(SUCCESS, " " _YELLOW_("%s"), tag); PrintAndLogEx(SUCCESS, " " _YELLOW_("%s"), tag);
} }
typedef enum { int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) {
MTNONE = 0,
MTCLASSIC = 1, int type = MTNONE;
MTMINI = 2,
MTDESFIRE = 4, if ((sak & 0x02) != 0x02) {
MTPLUS = 8, if ((sak & 0x19) == 0x19) {
MTULTRALIGHT = 16, type |= MTCLASSIC;
HID_SEOS = 32, } else if ((sak & 0x40) == 0x40) {
MTOTHER = 64, type |= MTISO18092;
MTEMV = 128, } else if ((sak & 0x38) == 0x38) {
MTFUDAN = 256, type |= MTCLASSIC;
MTISO18092 = 512, } else if ((sak & 0x18) == 0x18) {
MT424 = 1024, if (select_status == 1) {
} nxp_mifare_type_t; type |= MTPLUS;
} else {
type |= MTCLASSIC;
}
} else if ((sak & 0x09) == 0x09) {
type |= MTMINI;
} else if ((sak & 0x28) == 0x28) {
type |= MTCLASSIC;
} else if ((sak & 0x08) == 0x08) {
if (select_status == 1) {
type |= MTPLUS;
} else {
type |= MTCLASSIC;
}
} else if ((sak & 0x11) == 0x11) {
type |= MTPLUS;
} else if ((sak & 0x10) == 0x10) {
type |= MTPLUS;
} else if ((sak & 0x01) == 0x01) {
type |= MTCLASSIC;
} else if ((sak & 0x24) == 0x24) {
type |= MTDESFIRE;
} else if ((sak & 0x20) == 0x20) {
if (select_status == 1) {
if ((atqa & 0x0040) == 0x0040) {
if ((atqa & 0x0300) == 0x0300) {
type |= MTDESFIRE;
} else {
type |= MTPLUS;
}
} else {
if ((atqa & 0x0001) == 0x0001) {
type |= HID_SEOS;
} else {
type |= MTPLUS;
}
if ((atqa & 0x0004) == 0x0004) {
type |= MTEMV;
}
}
type |= (MTDESFIRE | MT424);
}
} else if ((sak & 0x04) == 0x04) {
type |= MTDESFIRE;
} else {
type |= MTULTRALIGHT;
}
} else if ((sak & 0x0A) == 0x0A) {
if ((atqa & 0x0003) == 0x0003) {
type |= MTFUDAN;
} else if ((atqa & 0x0005) == 0x0005) {
type |= MTFUDAN;
}
} else if ((sak & 0x53) == 0x53) {
type |= MTFUDAN;
}
return type;
}
// Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1 // Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1
static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) { static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_status) {
int type = MTNONE; int type = MTNONE;
PrintAndLogEx(SUCCESS, "Possible types:"); PrintAndLogEx(SUCCESS, "Possible types:");
@ -1829,7 +1891,7 @@ static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) {
printTag("FM11RF005SH (FUDAN Shanghai Metro)"); printTag("FM11RF005SH (FUDAN Shanghai Metro)");
type |= MTFUDAN; type |= MTFUDAN;
} else if ((atqa & 0x0005) == 0x0005) { } else if ((atqa & 0x0005) == 0x0005) {
printTag("FM11RF005M (FUDAN MIFARE Classic clone)"); printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)");
type |= MTFUDAN; type |= MTFUDAN;
} }
} else if ((sak & 0x53) == 0x53) { } else if ((sak & 0x53) == 0x53) {
@ -2007,6 +2069,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]);
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]); PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
bool isMifareMini = false;
bool isMifareClassic = true; bool isMifareClassic = true;
bool isMifareDESFire = false; bool isMifareDESFire = false;
bool isMifarePlus = false; bool isMifarePlus = false;
@ -2020,8 +2083,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
int nxptype = MTNONE; int nxptype = MTNONE;
if (card.uidlen <= 4) { if (card.uidlen <= 4) {
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); nxptype = detect_nxp_card_print(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status);
isMifareMini = ((nxptype & MTMINI) == MTMINI);
isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC); isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC);
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE); isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
isMifarePlus = ((nxptype & MTPLUS) == MTPLUS); isMifarePlus = ((nxptype & MTPLUS) == MTPLUS);
@ -2046,8 +2110,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
isMifareClassic = false; isMifareClassic = false;
break; break;
case 0x04: // NXP case 0x04: // NXP
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); nxptype = detect_nxp_card_print(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status);
isMifareMini = ((nxptype & MTMINI) == MTMINI);
isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC); isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC);
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE); isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
isMifarePlus = ((nxptype & MTPLUS) == MTPLUS); isMifarePlus = ((nxptype & MTPLUS) == MTPLUS);
@ -2136,7 +2201,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} else if (card.atqa[0] == 0x05) { } else if (card.atqa[0] == 0x05) {
// Uses MIFARE Crypto-1 algo // Uses MIFARE Crypto-1 algo
printTag("FM11RF005M (FUDAN MIFARE Classic clone)"); printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)");
} }
break; break;
} }
@ -2383,10 +2448,13 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} else { } else {
if (card.ats[pos] == 0x80 || card.ats[pos] == 0x00) { if (card.ats[pos] == 0x80 || card.ats[pos] == 0x00) {
PrintAndLogEx(SUCCESS, " %s (compact TLV data object)", sprint_hex_inrow(&card.ats[pos], calen)); PrintAndLogEx(SUCCESS, "%s (compact TLV data object)", sprint_hex_inrow(&card.ats[pos], calen));
get_compact_tlv(card.ats + pos, calen); get_compact_tlv(card.ats + pos, calen);
} else { } else {
PrintAndLogEx(SUCCESS, " %s", sprint_hex_inrow(card.ats + pos, calen)); PrintAndLogEx(SUCCESS, "%s - %s"
, sprint_hex_inrow(card.ats + pos, calen)
, sprint_ascii(card.ats + pos, calen)
);
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
@ -2495,7 +2563,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
uint16_t isMagic = 0; uint16_t isMagic = 0;
if (isMifareClassic) { if (isMifareClassic || isMifareMini) {
isMagic = detect_mf_magic(true, MF_KEY_B, 0xFFFFFFFFFFFF); isMagic = detect_mf_magic(true, MF_KEY_B, 0xFFFFFFFFFFFF);
} }
@ -2503,7 +2571,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
isMagic = detect_mf_magic(false, MF_KEY_A, 0); isMagic = detect_mf_magic(false, MF_KEY_A, 0);
} }
if (isMifareClassic) { if (isMifareClassic || isMifareMini) {
int res = detect_classic_static_nonce(); int res = detect_classic_static_nonce();
if (res == NONCE_STATIC) { if (res == NONCE_STATIC) {
PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes")); PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes"));
@ -2594,7 +2662,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("hf ntag424 info") "`"); PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("hf ntag424 info") "`");
} }
if (isMifareClassic) { if (isMifareClassic || isMifareMini) {
if (((isMagic & MAGIC_FLAG_GEN_1A) == MAGIC_FLAG_GEN_1A) || ((isMagic & MAGIC_FLAG_GEN_1B) == MAGIC_FLAG_GEN_1B)) { if (((isMagic & MAGIC_FLAG_GEN_1A) == MAGIC_FLAG_GEN_1A) || ((isMagic & MAGIC_FLAG_GEN_1B) == MAGIC_FLAG_GEN_1B)) {
PrintAndLogEx(HINT, "Hint: use `" _YELLOW_("hf mf c*") "` magic commands"); PrintAndLogEx(HINT, "Hint: use `" _YELLOW_("hf mf c*") "` magic commands");

View file

@ -36,6 +36,21 @@ typedef struct {
const char *hint; const char *hint;
} hintAIDList_t; } hintAIDList_t;
typedef enum {
MTNONE = 0,
MTCLASSIC = 1,
MTMINI = 2,
MTDESFIRE = 4,
MTPLUS = 8,
MTULTRALIGHT = 16,
HID_SEOS = 32,
MTOTHER = 64,
MTEMV = 128,
MTFUDAN = 256,
MTISO18092 = 512,
MT424 = 1024,
} nxp_mifare_type_t;
int CmdHF14A(const char *Cmd); int CmdHF14A(const char *Cmd);
int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff
int CmdHF14ASim(const char *Cmd); // used by hf mfu sim int CmdHF14ASim(const char *Cmd); // used by hf mfu sim
@ -43,6 +58,8 @@ int CmdHF14ANdefRead(const char *Cmd); // used by cmdnfc.c
int CmdHF14ANdefFormat(const char *Cmd); // used by cmdnfc.c int CmdHF14ANdefFormat(const char *Cmd); // used by cmdnfc.c
int CmdHF14ANdefWrite(const char *Cmd); // used by cmdnfc.c int CmdHF14ANdefWrite(const char *Cmd); // used by cmdnfc.c
int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status);
int hf14a_getconfig(hf14a_config *config); int hf14a_getconfig(hf14a_config *config);
int hf14a_setconfig(hf14a_config *config, bool verbose); int hf14a_setconfig(hf14a_config *config, bool verbose);
int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search); int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search);

View file

@ -32,7 +32,7 @@
#include "crapto1/crapto1.h" // prng_successor #include "crapto1/crapto1.h" // prng_successor
#include "commonutil.h" // num_to_bytes #include "commonutil.h" // num_to_bytes
#include "util_posix.h" // msclock #include "util_posix.h" // msclock
#include "ui.h" // searchhomedirectory #include "ui.h" // search home directory
#include "proxgui.h" // Picture Window #include "proxgui.h" // Picture Window
// Max file size in bytes. Used in several places. // Max file size in bytes. Used in several places.

View file

@ -1419,8 +1419,9 @@ static int CmdHF14aDesChk(const char *Cmd) {
} }
if (pattern2b && startPattern < 0x10000) { if (pattern2b && startPattern < 0x10000) {
if (verbose == false) if (verbose == false) {
PrintAndLogEx(NORMAL, "p" NOLF); PrintAndLogEx(NORMAL, "p" NOLF);
}
aeskeyListLen = 0; aeskeyListLen = 0;
deskeyListLen = 0; deskeyListLen = 0;
@ -1430,29 +1431,34 @@ static int CmdHF14aDesChk(const char *Cmd) {
} }
if (dict_filenamelen) { if (dict_filenamelen) {
if (verbose == false) if (verbose == false) {
PrintAndLogEx(NORMAL, "d" NOLF); PrintAndLogEx(NORMAL, "d" NOLF);
}
uint32_t keycnt = 0; uint32_t keycnt = 0;
res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false);
if (res == PM3_SUCCESS && endFilePosition) if (res == PM3_SUCCESS && endFilePosition) {
deskeyListLen = keycnt; deskeyListLen = keycnt;
}
keycnt = 0; keycnt = 0;
res = loadFileDICTIONARYEx((char *)dict_filename, aeskeyList, sizeof(aeskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); res = loadFileDICTIONARYEx((char *)dict_filename, aeskeyList, sizeof(aeskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false);
if (res == PM3_SUCCESS && endFilePosition) if (res == PM3_SUCCESS && endFilePosition) {
aeskeyListLen = keycnt; aeskeyListLen = keycnt;
}
keycnt = 0; keycnt = 0;
res = loadFileDICTIONARYEx((char *)dict_filename, k3kkeyList, sizeof(k3kkeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); res = loadFileDICTIONARYEx((char *)dict_filename, k3kkeyList, sizeof(k3kkeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false);
if (res == PM3_SUCCESS && endFilePosition) if (res == PM3_SUCCESS && endFilePosition) {
k3kkeyListLen = keycnt; k3kkeyListLen = keycnt;
}
continue; continue;
} }
} }
if (verbose == false) if (verbose == false) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
}
// save keys to json // save keys to json
if ((jsonnamelen > 0) && result) { if ((jsonnamelen > 0) && result) {
@ -4848,13 +4854,15 @@ static int DesfileReadFileAndPrint(DesfireContext_t *dctx,
PrintAndLogEx(WARNING, "File needs to be authenticated with key 0x%02x or 0x%02x but current authentication key is 0x%02x", fsettings.rAccess, fsettings.rwAccess, dctx->keyNum); PrintAndLogEx(WARNING, "File needs to be authenticated with key 0x%02x or 0x%02x but current authentication key is 0x%02x", fsettings.rAccess, fsettings.rwAccess, dctx->keyNum);
if (fsettings.rAccess == 0x0f && fsettings.rwAccess == 0x0f) if (fsettings.rAccess == 0x0f && fsettings.rwAccess == 0x0f)
PrintAndLogEx(WARNING, "File access denied. All read access rights is 0x0f."); PrintAndLogEx(WARNING, "File access denied. All read access rights is 0x0F");
if (verbose) if (verbose) {
PrintAndLogEx(INFO, "Got file type: %s. Option: %s. comm mode: %s", PrintAndLogEx(INFO, _CYAN_("File type:") " %s Option: %s comm mode: %s",
GetDesfireFileType(fsettings.fileType), GetDesfireFileType(fsettings.fileType),
CLIGetOptionListStr(DesfireReadFileTypeOpts, filetype), CLIGetOptionListStr(DesfireReadFileTypeOpts, filetype),
CLIGetOptionListStr(DesfireCommunicationModeOpts, fsettings.commMode)); CLIGetOptionListStr(DesfireCommunicationModeOpts, fsettings.commMode)
);
}
} else { } else {
PrintAndLogEx(WARNING, "GetFileSettings error. Can't get file type."); PrintAndLogEx(WARNING, "GetFileSettings error. Can't get file type.");
} }

View file

@ -829,8 +829,16 @@ static int CmdHFTopazSniff(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
uint8_t param = 0; uint8_t param = 0;
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort sniffing");
SendCommandNG(CMD_HF_ISO14443A_SNIFF, (uint8_t *)&param, sizeof(uint8_t)); SendCommandNG(CMD_HF_ISO14443A_SNIFF, (uint8_t *)&param, sizeof(uint8_t));
PacketResponseNG resp;
WaitForResponse(CMD_HF_ISO14443A_SNIFF, &resp);
PrintAndLogEx(INFO, "Done!");
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf topaz list")"` to view captured tracelog");
PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing");
return PM3_SUCCESS; return PM3_SUCCESS;
} }