Merge branch 'RfidResearchGroup-master' into mf-supercard

This commit is contained in:
AloneLiberty 2023-03-25 18:08:19 +03:00
commit 00b7091178
9 changed files with 257 additions and 28 deletions

View file

@ -4,6 +4,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased] ## [unreleased][unreleased]
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty) - Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
- Added `hf mf gdmgetblk` - Support Gen4 GDM read configuration block (@iceman1001)
- Changed magic note to include a section about GDM tags (@iceman1001)
- Added `hf mf gdmsetblk` - Support Gen4 GDM write block (@iceman1001) - Added `hf mf gdmsetblk` - Support Gen4 GDM write block (@iceman1001)
- Changed `hf 14a info` - detect Gen GDM magic tags (@iceman1001) - Changed `hf 14a info` - detect Gen GDM magic tags (@iceman1001)
- Changed CLI max string argument length limit from 512 to 4096 (@iceman1001) - Changed CLI max string argument length limit from 512 to 4096 (@iceman1001)
@ -20,7 +22,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Fixed `pm3` script for passing arguments (@doegox) - Fixed `pm3` script for passing arguments (@doegox)
- Fixed python paths to include current directory (@jmichelp) - Fixed python paths to include current directory (@jmichelp)
- Fixed infinite loops in spindelayus (@lnv42) - Fixed infinite loops in spindelayus (@lnv42)
- Add ICECLASS standalone read/sim mode (@natesales) - Changed ICECLASS standalone to support a read/sim mode (@natesales)
- Changed `hf iclass encode` - added verbose flag (@natesales) - Changed `hf iclass encode` - added verbose flag (@natesales)
- Changed `hf waveshare` - now identify 1.54 nfc epaper correct (@ah01) - Changed `hf waveshare` - now identify 1.54 nfc epaper correct (@ah01)
- Fixed `Makefile` regression that broke `make install` (@henrygab) - Fixed `Makefile` regression that broke `make install` (@henrygab)
@ -32,12 +34,13 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `--back` option to `clear` command to clear the scrollback buffer (@wh201906) - Added `--back` option to `clear` command to clear the scrollback buffer (@wh201906)
- Changed `hf iclass decrypt` - mark credentials as decrypted in the dump (@natesales) - Changed `hf iclass decrypt` - mark credentials as decrypted in the dump (@natesales)
- Changed `hf iclass view` - show credentials on a decrypted dump (@natesales) - Changed `hf iclass view` - show credentials on a decrypted dump (@natesales)
- Show NTAG213TT tamper info in `hf mfu info` and add commands for configuring it's tamper feature (@mjaksn) - Changed `hf mfu info` - NTAG213TT tamper info (mjaksn)
- Add Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato) - Added commands for configuring NTAG213TT tamper featue (@mjaksn)
- Added Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato)
- Added XOR key extraction and flag to Guardall G-Prox II (@GuruSteve) - Added XOR key extraction and flag to Guardall G-Prox II (@GuruSteve)
- Changed verbiage on `hf iclass info` KeyAccess area to be congruent with AA1 and AA2 areas (@GuruSteve) - Changed verbiage on `hf iclass info` KeyAccess area to be congruent with AA1 and AA2 areas (@GuruSteve)
- Added `hf legic info` command for other sources: `hf legic einfo`, `hf legic view` (@0xdeb) - Added `hf legic info` command for other sources: `hf legic einfo`, `hf legic view` (@0xdeb)
-
## [Nitride.4.16191][2023-01-29] ## [Nitride.4.16191][2023-01-29]
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)

View file

