Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Magic gen 3 cards support
  • Loading branch information
McEloff committed Sep 5, 2020
1 parent 7904d96 commit 70be7ef
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...

## [unreleased][unreleased]
- Added `hf mf gen3*`magic gen 3 card operations (@McEloff)
- Readded verichip command which seems missing (@iceman1001)
- Fix missing t55x7 config block detection (@iceman1001)
- Fix missing define on proxspace (@mwalker33)
Expand Down
13 changes: 13 additions & 0 deletions armsrc/appmain.c
Expand Up @@ -1318,6 +1318,19 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareCIdent();
break;
}
// Gen 3 magic cards
case CMD_HF_MIFARE_GEN3UID: {
MifareGen3UID(packet->oldarg[0], packet->data.asBytes);
break;
}
case CMD_HF_MIFARE_GEN3BLK: {
MifareGen3Blk(packet->oldarg[0], packet->data.asBytes);
break;
}
case CMD_HF_MIFARE_GEN3FREEZ: {
MifareGen3Freez();
break;
}
// mifare sniffer
// case CMD_HF_MIFARE_SNIFF: {
// SniffMifare(packet->oldarg[0]);
Expand Down
148 changes: 148 additions & 0 deletions armsrc/mifarecmd.c
Expand Up @@ -2319,6 +2319,154 @@ void OnErrorMagic(uint8_t reason) {
OnSuccessMagic();
}

int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len) {
int retval = PM3_SUCCESS;
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);

LED_B_ON();
uint32_t save_iso14a_timeout = iso14a_get_timeout();
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 2000); // 2 seconds timeout

ReaderTransmit(cmd, cmd_len, NULL);
int res = ReaderReceive(buf, par);
if (res == 4 || memcmp(buf, "\x90\x00\xfd\x07", 4) == 0) {
// timeout for card memory reset
SpinDelay(1000);
} else {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card operation not completed");
retval = PM3_ESOFT;
}
iso14a_set_timeout(save_iso14a_timeout);
LED_B_OFF();

return retval;
}

void MifareGen3UID(uint8_t uidlen, uint8_t *uid) {
int retval = PM3_SUCCESS;
uint8_t uid_cmd[5] = { 0x90, 0xfb, 0xcc, 0xcc, 0x07 };
uint8_t *old_uid = BigBuf_malloc(10);
uint8_t *cmd = BigBuf_malloc(sizeof(uid_cmd) + uidlen + 2);
iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t));

iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);

if (!iso14443a_select_card(old_uid, card_info, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
retval = PM3_ESOFT;
goto OUT;
}
if (card_info->uidlen != uidlen) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID length");
retval = PM3_ESOFT;
goto OUT;
}

memcpy(cmd, uid_cmd, sizeof(uid_cmd));
memcpy(&cmd[sizeof(uid_cmd)], uid, uidlen);
AddCrc14A(cmd, sizeof(uid_cmd) + uidlen);

retval = DoGen3Cmd(cmd, sizeof(uid_cmd) + uidlen + 2);

OUT:
reply_ng(CMD_HF_MIFARE_GEN3UID, retval, old_uid, uidlen);
// turns off
OnSuccessMagic();
BigBuf_free();
}

void MifareGen3Blk(uint8_t block_len, uint8_t *block) {
#define MIFARE_BLOCK_SIZE (MAX_MIFARE_FRAME_SIZE - 2)
int retval = PM3_SUCCESS;
uint8_t block_cmd[5] = { 0x90, 0xf0, 0xcc, 0xcc, 0x10 };
uint8_t *uid = BigBuf_malloc(10);
uint8_t *cmd = BigBuf_malloc(sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE);
iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t));

iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);

if (!iso14443a_select_card(uid, card_info, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
retval = PM3_ESOFT;
goto OUT;
}

bool doReselect = false;
if (block_len < MIFARE_BLOCK_SIZE) {
if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, 0, &cmd[sizeof(block_cmd)], NULL, NULL) != MAX_MIFARE_FRAME_SIZE)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read manufacturer block failed");
retval = PM3_ESOFT;
goto OUT;
}
doReselect = true;
}

