Merge branch 'master' of https://github.com/RfidResearchGroup/proxmark3 into mf-supercard

This commit is contained in:
AloneLiberty 2023-03-26 16:05:57 +03:00
commit 2c74b98974
9 changed files with 143 additions and 112 deletions

View file

@ -1735,14 +1735,12 @@ 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: { case CMD_HF_MIFARE_G4_GDM_CONFIG: {
struct p { struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6]; uint8_t key[6];
} PACKED; } PACKED;
struct p *payload = (struct p *) packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
MifareReadBlockGDM(payload->blockno, payload->keytype, payload->key); MifareReadConfigBlockGDM(payload->key);
break; break;
} }
case CMD_HF_MIFARE_G4_GDM_WRBL: { case CMD_HF_MIFARE_G4_GDM_WRBL: {

View file

@ -214,7 +214,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
LEDsoff(); LEDsoff();
} }
void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key) { void MifareReadConfigBlockGDM(uint8_t *key) {
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
@ -248,12 +248,12 @@ void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key) {
goto OUT; goto OUT;
} }
if (mifare_classic_authex_2(pcs, cuid, blockno, keytype, ui64key, AUTH_FIRST, NULL, NULL, true)) { if (mifare_classic_authex_2(pcs, cuid, 0, 0, ui64key, AUTH_FIRST, NULL, NULL, true)) {
retval = PM3_ESOFT; retval = PM3_ESOFT;
goto OUT; goto OUT;
}; };
if (mifare_classic_readblock_ex(pcs, cuid, blockno, outbuf, true)) { if (mifare_classic_readblock_ex(pcs, cuid, 0, outbuf, MIFARE_MAGIC_GDM_READBLOCK)) {
retval = PM3_ESOFT; retval = PM3_ESOFT;
goto OUT; goto OUT;
}; };
@ -266,7 +266,7 @@ void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key) {
OUT: OUT:
crypto1_deinit(pcs); crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_G4_GDM_RDBL, retval, outbuf, sizeof(outbuf)); reply_ng(CMD_HF_MIFARE_G4_GDM_CONFIG, retval, outbuf, sizeof(outbuf));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();
set_tracing(false); set_tracing(false);

View file

@ -59,7 +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 MifareReadConfigBlockGDM(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

@ -153,7 +153,7 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
num_to_bytes(prng_successor(GetTickCount(), 32), 4, nr); num_to_bytes(prng_successor(GetTickCount(), 32), 4, nr);
// Transmit MIFARE_CLASSIC_AUTH 0x60, 0x61 or GDM 0x80 // Transmit MIFARE_CLASSIC_AUTH 0x60, 0x61 or GDM 0x80
uint8_t cmdbyte = (is_gdm) ? MIFARE_MAGIC_GDM_AUTH_KEYA : MIFARE_AUTH_KEYA + (keyType & 0x01); uint8_t cmdbyte = (is_gdm) ? MIFARE_MAGIC_GDM_AUTH_KEYA + (keyType & 0x01) : MIFARE_AUTH_KEYA + (keyType & 0x01);
len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing); len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing);
if (len != 4) return 1; if (len != 4) return 1;
@ -230,20 +230,14 @@ 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); return mifare_classic_readblock_ex(pcs, uid, blockNo, blockData, ISO14443A_CMD_READBLOCK);
} }
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm) { int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte) {
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; uint16_t len = mifare_sendcmd_short(pcs, 1, iso_byte, blockNo, receivedAnswer, receivedAnswerPar, NULL);
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);
}
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;
@ -458,7 +452,6 @@ 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);
uint8_t res = 0; uint8_t res = 0;

View file

@ -75,7 +75,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
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_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte);
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);

View file

