From 97e16ba764d4b3cfe345c20920c55ce629df378c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 26 Mar 2023 03:41:12 +0200 Subject: [PATCH] renamed gdm getblk to config since that is what it does --- armsrc/appmain.c | 6 +- armsrc/mifarecmd.c | 8 +-- armsrc/mifarecmd.h | 2 +- armsrc/mifareutil.c | 15 ++-- armsrc/mifareutil.h | 2 +- client/src/cmdhfmf.c | 145 +++++++++++++++++++-------------------- doc/magic_cards_notes.md | 5 +- include/pm3_cmd.h | 1 + include/protocols.h | 1 + 9 files changed, 88 insertions(+), 97 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c90640828..969513d39 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1735,14 +1735,12 @@ static void PacketReceived(PacketCommandNG *packet) { MifareG4WriteBlk(payload->blockno, payload->pwd, payload->data, payload->workFlags); break; } - case CMD_HF_MIFARE_G4_GDM_RDBL: { + case CMD_HF_MIFARE_G4_GDM_CONFIG: { 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); + MifareReadConfigBlockGDM(payload->key); break; } case CMD_HF_MIFARE_G4_GDM_WRBL: { diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 0bcb4fd74..9eb44da5a 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -214,7 +214,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { LEDsoff(); } -void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key) { +void MifareReadConfigBlockGDM(uint8_t *key) { int retval = PM3_SUCCESS; @@ -248,12 +248,12 @@ void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key) { 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; 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; goto OUT; }; @@ -266,7 +266,7 @@ void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key) { OUT: 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); LEDsoff(); set_tracing(false); diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 062c02367..6363423fd 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -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 // 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); // MFC GEN4 GTU diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 29754538a..11009031b 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -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); // 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); 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) { - 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 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); - } - + uint16_t len = mifare_sendcmd_short(pcs, 1, iso_byte, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error %02x", receivedAnswer[0]); 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); // Receive the response - len = ReaderReceive(receivedAnswer, receivedAnswerPar); uint8_t res = 0; diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 37b1b1294..bcc813d00 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -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_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_ex(struct Crypto1State *pcs); diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index a0a2c6961..0ba8aac98 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -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) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf acl", @@ -521,7 +562,6 @@ static int CmdHF14AMfWrBl(const char *Cmd) { arg_lit0(NULL, "force", "override warnings"), arg_str0("k", "key", "", "key, 6 hex bytes"), arg_str0("d", "data", "", "bytes to write, 16 hex bytes"), - arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -569,36 +609,8 @@ static int CmdHF14AMfWrBl(const char *Cmd) { uint8_t blockno = (uint8_t)b; - // Sector trailer sanity checks. - // 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; - } - } else { - PrintAndLogEx(SUCCESS, "ST passed checks, continuing..."); - } + 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))); @@ -7560,73 +7572,47 @@ static int CmdHF14AGen4Save(const char *Cmd) { return PM3_SUCCESS; } -static int CmdHF14AGen4_GDM_GetBlk(const char *Cmd) { +static int CmdHF14AGen4_GDM_ConfigBlk(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" + CLIParserInit(&ctx, "hf mf gdmconfig", + "Get configuration data from magic gen4 GDM card.", + "hf mf gdmconfig\n" ); void *argtable[] = { arg_param_begin, - arg_int1("b", "blk", "", "block number"), - arg_lit0("v", "verbose", "verbose output"), arg_str0("k", "key", "", "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); + CLIExecWithReturn(ctx, Cmd, argtable, true); int keylen = 0; uint8_t key[6] = {0}; - CLIGetHexWithReturn(ctx, 3, key, &keylen); + CLIGetHexWithReturn(ctx, 1, 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)); + SendCommandNG(CMD_HF_MIFARE_G4_GDM_CONFIG, (uint8_t *)&payload, sizeof(payload)); 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"); 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, ""); - } + PrintAndLogEx(SUCCESS, "config... %s", sprint_hex(d, resp.length)); + PrintAndLogEx(NORMAL, ""); } return resp.status; @@ -7636,7 +7622,9 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) { CLIParserContext *ctx; 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" ); void *argtable[] = { @@ -7644,8 +7632,9 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) { arg_int1(NULL, "blk", "", "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", "", "key, 6 hex bytes"), arg_str0("d", "data", "", "bytes to write, 16 hex bytes"), + arg_str0("k", "key", "", "key, 6 hex bytes"), + arg_lit0(NULL, "force", "override warnings"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -7661,13 +7650,15 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) { 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); + 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); if (blen != MFBLOCK_SIZE) { @@ -7687,6 +7678,10 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) { 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, "data: %s", sprint_hex(block, sizeof(block))); @@ -7985,7 +7980,7 @@ static command_t CommandTable[] = { {"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"}, {"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"}, {"-----------", 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"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"}, // {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"}, diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index 8071f7ea7..9f4be7376 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -540,9 +540,11 @@ This tag has simular commands to the [UFUID](#mifare-classic-directwrite-ufuid-v It seems to be developed by the same person. **OBS** + 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 @@ -579,6 +581,7 @@ Write config: 3. send 16 bytes **Warning** + Example of configuration to Perma lock tag: `85000000000000000000000000000008` @@ -596,7 +599,7 @@ It is unknown what kind of block 0 changes the tag supports hf mf gdmsetblk # Read 0xE0 configuration: -hf mf gdmgetblk +hf mf gdmconfig ``` diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index f490cc419..b99bb8430 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -689,6 +689,7 @@ typedef struct { // Gen 4 GDM magic cards #define CMD_HF_MIFARE_G4_GDM_RDBL 0x0870 #define CMD_HF_MIFARE_G4_GDM_WRBL 0x0871 +#define CMD_HF_MIFARE_G4_GDM_CONFIG 0x0872 #define CMD_UNKNOWN 0xFFFF diff --git a/include/protocols.h b/include/protocols.h index 8450dc58a..5900b377c 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -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_WRITEBLOCK 0xA8 #define MIFARE_MAGIC_GDM_READBLOCK 0xE0 +#define MIFARE_MAGIC_GDM_READBLOCK_1 0xE1 #define MIFARE_EV1_PERSONAL_UID 0x40 #define MIFARE_EV1_SETMODE 0x43