@ -1735,7 +1735,16 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareG4WriteBlk(payload->blockno, payload->pwd, payload->data, payload->workFlags); MifareG4WriteBlk(payload->blockno, payload->pwd, payload->data, payload->workFlags);
break; break;
} }
case CMD_HF_MIFARE_G4_GDM_RDBL: {
struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareReadBlockGDM(payload->blockno, payload->keytype, payload->key);
break;
}
case CMD_HF_MIFARE_G4_GDM_WRBL: { case CMD_HF_MIFARE_G4_GDM_WRBL: {
struct p { struct p {
uint8_t blockno; uint8_t blockno;

View file

@ -214,6 +214,65 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
LEDsoff(); LEDsoff();
} }
void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key) {
int retval = PM3_SUCCESS;
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);
uint8_t outbuf[16] = {0x00};
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_readblock_ex(pcs, cuid, blockno, outbuf, true)) {
retval = PM3_ESOFT;
goto OUT;
};
if (mifare_classic_halt(pcs, cuid)) {
retval = PM3_ESOFT;
goto OUT;
};
OUT:
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_G4_GDM_RDBL, retval, outbuf, sizeof(outbuf));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
BigBuf_free();
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag. // Select, Authenticate, Read a MIFARE tag.
// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes) // read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)

View file

@ -59,6 +59,7 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overw
void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
// MFC GEN4 GDM // MFC GEN4 GDM
void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key);
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain); void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain);
// MFC GEN4 GTU // MFC GEN4 GTU

View file

@ -230,13 +230,20 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
} }
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
return mifare_classic_readblock_ex(pcs, uid, blockNo, blockData, false);
}
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm) {
int len;
uint8_t bt[2] = {0x00, 0x00};
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
uint16_t len;
if (is_gdm) {
len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
} else {
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
}
if (len == 1) { if (len == 1) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error %02x", receivedAnswer[0]); if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error %02x", receivedAnswer[0]);
return 1; return 1;
@ -246,6 +253,7 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo
return 2; return 2;
} }
uint8_t bt[2] = {0x00, 0x00};
memcpy(bt, receivedAnswer + 16, 2); memcpy(bt, receivedAnswer + 16, 2);
AddCrc14A(receivedAnswer, 16); AddCrc14A(receivedAnswer, 16);
if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) {
@ -416,19 +424,14 @@ 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) { 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); 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) { 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;
uint8_t par[3] = {0x00, 0x00, 0x00}; // enough for 18 Bytes to send
uint8_t res = 0;
uint8_t d_block[18], d_block_enc[18]; // variables
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// command MIFARE_MAGIC_GDM_WRITEBLOCK // command MIFARE_MAGIC_GDM_WRITEBLOCK
uint16_t len;
if (is_gdm) { if (is_gdm) {
len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
} else { } else {
@ -440,11 +443,14 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
return 1; return 1;
} }
uint8_t d_block[18], d_block_enc[18];
memcpy(d_block, blockData, 16); memcpy(d_block, blockData, 16);
AddCrc14A(d_block, 16); AddCrc14A(d_block, 16);
// enough for 18 Bytes to send
uint8_t par[3] = {0x00, 0x00, 0x00};
// crypto // crypto
for (pos = 0; pos < 18; pos++) { for (uint32_t pos = 0; pos < 18; pos++) {
d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos];
par[pos >> 3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos & 0x0007))); par[pos >> 3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos & 0x0007)));
} }
@ -452,9 +458,10 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
// Receive the response // Receive the response
len = ReaderReceive(receivedAnswer, receivedAnswerPar); len = ReaderReceive(receivedAnswer, receivedAnswerPar);
res = 0; uint8_t res = 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0; res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1; res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2; res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;

View file

@ -73,7 +73,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); 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(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_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_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm);
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
int mifare_classic_halt_ex(struct Crypto1State *pcs); 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(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);

View file