@ -400,6 +400,47 @@ static void mf_analyse_acl(uint16_t n, uint8_t *d) {
} }
} }
/*
Sector trailer sanity checks.
Warn if ACL is strict read-only, or invalid ACL.
*/
static int mf_analyse_st_block(uint8_t blockno, uint8_t *block, bool force){
if (mfIsSectorTrailer(blockno) == false) {
return PM3_SUCCESS;
}
PrintAndLogEx(INFO, "Sector trailer (ST) write detected");
// ensure access right isn't messed up.
if (mfValidateAccessConditions(&block[6]) == false) {
PrintAndLogEx(WARNING, "Invalid Access Conditions detected, replacing with default values");
memcpy(block + 6, "\xFF\x07\x80\x69", 4);
}
bool ro_detected = false;
uint8_t bar = mfNumBlocksPerSector(mfSectorNum(blockno));
for (uint8_t foo = 0; foo < bar; foo++) {
if (mfReadOnlyAccessConditions(foo, &block[6])) {
PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", blockno - bar + 1 + foo);
ro_detected = true;
}
}
if (ro_detected) {
if (force) {
PrintAndLogEx(WARNING, " --force override, continuing...");
} else {
PrintAndLogEx(INFO, "Exiting, please run `" _YELLOW_("hf mf acl -d %s") "` to understand", sprint_hex_inrow(&block[6], 3));
PrintAndLogEx(INFO, "Use `" _YELLOW_("--force") "` to override and write this data");
return PM3_EINVARG;
}
} else {
PrintAndLogEx(SUCCESS, "ST passed checks, continuing...");
}
return PM3_SUCCESS;
}
static int CmdHF14AMfAcl(const char *Cmd) { static int CmdHF14AMfAcl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf acl", CLIParserInit(&ctx, "hf mf acl",
@ -521,7 +562,6 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
arg_lit0(NULL, "force", "override warnings"), arg_lit0(NULL, "force", "override warnings"),
arg_str0("k", "key", "<hex>", "key, 6 hex bytes"), arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"), arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -569,37 +609,9 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
uint8_t blockno = (uint8_t)b; uint8_t blockno = (uint8_t)b;
// Sector trailer sanity checks. if (mf_analyse_st_block(blockno, block, force) != PM3_SUCCESS) {
// Warn if ACL is strict read-only, or invalid ACL.
if (mfIsSectorTrailer(blockno)) {
PrintAndLogEx(INFO, "Sector trailer (ST) write detected");
// ensure access right isn't messed up.
if (mfValidateAccessConditions(&block[6]) == false) {
PrintAndLogEx(WARNING, "Invalid Access Conditions detected, replacing with default values");
memcpy(block + 6, "\xFF\x07\x80\x69", 4);
}
bool ro_detected = false;
uint8_t bar = mfNumBlocksPerSector(mfSectorNum(blockno));
for (uint8_t foo = 0; foo < bar; foo++) {
if (mfReadOnlyAccessConditions(foo, &block[6])) {
PrintAndLogEx(WARNING, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", blockno - bar + 1 + foo);
ro_detected = true;
}
}
if (ro_detected) {
if (force) {
PrintAndLogEx(WARNING, " --force override, continuing...");
} else {
PrintAndLogEx(INFO, "Exiting, please run `" _YELLOW_("hf mf acl -d %s") "` to understand", sprint_hex_inrow(&block[6], 3));
PrintAndLogEx(INFO, "Use `" _YELLOW_("--force") "` to override and write this data");
return PM3_EINVARG; return PM3_EINVARG;
} }
} else {
PrintAndLogEx(SUCCESS, "ST passed checks, continuing...");
}
}
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)));
PrintAndLogEx(INFO, "data: %s", sprint_hex(block, sizeof(block))); PrintAndLogEx(INFO, "data: %s", sprint_hex(block, sizeof(block)));
@ -7674,74 +7686,48 @@ static int CmdHF14AGen4Save(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHF14AGen4_GDM_GetBlk(const char *Cmd) { static int CmdHF14AGen4_GDM_ConfigBlk(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gdmgetblk", CLIParserInit(&ctx, "hf mf gdmconfig",
"Get block data from magic gen4 GDM card.", "Get configuration data from magic gen4 GDM card.",
"hf mf gdmgetblk --blk 0 --> get block 0 (manufacturer)\n" "hf mf gdmconfig\n"
"hf mf gdmgetblk --blk 3 -v --> get block 3, decode sector trailer\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, 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_str0("k", "key", "<hex>", "key 6 bytes"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, true);
int b = arg_get_int_def(ctx, 1, 0);
bool verbose = arg_get_lit(ctx, 2);
int keylen = 0; int keylen = 0;
uint8_t key[6] = {0}; uint8_t key[6] = {0};
CLIGetHexWithReturn(ctx, 3, key, &keylen); CLIGetHexWithReturn(ctx, 1, key, &keylen);
CLIParserFree(ctx); CLIParserFree(ctx);
// validate args // 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) { if (keylen != 6 && keylen != 0) {
PrintAndLogEx(FAILED, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen); PrintAndLogEx(FAILED, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t blockno = (uint8_t)b;
PrintAndLogEx(NORMAL, "Block: %x", blockno) ;
struct p { struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6]; uint8_t key[6];
} PACKED payload; } PACKED payload;
payload.blockno = blockno;
payload.keytype = 0;
memcpy(payload.key, key, sizeof(payload.key)); memcpy(payload.key, key, sizeof(payload.key));
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_G4_GDM_RDBL, (uint8_t *)&payload, sizeof(payload)); SendCommandNG(CMD_HF_MIFARE_G4_GDM_CONFIG, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_RDBL, &resp, 1500) == false) { if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_CONFIG, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "command execute timeout"); PrintAndLogEx(WARNING, "command execute timeout");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
if (resp.status == PM3_SUCCESS) { if (resp.status == PM3_SUCCESS) {
uint8_t sector = mfSectorNum(blockno);
mf_print_sector_hdr(sector);
uint8_t *d = resp.data.asBytes; uint8_t *d = resp.data.asBytes;
mf_print_block_one(blockno, d, verbose); PrintAndLogEx(SUCCESS, "config... %s", sprint_hex(d, resp.length));
if (verbose) {
decode_print_st(blockno, d);
} else {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
} }
}
return resp.status; return resp.status;
} }
@ -7750,7 +7736,9 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gdmsetblk", CLIParserInit(&ctx, "hf mf gdmsetblk",
"Set block data on a magic gen4 GDM card", "Set block data on a magic gen4 GDM card\n"
"`--force` param is used to override warnings like bad ACL writes.\n"
" if not specified, it will exit if detected",
"hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f" "hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
); );
void *argtable[] = { void *argtable[] = {
@ -7758,8 +7746,9 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
arg_int1(NULL, "blk", "<dec>", "block number"), arg_int1(NULL, "blk", "<dec>", "block number"),
arg_lit0("a", NULL, "input key type is key A (def)"), arg_lit0("a", NULL, "input key type is key A (def)"),
arg_lit0("b", NULL, "input key type is key B"), 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_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
arg_lit0(NULL, "force", "override warnings"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -7775,13 +7764,15 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
keytype = MF_KEY_B;; keytype = MF_KEY_B;;
} }
int keylen = 0;
uint8_t key[6] = {0};
CLIGetHexWithReturn(ctx, 4, key, &keylen);
uint8_t block[MFBLOCK_SIZE] = {0x00}; uint8_t block[MFBLOCK_SIZE] = {0x00};
int blen = 0; int blen = 0;
CLIGetHexWithReturn(ctx, 5, block, &blen); CLIGetHexWithReturn(ctx, 4, block, &blen);
int keylen = 0;
uint8_t key[6] = {0};
CLIGetHexWithReturn(ctx, 5, key, &keylen);
bool force = arg_get_lit(ctx, 6);
CLIParserFree(ctx); CLIParserFree(ctx);
if (blen != MFBLOCK_SIZE) { if (blen != MFBLOCK_SIZE) {
@ -7801,6 +7792,10 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
uint8_t blockno = (uint8_t)b; uint8_t blockno = (uint8_t)b;
if (mf_analyse_st_block(blockno, block, force) != PM3_SUCCESS) {
return PM3_EINVARG;
}
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)));
PrintAndLogEx(INFO, "data: %s", sprint_hex(block, sizeof(block))); PrintAndLogEx(INFO, "data: %s", sprint_hex(block, sizeof(block)));
@ -8099,7 +8094,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"}, {"gdmconfig", CmdHF14AGen4_GDM_ConfigBlk, IfPm3Iso14443a, "Read config 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

