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;
}
str_lower(inHexStr);
// try each model and get result
for (int i = 0; i < count; i++) {
/*if (found) {
@ -479,16 +481,21 @@ static int CmdrevengSearch(const char *Cmd) {
ans = RunModel(Models[i], outHex, false, 0, result);
if (ans) {
str_lower(result);
// test for match
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...
found = true;
} else {
if (crcChars > 2) {
char *swapEndian = SwapEndianStr(result, crcChars, crcChars);
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...
found = true;
}
@ -498,16 +505,20 @@ static int CmdrevengSearch(const char *Cmd) {
}
ans = RunModel(Models[i], outHex, true, 0, revResult);
if (ans) {
str_lower(revResult);
// test for match
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...
found = true;
} else {
if (crcChars > 2) {
char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars);
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...
found = true;
}
@ -520,9 +531,9 @@ static int CmdrevengSearch(const char *Cmd) {
free(Models[i]);
}
if (found == false)
if (found == false) {
PrintAndLogEx(FAILED, "\nno matches found\n");
}
return PM3_SUCCESS;
}

View file

@ -991,7 +991,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
// CRC Check
if (iLen == -1) {
if (silentMode == false) {
PrintAndLogEx(ERR, "ISO 14443A CRC error.");
PrintAndLogEx(ERR, "ISO 14443A CRC error");
}
return PM3_ECRC;
}
@ -1665,23 +1665,85 @@ static void printTag(const char *tag) {
PrintAndLogEx(SUCCESS, " " _YELLOW_("%s"), tag);
}
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 detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) {
int type = MTNONE;
if ((sak & 0x02) != 0x02) {
if ((sak & 0x19) == 0x19) {
type |= MTCLASSIC;
} else if ((sak & 0x40) == 0x40) {
type |= MTISO18092;
} else if ((sak & 0x38) == 0x38) {
type |= MTCLASSIC;
} else if ((sak & 0x18) == 0x18) {
if (select_status == 1) {
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
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;
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)");
type |= MTFUDAN;
} else if ((atqa & 0x0005) == 0x0005) {
printTag("FM11RF005M (FUDAN MIFARE Classic clone)");
printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)");
type |= MTFUDAN;
}
} 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, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
bool isMifareMini = false;
bool isMifareClassic = true;
bool isMifareDESFire = false;
bool isMifarePlus = false;
@ -2020,8 +2083,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
int nxptype = MTNONE;
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);
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
isMifarePlus = ((nxptype & MTPLUS) == MTPLUS);
@ -2046,8 +2110,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
isMifareClassic = false;
break;
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);
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
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) {
// Uses MIFARE Crypto-1 algo
printTag("FM11RF005M (FUDAN MIFARE Classic clone)");
printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)");
}
break;
}
@ -2383,10 +2448,13 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} else {
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);
} 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, "");
@ -2495,7 +2563,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
uint16_t isMagic = 0;
if (isMifareClassic) {
if (isMifareClassic || isMifareMini) {
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);
}
if (isMifareClassic) {
if (isMifareClassic || isMifareMini) {
int res = detect_classic_static_nonce();
if (res == NONCE_STATIC) {
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") "`");
}
if (isMifareClassic) {
if (isMifareClassic || isMifareMini) {
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");

View file

@ -36,6 +36,21 @@ typedef struct {
const char *hint;
} 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 CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff
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 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_setconfig(hf14a_config *config, bool verbose);
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 "commonutil.h" // num_to_bytes
#include "util_posix.h" // msclock
#include "ui.h" // searchhomedirectory
#include "ui.h" // search home directory
#include "proxgui.h" // Picture Window
// 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 (verbose == false)
if (verbose == false) {
PrintAndLogEx(NORMAL, "p" NOLF);
}
aeskeyListLen = 0;
deskeyListLen = 0;
@ -1430,29 +1431,34 @@ static int CmdHF14aDesChk(const char *Cmd) {
}
if (dict_filenamelen) {
if (verbose == false)
if (verbose == false) {
PrintAndLogEx(NORMAL, "d" NOLF);
}
uint32_t keycnt = 0;
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;
}
keycnt = 0;
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;
}
keycnt = 0;
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;
}
continue;
}
}
if (verbose == false)
if (verbose == false) {
PrintAndLogEx(NORMAL, "");
}
// save keys to json
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);
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)
PrintAndLogEx(INFO, "Got file type: %s. Option: %s. comm mode: %s",
GetDesfireFileType(fsettings.fileType),
CLIGetOptionListStr(DesfireReadFileTypeOpts, filetype),
CLIGetOptionListStr(DesfireCommunicationModeOpts, fsettings.commMode));
if (verbose) {
PrintAndLogEx(INFO, _CYAN_("File type:") " %s Option: %s comm mode: %s",
GetDesfireFileType(fsettings.fileType),
CLIGetOptionListStr(DesfireReadFileTypeOpts, filetype),
CLIGetOptionListStr(DesfireCommunicationModeOpts, fsettings.commMode)
);
}
} else {
PrintAndLogEx(WARNING, "GetFileSettings error. Can't get file type.");
}

View file

@ -829,8 +829,16 @@ static int CmdHFTopazSniff(const char *Cmd) {
CLIParserFree(ctx);
uint8_t param = 0;
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort sniffing");
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;
}