if (block_len > 0) {
memcpy(cmd, block_cmd, sizeof(block_cmd));
memcpy(&cmd[sizeof(block_cmd)], block, block_len);
int ofs = sizeof(block_cmd);
if (card_info->uidlen == 4) {
cmd[ofs + 4] = cmd[ofs + 0] ^ cmd[ofs + 1] ^ cmd[ofs + 2] ^ cmd[ofs + 3];
ofs += 5;
} else if (card_info->uidlen == 7) {
ofs += 7;
} else {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong Card UID length");
retval = PM3_ESOFT;
goto OUT;
}
cmd[ofs++] = card_info->sak;
cmd[ofs++] = card_info->atqa[0];
cmd[ofs++] = card_info->atqa[1];
AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE);

if (doReselect) {
if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
retval = PM3_ESOFT;
goto OUT;
}
}

retval = DoGen3Cmd(cmd, sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE);
}

OUT:
reply_ng(CMD_HF_MIFARE_GEN3BLK, retval, &cmd[sizeof(block_cmd)], MIFARE_BLOCK_SIZE);
// turns off
OnSuccessMagic();
BigBuf_free();
}

void MifareGen3Freez(void) {
int retval = PM3_SUCCESS;
uint8_t freeze_cmd[7] = { 0x90, 0xfd, 0x11, 0x11, 0x00, 0xe7, 0x91 };
uint8_t *uid = BigBuf_malloc(10);

iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);

if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
retval = PM3_ESOFT;
goto OUT;
}

retval = DoGen3Cmd(freeze_cmd, sizeof(freeze_cmd));

OUT:
reply_ng(CMD_HF_MIFARE_GEN3FREEZ, retval, NULL, 0);
// turns off
OnSuccessMagic();
BigBuf_free();
}

void MifareSetMod(uint8_t *datain) {

uint8_t mod = datain[0];
Expand Down
5 changes: 5 additions & 0 deletions armsrc/mifarecmd.h
Expand Up @@ -44,6 +44,11 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
void MifareCIdent(void); // is "magic chinese" card?
void MifareHasStaticNonce(void); // Has the tag a static nonce?

int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len);
void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID without manufacturer block
void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overwrite manufacturer block
void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes

void MifareSetMod(uint8_t *datain);
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);

Expand Down
109 changes: 109 additions & 0 deletions client/src/cmdhfmf.c
Expand Up @@ -500,6 +500,48 @@ static int usage_hf14_nack(void) {
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf nack"));
return PM3_SUCCESS;
}
static int usage_hf14_gen3uid(void) {
PrintAndLogEx(NORMAL, "Set UID for magic GEN 3 card without manufacturer block changing");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: hf mf gen3uid [h] <uid>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " <uid> UID 8/14 hex symbols");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304050607"));
return PM3_SUCCESS;
}
static int usage_hf14_gen3blk(void) {
PrintAndLogEx(NORMAL, "Overwrite full manufacturer block for magic GEN 3 card");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: hf mf gen3blk [h] [block data (up to 32 hex symbols)]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " [block] manufacturer block data up to 32 hex symbols to write");
PrintAndLogEx(NORMAL, " - If block data not specified, it prints current");
PrintAndLogEx(NORMAL, " data without changes");
PrintAndLogEx(NORMAL, " - You can specify part of manufacturer block as");
PrintAndLogEx(NORMAL, " 4/7-bytes for UID change only for example");
PrintAndLogEx(NORMAL, " NOTE: BCC, SAK, ATQA will be calculated automatically");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304FFFFFFFF0102030405060708"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304050607"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk"));
return PM3_SUCCESS;
}
static int usage_hf14_gen3freez(void) {
PrintAndLogEx(NORMAL, "Lock further UID changes. No more UID changes available after operation completed");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: hf mf gen3freez [h] <Y>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " <Y> confirm UID locks operation");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3freez Y"));
return PM3_SUCCESS;
}

