added support for the magic card called GDM.

This commit is contained in:
iceman1001 2023-03-21 19:49:52 +01:00
commit 07f6162780
10 changed files with 205 additions and 11 deletions

View file

@ -3,6 +3,8 @@ 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 gdmsetblk` - Support Gen4 GDM write block (@iceman1001)
- Changed `hf 14a info` - detect Gen GDM magic tags (@iceman1001)
- Changed CLI max string argument length limit from 512 to 4096 (@iceman1001)
- Fixed `data asn1` - now handles bad input better (@iceman1001)
- Added new public key for signature MIFARE Plus Troika (@iceman100)

View file

@ -1686,7 +1686,7 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareECardLoadExt(payload->sectorcnt, payload->keytype);
break;
}
// Work with "magic Chinese" card
// Gen1a / 1b - "magic Chinese" card
case CMD_HF_MIFARE_CSETBL: {
MifareCSetBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
break;
@ -1713,6 +1713,7 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareGen3Freez();
break;
}
// Gen 4 GTU magic cards
case CMD_HF_MIFARE_G4_RDBL: {
struct p {
uint8_t blockno;
@ -1723,7 +1724,6 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareG4ReadBlk(payload->blockno, payload->pwd, payload->workFlags);
break;
}
// Gen 4 GTU magic cards
case CMD_HF_MIFARE_G4_WRBL: {
struct p {
uint8_t blockno;
@ -1735,6 +1735,18 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareG4WriteBlk(payload->blockno, payload->pwd, payload->data, payload->workFlags);
break;
}
case CMD_HF_MIFARE_G4_GDM_WRBL: {
struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6];
uint8_t data[16]; // data to be written
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareWriteBlockGDM(payload->blockno, payload->keytype, payload->key, payload->data);
break;
}
case CMD_HF_MIFARE_PERSONALIZE_UID: {
struct p {
uint8_t keytype;

View file

@ -446,6 +446,73 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
set_tracing(false);
}
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain) {
int retval = PM3_SUCCESS;
// check args
if (datain == NULL) {
retval = PM3_EINVARG;
goto OUT;
}
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
if (par == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
uint8_t *uid = BigBuf_malloc(10);
if (uid == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
// variables
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
uint64_t ui64key = bytes_to_num(key, 6);
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_authex_2(pcs, cuid, blockno, keytype, ui64key, AUTH_FIRST, NULL, NULL, true)) {
retval = PM3_ESOFT;
goto OUT;
};
if (mifare_classic_writeblock_ex(pcs, cuid, blockno, datain, true)) {
retval = PM3_ESOFT;
goto OUT;
};
if (mifare_classic_halt(pcs, cuid)) {
retval = PM3_ESOFT;
goto OUT;
};
if (g_dbglevel >= 2) DbpString("WRITE BLOCK FINISHED");
OUT:
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_G4_GDM_WRBL, retval, NULL, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
BigBuf_free();
}
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
// params
uint8_t blockNo = arg0;
@ -2356,7 +2423,7 @@ void MifareCIdent(bool is_mfc) {
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 gen3gmd[4] = { MIFARE_MAGIC_GDM_AUTH_KEYA, 0x00, 0x6C, 0x92};
uint8_t gen4gmd[4] = { MIFARE_MAGIC_GDM_AUTH_KEYA, 0x00, 0x6C, 0x92};
uint8_t gen4GetConf[8] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
@ -2493,17 +2560,17 @@ void MifareCIdent(bool is_mfc) {
}
}
// magic MFC Gen3 test 2
// magic MFC Gen4 GDM 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(gen3gmd, sizeof(gen3gmd), NULL);
ReaderTransmit(gen4gmd, sizeof(gen4gmd), NULL);
res = ReaderReceive(buf, par);
if (res == 4) {
isGen = MAGIC_GEN_3;
isGen = MAGIC_GEN_4GDM;
}
}
}

View file

@ -46,16 +46,21 @@ void MifareEMemGet(uint8_t blockno, uint8_t blockcnt);
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype);
int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype);
// MFC GEN1a /1b
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
void MifareCIdent(bool is_mfc); // is "magic chinese" card?
void MifareHasStaticNonce(void); // Has the tag a static nonce?
// MFC GEN3
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
// MFC GEN4 GDM
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain);
// MFC GEN4 GTU
void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd, uint8_t workFlags);
void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t workFlags);

View file

@ -137,8 +137,10 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested) {
return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL);
}
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) {
return mifare_classic_authex_2(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL, false);
}
int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm) {
int len;
uint32_t pos, nt, ntpp; // Supplied tag nonce
uint8_t par[1] = {0x00};
@ -150,8 +152,9 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
// "random" reader nonce:
num_to_bytes(prng_successor(GetTickCount(), 32), 4, nr);
// Transmit MIFARE_CLASSIC_AUTH
len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing);
// Transmit MIFARE_CLASSIC_AUTH 0x60, 0x61 or GDM 0x80
uint8_t cmdbyte = (is_gdm) ? MIFARE_MAGIC_GDM_AUTH_KEYA : MIFARE_AUTH_KEYA + (keyType & 0x01);
len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing);
if (len != 4) return 1;
// Save the tag nonce (nt)
@ -411,6 +414,10 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) {
}
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
return mifare_classic_writeblock_ex(pcs, uid, blockNo, blockData, false);
}
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm) {
// variables
uint16_t len = 0;
uint32_t pos = 0;
@ -421,8 +428,12 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// command MIFARE_CLASSIC_WRITEBLOCK
// command MIFARE_MAGIC_GDM_WRITEBLOCK
if (is_gdm) {
len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
} else {
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
}
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
@ -456,6 +467,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
return 0;
}
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) {
// variables
uint16_t len = 0;

View file

@ -72,10 +72,12 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
// mifare classic
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing);
int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm);
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
int mifare_classic_halt_ex(struct Crypto1State *pcs);
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm);
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action);
// Ultralight/NTAG...

View file

@ -7560,6 +7560,88 @@ static int CmdHF14AGen4Save(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gdmsetblk",
"Set block data on a magic gen4 GDM card",
"hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
);
void *argtable[] = {
arg_param_begin,
arg_int1(NULL, "blk", "<dec>", "block number"),
arg_lit0("a", NULL, "input key type is key A (def)"),
arg_lit0("b", NULL, "input key type is key B"),
arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int b = arg_get_int_def(ctx, 1, 1);
uint8_t keytype = MF_KEY_A;
if (arg_get_lit(ctx, 2) && arg_get_lit(ctx, 3)) {
CLIParserFree(ctx);
PrintAndLogEx(WARNING, "Input key type must be A or B");
return PM3_EINVARG;
} else if (arg_get_lit(ctx, 3)) {
keytype = MF_KEY_B;;
}
int keylen = 0;
uint8_t key[6] = {0};
CLIGetHexWithReturn(ctx, 4, key, &keylen);
uint8_t block[MFBLOCK_SIZE] = {0x00};
int blen = 0;
CLIGetHexWithReturn(ctx, 5, block, &blen);
CLIParserFree(ctx);
if (blen != MFBLOCK_SIZE) {
PrintAndLogEx(WARNING, "expected 16 HEX bytes. got %i", blen);
return PM3_EINVARG;
}
if (b < 0 || b >= MIFARE_4K_MAXBLOCK) {
PrintAndLogEx(FAILED, "target block number out-of-range, got %i", b);
return PM3_EINVARG;
}
uint8_t blockno = (uint8_t)b;
PrintAndLogEx(INFO, "Writing block no %d, key %c - %s", blockno, (keytype == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(key, sizeof(key)));
PrintAndLogEx(INFO, "data: %s", sprint_hex(block, sizeof(block)));
struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6];
uint8_t data[MFBLOCK_SIZE]; // data to be written
} PACKED payload;
payload.blockno = blockno;
payload.keytype = keytype;
memcpy(payload.key, key, sizeof(payload.key));
memcpy(payload.data, block, sizeof(payload.data));
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_G4_GDM_WRBL, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_WRBL, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "command execute timeout");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf rdbl") "` to verify");
} else {
PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
PrintAndLogEx(HINT, "Maybe access rights? Try specify keytype `" _YELLOW_("hf mf gdmsetblk -%c ...") "` instead", (keytype == MF_KEY_A) ? 'b' : 'a');
}
return PM3_SUCCESS;
}
static int CmdHF14AMfValue(const char *Cmd) {
@ -7825,6 +7907,8 @@ static command_t CommandTable[] = {
{"gsave", CmdHF14AGen4Save, IfPm3Iso14443a, "Save dump from card into file or emulator"},
{"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"},
{"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"},
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
{"ndefformat", CmdHFMFNDEFFormat, IfPm3Iso14443a, "Format MIFARE Classic Tag as NFC Tag"},

View file

@ -1214,6 +1214,7 @@ int mfG4SetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags
return PM3_SUCCESS;
}
// variables
uint32_t cuid = 0; // uid part used for crypto1.
@ -1414,6 +1415,9 @@ int detect_mf_magic(bool is_mfc) {
case MAGIC_GEN_4GTU:
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 4 GTU"));
break;
case MAGIC_GEN_4GDM:
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 4 GDM"));
break;
case MAGIC_GEN_UNFUSED:
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Write Once / FUID"));
break;

View file

@ -686,6 +686,10 @@ typedef struct {
#define CMD_HF_MIFARE_G4_RDBL 0x0860
#define CMD_HF_MIFARE_G4_WRBL 0x0861
// Gen 4 GDM magic cards
#define CMD_HF_MIFARE_G4_GDM_RDBL 0x0870
#define CMD_HF_MIFARE_G4_GDM_WRBL 0x0871
#define CMD_UNKNOWN 0xFFFF
//Mifare simulation flags

View file

@ -192,6 +192,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MIFARE_MAGIC_GDM_AUTH_KEYA 0x80
#define MIFARE_MAGIC_GDM_AUTH_KEYB 0x81
#define MIFARE_MAGIC_GDM_WRITEBLOCK 0xA8
#define MIFARE_EV1_PERSONAL_UID 0x40
#define MIFARE_EV1_SETMODE 0x43
@ -259,6 +260,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MAGIC_NTAG21X 7
#define MAGIC_GEN_3 8
#define MAGIC_GEN_4GTU 9
#define MAGIC_GEN_4GDM 10
// Commands for configuration of Gen4 GTU cards.
// see https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md