@ -7674,6 +7674,78 @@ static int CmdHF14AGen4Save(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHF14AGen4_GDM_GetBlk(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gdmgetblk",
"Get block data from magic gen4 GDM card.",
"hf mf gdmgetblk --blk 0 --> get block 0 (manufacturer)\n"
"hf mf gdmgetblk --blk 3 -v --> get block 3, decode sector trailer\n"
);
void *argtable[] = {
arg_param_begin,
arg_int1("b", "blk", "<dec>", "block number"),
arg_lit0("v", "verbose", "verbose output"),
arg_str0("k", "key", "<hex>", "key 6 bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int b = arg_get_int_def(ctx, 1, 0);
bool verbose = arg_get_lit(ctx, 2);
int keylen = 0;
uint8_t key[6] = {0};
CLIGetHexWithReturn(ctx, 3, key, &keylen);
CLIParserFree(ctx);
// validate args
if (b < 0 || b >= MIFARE_4K_MAXBLOCK) {
PrintAndLogEx(FAILED, "target block number out-of-range, got %i", b);
return PM3_EINVARG;
}
if (keylen != 6 && keylen != 0) {
PrintAndLogEx(FAILED, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen);
return PM3_EINVARG;
}
uint8_t blockno = (uint8_t)b;
PrintAndLogEx(NORMAL, "Block: %x", blockno) ;
struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6];
} PACKED payload;
payload.blockno = blockno;
payload.keytype = 0;
memcpy(payload.key, key, sizeof(payload.key));
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_G4_GDM_RDBL, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_RDBL, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "command execute timeout");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
uint8_t sector = mfSectorNum(blockno);
mf_print_sector_hdr(sector);
uint8_t *d = resp.data.asBytes;
mf_print_block_one(blockno, d, verbose);
if (verbose) {
decode_print_st(blockno, d);
} else {
PrintAndLogEx(NORMAL, "");
}
}
return resp.status;
}
static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) { static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
@ -7713,7 +7785,7 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
if (blen != MFBLOCK_SIZE) { if (blen != MFBLOCK_SIZE) {
PrintAndLogEx(WARNING, "expected 16 HEX bytes. got %i", blen); PrintAndLogEx(WARNING, "expected %u HEX bytes. got %i", MFBLOCK_SIZE, blen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -7722,6 +7794,11 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 6 && keylen != 0) {
PrintAndLogEx(FAILED, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen);
return PM3_EINVARG;
}
uint8_t blockno = (uint8_t)b; 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, "Writing block no %d, key %c - %s", blockno, (keytype == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(key, sizeof(key)));
@ -8022,6 +8099,7 @@ static command_t CommandTable[] = {
{"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"}, {"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"},
{"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"}, {"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"}, {"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"},
{"gdmgetblk", CmdHF14AGen4_GDM_GetBlk, IfPm3Iso14443a, "Read block from card"},
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"}, {"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"}, // {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},

View file

@ -20,6 +20,7 @@ Useful docs:
* [MIFARE Classic DirectWrite, UFUID version](#mifare-classic-directwrite-ufuid-version) * [MIFARE Classic DirectWrite, UFUID version](#mifare-classic-directwrite-ufuid-version)
* [MIFARE Classic, other versions](#mifare-classic-other-versions) * [MIFARE Classic, other versions](#mifare-classic-other-versions)
* [MIFARE Classic Gen3 aka APDU](#mifare-classic-gen3-aka-apdu) * [MIFARE Classic Gen3 aka APDU](#mifare-classic-gen3-aka-apdu)
* [MIFARE Classic Gen4 aka GDM](#mifare-classic-gen4-aka-gdm)
* [MIFARE Classic Super](#mifare-classic-super) * [MIFARE Classic Super](#mifare-classic-super)
- [MIFARE Ultralight](#mifare-ultralight) - [MIFARE Ultralight](#mifare-ultralight)
* [MIFARE Ultralight blocks 0..2](#mifare-ultralight-blocks-02) * [MIFARE Ultralight blocks 0..2](#mifare-ultralight-blocks-02)
@ -68,6 +69,7 @@ To restore anticollision config of the Proxmark3:
``` ```
hf 14a config --std hf 14a config --std
``` ```
# MIFARE Classic # MIFARE Classic
^[Top](#top) ^[Top](#top)
@ -89,7 +91,7 @@ UID 4b: (actually NUID as there are no more "unique" IDs on 4b)
``` ```
Computing BCC on UID 11223344: `hf analyse lcr -d 11223344` = `44` Computing BCC on UID 11223344: `analyse lcr -d 11223344` = `44`
UID 7b: UID 7b:
@ -262,6 +264,8 @@ hf 14a info
* Read: `40(7)`, `30xx` * Read: `40(7)`, `30xx`
* Write: `40(7)`, `A0xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc * Write: `40(7)`, `A0xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
## MIFARE Classic DirectWrite aka Gen2 aka CUID ## MIFARE Classic DirectWrite aka Gen2 aka CUID
^[Top](#top) ^[Top](#top)
@ -396,6 +400,7 @@ hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 04112233445566184200626364656667 # for 4k
hf 14a config --std hf 14a config --std
hf 14a reader hf 14a reader
``` ```
## MIFARE Classic DirectWrite, FUID version aka 1-write ## MIFARE Classic DirectWrite, FUID version aka 1-write
^[Top](#top) ^[Top](#top)
@ -436,14 +441,6 @@ hf 14a raw -k -c e100
hf 14a raw -c 85000000000000000000000000000008 hf 14a raw -c 85000000000000000000000000000008
``` ```
## MIFARE Classic, other versions
^[Top](#top)
**TODO**
* ZXUID, EUID, ICUID ?
* Some cards exhibit a specific SAK=28 ??
## MIFARE Classic Gen3 aka APDU ## MIFARE Classic Gen3 aka APDU
^[Top](#top) ^[Top](#top)
@ -517,6 +514,72 @@ hf 14a raw -s -c -t 2000 90F0CCCC10 041219c3219316984200e32000000000
hf 14a raw -s -c 90FD111100 hf 14a raw -s -c 90FD111100
``` ```
## MIFARE Classic Gen4 aka GDM
^[Top](#top)
Tag has shadow mode enabled from start.
Meaning every write or changes to normal MFC memory is restored back to a copy from persistent memory after about 3 seconds
off rfid field.
Tag also seems to support Gen2 style, direct write, to block 0 to the normal MFC memory.
The persistent memory is also writable. For that tag uses its own backdoor commands.
for example to write, you must use a customer authentication byte, 0x80, to authenticate with an all zeros key, 0x0000000000.
Then send the data to be written.
** OBS **
When writing to persistent memory it is possible to write _bad_ ACL and perm-brick the tag.
### Identify
^[Top](#top)
```
hf 14a info
...
[+] Magic capabilities : Gen 4 GDM
```
### Magic commands
^[Top](#top)
* Auth: `80xx`+crc
* Write: `A8xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
* Read : `E000`+crc (unidentified)
### Characteristics
^[Top](#top)
* Have no knowledge in ATQA/SAK/BCC quirks or if there is a wipe, softbrick recover
* Its magic part seem to be three identified custom command.
* Auth command 0x80, with the key 0x0000000000, Write 0xA8 allows writing to persistent memory, Read 0xE0 which seems to return a configuration. This is unknown today what these bytes are.
It is unknown what kind of block 0 changes the tag supports
* UID: 4b
* ATQA/SAK: unknown
* BCC: unknown
* ATS: none
### Proxmark3 commands
^[Top](#top)
```
# Write to persistent memory
hf mf gdmsetblk
# Read 0xE0 configuration:
hf mf gdmgetblk
```
### libnfc commands
^[Top](#top)
No implemented commands today
## MIFARE Classic, other versions
^[Top](#top)
**TODO**
* ZXUID, EUID, ICUID ?
* Some cards exhibit a specific SAK=28 ??
## MIFARE Classic Super ## MIFARE Classic Super
^[Top](#top) ^[Top](#top)
@ -1019,7 +1082,6 @@ script run hf_15_magic -u E004013344556677
A.k.a ultimate magic card, most promenent feature is shadow mode (GTU) and optional password protected backdoor commands. A.k.a ultimate magic card, most promenent feature is shadow mode (GTU) and optional password protected backdoor commands.
Can emulate MIFARE Classic, Ultralight/NTAG families, 14b UID & App Data Can emulate MIFARE Classic, Ultralight/NTAG families, 14b UID & App Data
- [Identify](#identify) - [Identify](#identify)
@ -1057,6 +1119,7 @@ The card will be identified only if the password is the default one. One can ide
hf 14a raw -s -c -t 1000 CF00000000C6 hf 14a raw -s -c -t 1000 CF00000000C6
``` ```
If the card is an Ultimate Magic Card, it returns 30 or 32 bytes. If the card is an Ultimate Magic Card, it returns 30 or 32 bytes.
### Magic commands ### Magic commands
^[Top](#top) ^^[Gen4](#g4top) ^[Top](#top) ^^[Gen4](#g4top)
@ -1203,6 +1266,7 @@ OR (Note the script will correct the ATQA correctly)
``` ```
script run hf_mf_ultimatecard -q 004428 script run hf_mf_ultimatecard -q 004428
``` ```
### Change ATS ### Change ATS
^[Top](#top) ^^[Gen4](#g4top) ^[Top](#top) ^^[Gen4](#g4top)
@ -1240,6 +1304,7 @@ Example: set UID length to 7 bytes, default pwd
``` ```
hf 14a raw -s -c -t 1000 CF000000006801 hf 14a raw -s -c -t 1000 CF000000006801
``` ```
### Set 14443A UID ### Set 14443A UID
^[Top](#top) ^^[Gen4](#g4top) ^[Top](#top) ^^[Gen4](#g4top)
@ -1353,6 +1418,7 @@ script run hf_mf_ultimatecard -m 02
``` ```
Now the card supports the 3DES UL-C authentication. Now the card supports the 3DES UL-C authentication.
### Set Ultralight and M1 maximum read/write sectors ### Set Ultralight and M1 maximum read/write sectors
^[Top](#top) ^^[Gen4](#g4top) ^[Top](#top) ^^[Gen4](#g4top)
@ -1366,6 +1432,7 @@ Example: set maximum 63 blocks read/write for Mifare Classic 1K
``` ```
hf 14a raw -s -c -t 1000 CF000000006B3F hf 14a raw -s -c -t 1000 CF000000006B3F
``` ```
### Set shadow mode (GTU) ### Set shadow mode (GTU)
^[Top](#top) ^^[Gen4](#g4top) ^[Top](#top) ^^[Gen4](#g4top)
@ -1479,6 +1546,7 @@ Default configuration:
^^ cf cmd 68: UID length ^^ cf cmd 68: UID length
^^ cf cmd 69: Ultralight protocol ^^ cf cmd 69: Ultralight protocol
``` ```
### Fast configuration ### Fast configuration
^[Top](#top) ^^[Gen4](#g4top) ^[Top](#top) ^^[Gen4](#g4top)

View file

@ -193,6 +193,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MIFARE_MAGIC_GDM_AUTH_KEYA 0x80 #define MIFARE_MAGIC_GDM_AUTH_KEYA 0x80
#define MIFARE_MAGIC_GDM_AUTH_KEYB 0x81 #define MIFARE_MAGIC_GDM_AUTH_KEYB 0x81
#define MIFARE_MAGIC_GDM_WRITEBLOCK 0xA8 #define MIFARE_MAGIC_GDM_WRITEBLOCK 0xA8
#define MIFARE_MAGIC_GDM_READBLOCK 0xE0
#define MIFARE_EV1_PERSONAL_UID 0x40 #define MIFARE_EV1_PERSONAL_UID 0x40
#define MIFARE_EV1_SETMODE 0x43 #define MIFARE_EV1_SETMODE 0x43