Skip to content

Commit

Permalink
New magic detection
Browse files Browse the repository at this point in the history
Detect TID, SID; UMC, USCUID and others

Signed-off-by: team-orangeBlue <[email protected]>
  • Loading branch information
team-orangeBlue authored Nov 14, 2023
1 parent 8d245c2 commit c21b9fd
Showing 1 changed file with 82 additions and 38 deletions.
120 changes: 82 additions & 38 deletions armsrc/mifarecmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ static uint8_t dummy_answer = 0;

//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// key_auth_cmd is one of MIFARE_AUTH_KEYA, MIFARE_AUTH_KEYB, or MIFARE_MAGIC_GDM_AUTH_KEY
// read_cmd is one of ISO14443A_CMD_READBLOCK, MIFARE_MAGIC_GDM_READBLOCK, or MIFARE_MAGIC_GDM_READ_CFG
// key_auth_cmd is one of MIFARE_AUTH_KEYA, MIFARE_AUTH_KEYB, or MIFARE_MAGIC_USCUID_AUTH_KEY
// read_cmd is one of ISO14443A_CMD_READBLOCK, MIFARE_MAGIC_USCUID_READBLOCK, or MIFARE_MAGIC_USCUID_READ_CFG
// block_data must be 16*count bytes large
// block_no through block_no+count-1 normally needs to be within the same sector
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -127,8 +127,8 @@ int16_t mifare_cmd_readblocks(uint8_t key_auth_cmd, uint8_t *key, uint8_t read_c

//-----------------------------------------------------------------------------
// Select, Authenticate, Write a MIFARE tag.
// key_auth_cmd is one of MIFARE_AUTH_KEYA, MIFARE_AUTH_KEYB, or MIFARE_MAGIC_GDM_AUTH_KEY
// write_cmd is one of ISO14443A_CMD_WRITEBLOCK, MIFARE_MAGIC_GDM_WRITEBLOCK, or MIFARE_MAGIC_GDM_WRITE_CFG
// key_auth_cmd is one of MIFARE_AUTH_KEYA, MIFARE_AUTH_KEYB, or MIFARE_MAGIC_USCUID_AUTH_KEY
// write_cmd is one of ISO14443A_CMD_WRITEBLOCK, MIFARE_MAGIC_USCUID_WRITEBLOCK, or MIFARE_MAGIC_USCUID_WRITE_CFG
// block_data must be 16*count bytes large
// block_no through block_no+count-1 normally needs to be within the same sector
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -2208,7 +2208,9 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) {
//-----------------------------------------------------------------------------
// magic uid card generation 1 commands
static uint8_t wupC1[] = { MIFARE_MAGICWUPC1 };
static uint8_t wupU1[] = { MIFARE_MAGICWUPU1 };
static uint8_t wupC2[] = { MIFARE_MAGICWUPC2 };
//static uint8_t wupU2[] = { MIFARE_MAGICWUPU2 };
static uint8_t wipeC[] = { MIFARE_MAGICWIPEC };

void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) {
Expand Down Expand Up @@ -2418,13 +2420,17 @@ void MifareCIdent(bool is_mfc) {
uint8_t isGen = 0;
uint8_t rec[1] = {0x00};
uint8_t recpar[1] = {0x00};
uint8_t usc_getcfg[4] = {0xE0, 0x00, 0x39, 0xF7};
uint8_t rats[4] = {ISO14443A_CMD_RATS, 0x80, 0x31, 0x73};
uint8_t rdblf0[4] = {ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
uint8_t rdbl00[4] = {ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
uint8_t gen4gdm[4] = {MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92};
uint8_t gen4GetConf[8] = {GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
uint8_t gen4usc[4] = {MIFARE_MAGIC_USCUID_AUTH_KEY, 0x00, 0x6C, 0x92};
uint8_t tidfind[7] = {0x02, 0x00, 0xEC, 0x00, 0x00, 0xdc, 0xba}; // PLEASE warn if this command changes something in the tag. It seems not to.
uint8_t sidfind[8] = {0x02, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x4b, 0xe3};
uint8_t sidfind2[8] = {0x02, 0x00, 0xFB, 0x00, 0x00, 0x00, 0xdb, 0x88};
uint8_t gen4GetVer[8] = {GEN_4UMC_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4UMC_VER, 0, 0};
uint8_t superGen1[9] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};

uint8_t superFurui[18] = {0xAA, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
uint8_t *uid = BigBuf_malloc(10);
Expand All @@ -2445,26 +2451,46 @@ void MifareCIdent(bool is_mfc) {
if (!ReaderReceive(rec, recpar) || (rec[0] != 0x0a)) {
isGen = MAGIC_GEN_1B;
goto OUT;
};
}
ReaderTransmit(usc_getcfg, sizeof(usc_getcfg), NULL);
if (ReaderReceive(rec, recpar) && rec[0] == 0x7A ){
isGen = MAGIC_GEN_4USC; // If we detect a configuration, consider tag as USCUID (even if it is UFUID/...)
goto OUT;
}
isGen = MAGIC_GEN_1A;
goto OUT;
} else {
ReaderTransmitBitsPar(wupU1, 7, NULL, NULL); // send 0x20 command for USCUID chips
if (ReaderReceive(rec, recpar) && (rec[0] == 0x0a)) {
isGen = MAGIC_GEN_4USC; // as there is no "B" variant of USCUID, only 0x20 ACK is sufficient
}

}
// reset card
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);

int res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
// Check for Magic Gen4 GTU with default password:
// Get config should return 30 or 32 bytes
AddCrc14A(gen4GetConf, sizeof(gen4GetConf) - 2);
ReaderTransmit(gen4GetConf, sizeof(gen4GetConf), NULL);
// Find Furui supercard using cloner method
AddCrc14A(superFurui, sizeof(superFurui) - 2);
ReaderTransmit(superFurui, sizeof(superFurui), NULL);
res = ReaderReceive(buf, par);
if (res == 2){
isGen = MAGIC_SUPER_FURUI;
goto OUT;
}
// Check for Ultimate magic with default password:
// Get version should give 5 bytes
AddCrc14A(gen4GetVer, sizeof(gen4GetVer) - 2);
ReaderTransmit(gen4GetVer, sizeof(gen4GetVer), NULL);
res = ReaderReceive(buf, par);
if (res == 32 || res == 34) {
isGen = MAGIC_GEN_4GTU;
goto OUT;
if (memcmp(buf, "\x00\x00\x00\x03\xA0\x34\x8F", 7) == 0){
isGen = MAGIC_GEN_4UMC3;
goto OUT;
} else if (memcmp(buf, "\x00\x00\x00\x06\xA0\x8C\xF1", 7) == 0) {
isGen = MAGIC_GEN_4UMC6;
goto OUT;
}
}

Expand All @@ -2483,6 +2509,25 @@ void MifareCIdent(bool is_mfc) {
ReaderTransmit(rats, sizeof(rats), NULL);
res = ReaderReceive(buf, par);
if (res) {
// Find CPU magic tag (SID/TID)
// As they have ATS based on UID, need to issue APDU
ReaderTransmit(tidfind, sizeof(tidfind), NULL);
res = ReaderReceive(buf, par);
if (memcmp(buf, "\x90\x00\xFD\x07", 4) == 0) { // Must make sure it was a 9000 because FMCOS needs Lc (this doesn't)
isGen = MAGIC_TID;
goto OUT;
}
// Separator
ReaderTransmit(sidfind, sizeof(sidfind), NULL);
res = ReaderReceive(buf, par);
if (res > 9) { // Because it's unknown whether "DEFAULT" can change, we're checking for its presence
ReaderTransmit(sidfind2, sizeof(sidfind2), NULL);
res=ReaderReceive(buf, par);
if (memcmp(buf, "\x6A\x82\x9f\x21", 4) == 0){
isGen = MAGIC_SID;
goto OUT;
}
}
// test for super card
ReaderTransmit(superGen1, sizeof(superGen1), NULL);
res = ReaderReceive(buf, par);
Expand All @@ -2501,7 +2546,6 @@ void MifareCIdent(bool is_mfc) {
if (res == 18) {
isGen = MAGIC_SUPER_GEN2;
}

goto OUT;
}
// test for some MFC gen2
Expand Down Expand Up @@ -2568,34 +2612,34 @@ void MifareCIdent(bool is_mfc) {
}
}

// magic MFC Gen4 GDM test
// magic MFC USCUID test
if (isGen != MAGIC_GEN_3) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
ReaderTransmit(gen4gdm, sizeof(gen4gdm), NULL);
ReaderTransmit(gen4usc, sizeof(gen4usc), NULL);
res = ReaderReceive(buf, par);
if (res == 4) {
isGen = MAGIC_GEN_4GDM;
isGen = MAGIC_GEN_4USC;
}
}

if (isGen != MAGIC_GEN_4GDM) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
if (mifare_classic_authex(pcs, cuid, 68, MF_KEY_B, 0x707B11FC1481, AUTH_FIRST, NULL, NULL) == 0) {
isGen = MAGIC_QL88;
}
crypto1_deinit(pcs);
}
if (isGen != MAGIC_GEN_4USC) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
if (mifare_classic_authex(pcs, cuid, 68, MF_KEY_B, 0x707B11FC1481, AUTH_FIRST, NULL, NULL) == 0) {
isGen = MAGIC_QL88;
}
crypto1_deinit(pcs);
}
}
}