@ -370,7 +370,7 @@ Android compatible
^[Top](#top) ^[Top](#top)
``` ```
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 11223344440804006263646566676869 hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 11223344440804006263646566676869 --force
hf mf wipe --gen2 hf mf wipe --gen2
``` ```
@ -385,8 +385,13 @@ e.g. for 4b UID:
``` ```
hf 14a config --atqa force --bcc ignore --cl2 skip --rats skip hf 14a config --atqa force --bcc ignore --cl2 skip --rats skip
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 11223344440804006263646566676869 # for 1k
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 11223344441802006263646566676869 # for 4k # for 1k
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 11223344440804006263646566676869 --force
# for 4k
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 11223344441802006263646566676869 --force
hf 14a config --std hf 14a config --std
hf 14a reader hf 14a reader
``` ```
@ -395,8 +400,13 @@ e.g. for 7b UID:
``` ```
hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip --rats skip hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip --rats skip
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 04112233445566084400626364656667 # for 1k
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 04112233445566184200626364656667 # for 4k # for 1k
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 04112233445566084400626364656667 --force
# for 4k
hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 04112233445566184200626364656667 --force
hf 14a config --std hf 14a config --std
hf 14a reader hf 14a reader
``` ```
@ -516,6 +526,7 @@ hf 14a raw -s -c 90FD111100
## MIFARE Classic Gen4 aka GDM ## MIFARE Classic Gen4 aka GDM
^[Top](#top) ^[Top](#top)
Tag has shadow mode enabled from start. 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 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. off rfid field.
@ -525,9 +536,16 @@ The persistent memory is also writable. For that tag uses its own backdoor comma
for example to write, you must use a customer authentication byte, 0x80, to authenticate with an all zeros key, 0x0000000000. 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. Then send the data to be written.
This tag has simular commands to the [UFUID](#mifare-classic-directwrite-ufuid-version)
It seems to be developed by the same person.
**OBS** **OBS**
When writing to persistent memory it is possible to write _bad_ ACL and perm-brick the tag. When writing to persistent memory it is possible to write _bad_ ACL and perm-brick the tag.
**OBS**
It is possible to write a configuration that perma locks the tag, ie no more magic
### Identify ### Identify
^[Top](#top) ^[Top](#top)
@ -542,7 +560,8 @@ hf 14a info
* Auth: `80xx`+crc * Auth: `80xx`+crc
* Write: `A8xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc * Write: `A8xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
* Read : `E000`+crc (unidentified) * Read config: `E000`+crc (unidentified)
* Write config: `E100`+crc
### Characteristics ### Characteristics
^[Top](#top) ^[Top](#top)
@ -551,6 +570,22 @@ hf 14a info
* Its magic part seem to be three identified custom command. * 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. * 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.
Read config:
1. sending custom auth with all zeros key
2. send 0xE000, will return the configuration bytes.
`results: 850000000000000000005A5A00000008`
Write config:
1. sending custom auth with all zeros key
2. send 0xE100
3. send 16 bytes
**Warning**
Example of configuration to Perma lock tag:
`85000000000000000000000000000008`
It is unknown what kind of block 0 changes the tag supports It is unknown what kind of block 0 changes the tag supports
* UID: 4b * UID: 4b
* ATQA/SAK: unknown * ATQA/SAK: unknown
@ -564,7 +599,7 @@ It is unknown what kind of block 0 changes the tag supports
hf mf gdmsetblk hf mf gdmsetblk
# Read 0xE0 configuration: # Read 0xE0 configuration:
hf mf gdmgetblk hf mf gdmconfig
``` ```
@ -1097,6 +1132,7 @@ Can emulate MIFARE Classic, Ultralight/NTAG families, 14b UID & App Data
- [Select Ultralight mode](#select-ultralight-mode) - [Select Ultralight mode](#select-ultralight-mode)
- [Set shadow mode (GTU)](#set-shadow-mode-gtu) - [Set shadow mode (GTU)](#set-shadow-mode-gtu)
- [Direct block read and write](#direct-block-read-and-write) - [Direct block read and write](#direct-block-read-and-write)
- [(De)Activate direct write to block 0](#deactivate-direct-write-to-block-0)
- [Change backdoor password](#change-backdoor-password) - [Change backdoor password](#change-backdoor-password)
- [Dump configuration](#dump-configuration) - [Dump configuration](#dump-configuration)
- [Fast configuration](#fast-configuration) - [Fast configuration](#fast-configuration)
@ -1201,7 +1237,7 @@ CF <passwd> C6 // Dump configuration
CF <passwd> CC // Factory test, returns 6666 CF <passwd> CC // Factory test, returns 6666
CF <passwd> CD <1b block number><16b block data> // Backdoor write 16b block CF <passwd> CD <1b block number><16b block data> // Backdoor write 16b block
CF <passwd> CE <1b block number> // Backdoor read 16b block CF <passwd> CE <1b block number> // Backdoor read 16b block
CF <passwd> CF <1b param> // Unknown CF <passwd> CF <1b param> // (De)Activate direct write to block 0
CF <passwd> F0 <30b configuration data> // Configure all params in one cmd CF <passwd> F0 <30b configuration data> // Configure all params in one cmd
CF <passwd> F1 <30b configuration data> // Configure all params in one cmd and fuse the configuration permanently CF <passwd> F1 <30b configuration data> // Configure all params in one cmd and fuse the configuration permanently
CF <passwd> FE <4b new_password> // change password CF <passwd> FE <4b new_password> // change password
@ -1494,19 +1530,27 @@ Example: write block0 with factory data, default pwd
hf 14a raw -s -c -t 1000 CF00000000CD00112233441C000011778185BA18000000 hf 14a raw -s -c -t 1000 CF00000000CD00112233441C000011778185BA18000000
``` ```
### Unknown command ### (De)Activate direct write to block 0
^[Top](#top) ^^[Gen4](#g4top) ^[Top](#top) ^^[Gen4](#g4top)
This command modifies one byte in configuration dump, but purpose one is unknown. This command enables/disables direct writes to block 0.
``` ```
hf 14a raw -s -c -t 1000 CF<passwd>CF<1b param> hf 14a raw -s -c -t 1000 CF<passwd>CF<1b param>
``` ```
* `<param>` * `<param>`
* `??`: ??? * `00`: Activate direct write to block 0 (Same behaviour of Gen2 cards. Some readers may identify the card as magic)
* `01`: Deactivate direct write to block 0 (Same behaviour of vanilla cards)
* `02`: Default value. (Same behaviour as `00` (?))
Example: Example: enable direct writes to block 0, default pwd
hf 14a raw -s -c -t 1000 CF00000000CF02 ```
hf 14a raw -s -c -t 1000 CF00000000CF00
```
Example: disable direct writes to block 0, default pwd
```
hf 14a raw -s -c -t 1000 CF00000000CF01
```
### Change backdoor password ### Change backdoor password
^[Top](#top) ^^[Gen4](#g4top) ^[Top](#top) ^^[Gen4](#g4top)
@ -1536,7 +1580,7 @@ Default configuration:
``` ```
00000000000002000978009102DABC191010111213141516040008006B024F6B 00000000000002000978009102DABC191010111213141516040008006B024F6B
^^^^ ?? ^^^^ ??
^^ cf cmd cf: ?? this byte set by cmd cf<pwd>cf<param>, factory value 0x02 ^^ cf cmd cf: block0 direct write setting, factory value 0x02
^^ cf cmd 6b: maximum read/write sectors, factory value 0x6b ^^ cf cmd 6b: maximum read/write sectors, factory value 0x6b
^^ cf cmd 6a: UL mode ^^ cf cmd 6a: UL mode
^^^^^^ cf cmd 35: ATQA/SAK ^^^^^^ cf cmd 35: ATQA/SAK
@ -1657,4 +1701,3 @@ hf mfu wrbl -b 250 -d 00040402 --force
hf mfu wrbl -b 251 -d 01001303 --force hf mfu wrbl -b 251 -d 01001303 --force
hf mfu info hf mfu info
``` ```

View file

@ -689,6 +689,7 @@ typedef struct {
// Gen 4 GDM magic cards // Gen 4 GDM magic cards
#define CMD_HF_MIFARE_G4_GDM_RDBL 0x0870 #define CMD_HF_MIFARE_G4_GDM_RDBL 0x0870
#define CMD_HF_MIFARE_G4_GDM_WRBL 0x0871 #define CMD_HF_MIFARE_G4_GDM_WRBL 0x0871
#define CMD_HF_MIFARE_G4_GDM_CONFIG 0x0872
#define CMD_UNKNOWN 0xFFFF #define CMD_UNKNOWN 0xFFFF

View file

@ -194,6 +194,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#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_MAGIC_GDM_READBLOCK 0xE0
#define MIFARE_MAGIC_GDM_READBLOCK_1 0xE1
#define MIFARE_EV1_PERSONAL_UID 0x40 #define MIFARE_EV1_PERSONAL_UID 0x40
#define MIFARE_EV1_SETMODE 0x43 #define MIFARE_EV1_SETMODE 0x43