static int GetHFMF14AUID(uint8_t *uid, int *uidlen) {
clearCommandBuffer();
Expand Down Expand Up @@ -5086,6 +5128,69 @@ static int CmdHF14AMfList(const char *Cmd) {
return CmdTraceList("mf");
}

static int CmdHf14AGen3UID(const char *Cmd) {
uint8_t uid[7] = {0x00};
uint8_t oldUid[10] = {0x00};
uint8_t uidlen;

char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_hf14_gen3uid();

if (param_gethex(Cmd, 0, uid, 8))
if (param_gethex(Cmd, 0, uid, 14))
return usage_hf14_gen3uid();
else
uidlen = 7;
else
uidlen = 4;

int res = mfGen3UID(uid, uidlen, oldUid);
if (res) {
PrintAndLogEx(ERR, "Can't set UID. Error=%d", res);
return PM3_ESOFT;
}

PrintAndLogEx(SUCCESS, "Old UID : %s", sprint_hex(oldUid, uidlen));
PrintAndLogEx(SUCCESS, "New UID : %s", sprint_hex(uid, uidlen));
return PM3_SUCCESS;
}

static int CmdHf14AGen3Blk(const char *Cmd) {
uint8_t block[16] = {0x00};
int blocklen = 0;
uint8_t newBlock[16] = {0x00};

char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_hf14_gen3blk();

if (ctmp != '\0' && param_gethex_to_eol(Cmd, 0, block, sizeof(block), &blocklen))
return usage_hf14_gen3blk();

int res = mfGen3Blk(block, blocklen, newBlock);
if (res) {
PrintAndLogEx(ERR, "Can't change manufacturer block data. Error=%d", res);
return PM3_ESOFT;
}

PrintAndLogEx(SUCCESS, "Current Block : %s", sprint_hex(newBlock, 16));
return PM3_SUCCESS;
}

static int CmdHf14AGen3Freez(const char *Cmd) {
char ctmp = param_getchar(Cmd, 0);
if (tolower(ctmp) == 'h') return usage_hf14_gen3freez();
if (ctmp != 'Y') return usage_hf14_gen3freez();

int res = mfGen3Freez();
if (res) {
PrintAndLogEx(ERR, "Can't lock UID changes. Error=%d", res);
return PM3_ESOFT;
}

PrintAndLogEx(SUCCESS, "Gen 3 UID locked");
return PM3_SUCCESS;
}

static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"},
Expand Down Expand Up @@ -5131,6 +5236,10 @@ static command_t CommandTable[] = {
{"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump (magic chinese card)"},
{"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from magic chinese card into file or emulator"},
{"cview", CmdHF14AMfCView, IfPm3Iso14443a, "view card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3") " -----------------------"},
{"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without manufacturer block (magic gen3 card)"},
{"gen3blk", CmdHf14AGen3Blk, IfPm3Iso14443a, "Overwrite full manufacturer block (magic gen 3 card)"},
{"gen3freez", CmdHf14AGen3Freez, IfPm3Iso14443a, "Lock further UID changes (magic gen 3 card)"},

{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"},
{"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
Expand Down
42 changes: 42 additions & 0 deletions client/src/mifare/mifarehost.c
Expand Up @@ -944,6 +944,48 @@ int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) {
return PM3_SUCCESS;
}

int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid) {
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_GEN3UID, uidlen, 0, 0, uid, uidlen);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3UID, &resp, 3500)) {
if (resp.status == PM3_SUCCESS && oldUid) {
memcpy(oldUid, resp.data.asBytes, uidlen);
}
return resp.status;
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
return PM3_ETIMEOUT;
}
}

int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock) {
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_GEN3BLK, blockLen, 0, 0, block, 16);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3BLK, &resp, 3500)) {
if (resp.status == PM3_SUCCESS && newBlock) {
memcpy(newBlock, resp.data.asBytes, 16);
}
return resp.status;
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
return PM3_ETIMEOUT;
}
}

int mfGen3Freez(void) {
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_GEN3FREEZ, NULL, 0);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3FREEZ, &resp, 3500)) {
return resp.status;
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
return PM3_ETIMEOUT;
}
}

// SNIFFER
// [iceman] so many global variables....

Expand Down
4 changes: 4 additions & 0 deletions client/src/mifare/mifarehost.h
Expand Up @@ -80,6 +80,10 @@ int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak);
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);

int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid);
int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock);
int mfGen3Freez(void);

int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);

int detect_classic_prng(void);
Expand Down
5 changes: 5 additions & 0 deletions include/pm3_cmd.h
Expand Up @@ -648,6 +648,11 @@ typedef struct {
//For Atmel CryptoRF
#define CMD_HF_CRYPTORF_SIM 0x0820

// Gen 3 magic cards
#define CMD_HF_MIFARE_GEN3UID 0x0850
#define CMD_HF_MIFARE_GEN3BLK 0x0851
#define CMD_HF_MIFARE_GEN3FREEZ 0x0852

#define CMD_UNKNOWN 0xFFFF

//Mifare simulation flags
Expand Down

0 comments on commit 70be7ef

Please sign in to comment.