Expand Down Expand Up @@ -2879,7 +2923,7 @@ void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd, uint8_t workFlags) {
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
}

uint8_t cmd[] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_READ, blockno,
uint8_t cmd[] = { GEN_4UMC_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4UMC_READ, blockno,
0x00, 0x00
};

Expand All @@ -2898,7 +2942,7 @@ void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd, uint8_t workFlags) {
LED_B_OFF();

OUT:
reply_ng(CMD_HF_MIFARE_G4_RDBL, retval, buf, res);
reply_ng(CMD_HF_MIFARE_UMC_RDBL, retval, buf, res);
// turns off
if (done || retval != 0) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
Expand Down Expand Up @@ -2955,7 +2999,7 @@ void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t work
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
}

uint8_t cmd[] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_WRITE, blockno,
uint8_t cmd[] = { GEN_4UMC_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4UMC_WRITE, blockno,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
Expand All @@ -2977,7 +3021,7 @@ void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t work
LED_B_OFF();

OUT:
reply_ng(CMD_HF_MIFARE_G4_WRBL, retval, buf, res);
reply_ng(CMD_HF_MIFARE_UMC_WRBL, retval, buf, res);
// turns off
if (done || retval != 0) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
Expand Down

0 comments on commit c21b9fd

Please sign in to comment.