From b5ecdde19ee2c07cfbfec31e774c1d3fa8cd85da Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 29 Aug 2024 12:27:11 +0200 Subject: [PATCH] fixes and textual --- CHANGELOG.md | 2 + client/src/cmdhf14a.c | 2 + client/src/cmdhfmf.c | 23 ++--- client/src/cmdhfmfu.c | 109 +++++++++++++++++++++--- client/src/cmdhfmfu.h | 3 +- tools/hitag2crack/crack5opencl/opencl.c | 4 +- 6 files changed, 117 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1090e226..0e269bcc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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] +- Fixed `hf mfu wrbl` - compabilty write only writes 4 bytes. Now handled correct (@iceman1001) +- Changed `hf mfu info` - better magic tag detection (@iceman1001) - Added ELECTRA pattern decoding in `lf search` (@CiRIP) - Firmware size optimization, skipping unused FPGA bitstreams (@douniwan5788) - Added pretty Hitag S config parsing (@CiRIP) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index bb6a7a910..d826ddeb2 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2591,6 +2591,8 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { return PM3_EFAILED; } + PrintAndLogEx(INFO, ""); + uint16_t isMagic = 0; if (isMifareClassic || isMifareMini) { diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index a5580a9f4..9cc25462c 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -2512,13 +2512,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { arg_lit0("l", "legacy", "legacy mode (use the slow `hf mf chk`)"), arg_lit0("v", "verbose", "verbose output"), + arg_lit0(NULL, "ns", "No save to file"), + arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"), arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (default)"), arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"), arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"), - arg_lit0(NULL, "ns", "No save"), - arg_lit0(NULL, "in", "None (use CPU regular instruction set)"), #if defined(COMPILER_HAS_SIMD_X86) arg_lit0(NULL, "im", "MMX"), @@ -2559,12 +2559,12 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { bool legacy_mfchk = arg_get_lit(ctx, 7); bool verbose = arg_get_lit(ctx, 8); - bool m0 = arg_get_lit(ctx, 9); - bool m1 = arg_get_lit(ctx, 10); - bool m2 = arg_get_lit(ctx, 11); - bool m4 = arg_get_lit(ctx, 12); + bool no_save = arg_get_lit(ctx, 9); - bool no_save = arg_get_lit(ctx, 13); + bool m0 = arg_get_lit(ctx, 10); + bool m1 = arg_get_lit(ctx, 11); + bool m2 = arg_get_lit(ctx, 12); + bool m4 = arg_get_lit(ctx, 13); bool in = arg_get_lit(ctx, 14); #if defined(COMPILER_HAS_SIMD_X86) @@ -3334,7 +3334,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { arg_int0(NULL, "blk", "", "block number (single block recovery mode)"), arg_lit0("a", NULL, "single block recovery key A"), arg_lit0("b", NULL, "single block recovery key B"), - arg_lit0(NULL, "no-default", "Don't add the bunch of extra default keys"), + arg_lit0(NULL, "no-default", "Skip check default keys"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -3773,7 +3773,7 @@ static int CmdHF14AMfChk(const char *Cmd) { arg_lit0(NULL, "emu", "Fill simulator keys from found keys"), arg_lit0(NULL, "dump", "Dump found keys to binary file"), arg_str0("f", "file", "", "Filename of dictionary"), - arg_lit0(NULL, "no-default", "Don't add the bunch of extra default keys"), + arg_lit0(NULL, "no-default", "Skip check default keys"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -9565,12 +9565,13 @@ static int CmdHF14AMfInfo(const char *Cmd) { uint8_t k08s[6] = {0xA3, 0x96, 0xEF, 0xA4, 0xE2, 0x4F}; if (mfReadBlock(0, 4, k08s, blockdata) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Backdoor key..... " _RED_("%02X%02X%02X%02X%02X%02X"), k08s[0], k08s[1], k08s[2], k08s[3], k08s[4], k08s[5]); + PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08s, sizeof(k08s))); fKeyType = MF_KEY_BD08S; } + uint8_t k08[6] = {0xA3, 0x16, 0x67, 0xA8, 0xCE, 0xC1}; if (mfReadBlock(0, 4, k08, blockdata) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Backdoor key..... " _RED_("%02X%02X%02X%02X%02X%02X"), k08[0], k08[1], k08[2], k08[3], k08[4], k08[5]); + PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%02X%02X%02X%02X%02X%02X"), k08[0], k08[1], k08[2], k08[3], k08[4], k08[5]); fKeyType = MF_KEY_BD08; } diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index c79ef1521..0e2099f6c 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -233,6 +233,47 @@ static int ul_print_nxp_silicon_info(uint8_t *card_uid) { return PM3_SUCCESS; } +static int get_ulc_3des_key_magic(uint64_t magic_type, uint8_t *key) { + + mf_readblock_ex_t payload = { + .read_cmd = ISO14443A_CMD_READBLOCK, + .block_no = 0x2C, + }; + + if ((magic_type & MFU_TT_MAGIC_1A) == MFU_TT_MAGIC_1A) { + payload.wakeup = MF_WAKE_GEN1A; + payload.auth_cmd = 0; + } else if ((magic_type & MFU_TT_MAGIC_1B) == MFU_TT_MAGIC_1B) { + payload.wakeup = MF_WAKE_GEN1B; + payload.auth_cmd = 0; + } else if ((magic_type & MFU_TT_MAGIC_4) == MFU_TT_MAGIC_4) { + payload.wakeup = MF_WAKE_GDM_ALT; + payload.auth_cmd = 0; + } else if ((magic_type & MFU_TT_MAGIC_NTAG21X) == MFU_TT_MAGIC_NTAG21X) { + payload.wakeup = MF_WAKE_WUPA; + payload.auth_cmd = 0; + } else { + payload.wakeup = MF_WAKE_WUPA; + payload.auth_cmd = MIFARE_MAGIC_GDM_AUTH_KEY; + } + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL_EX, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL_EX, &resp, 1500) == false) { + PrintAndLogEx(WARNING, "command execute timeout"); + return PM3_ETIMEOUT; + } + + if (resp.status == PM3_SUCCESS && resp.length == MFBLOCK_SIZE) { + uint8_t *d = resp.data.asBytes; + reverse_array(d, 8); + reverse_array(d + 8, 8); + memcpy(key, d, MFBLOCK_SIZE); + } + + return resp.status; +} /* The 7 MSBits (=n) code the storage size itself based on 2^n, @@ -1958,7 +1999,6 @@ static int mfu_fingerprint(uint64_t tagtype, bool hasAuthKey, uint8_t *authkey, clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_READCARD, 0, pages, keytype, authkey, ak_len); - PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { PrintAndLogEx(WARNING, "Command execute timeout"); @@ -2352,7 +2392,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) { mfu_fingerprint(tagtype, has_auth_key, authkeyptr, ak_len); - if ((tagtype & MFU_TT_MAGIC)) { + DropField(); + + if ((tagtype & MFU_TT_MAGIC) == MFU_TT_MAGIC) { //just read key uint8_t ulc_deskey[16] = {0x00}; status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); @@ -2361,12 +2403,15 @@ static int CmdHF14AMfUInfo(const char *Cmd) { PrintAndLogEx(ERR, "Error: tag didn't answer to READ magic"); return PM3_ESOFT; } + if (status == 16) { ulc_print_3deskey(ulc_deskey); } + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; + } else { - DropField(); // if we called info with key, just return if (has_auth_key) { PrintAndLogEx(NORMAL, ""); @@ -2612,9 +2657,10 @@ static int CmdHF14AMfUInfo(const char *Cmd) { } out: + DropField(); + mfu_fingerprint(tagtype, has_auth_key, authkeyptr, ak_len); - DropField(); if (locked) { PrintAndLogEx(INFO, "\nTag appears to be locked, try using a key to get more info"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen -r`") " to get see known pwd gen algo suggestions"); @@ -2718,8 +2764,30 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { PrintAndLogEx(INFO, "Using %s " _GREEN_("%s"), (ak_len == 16) ? "3des" : "pwd", sprint_hex(authenticationkey, ak_len)); } - // Send write Block - int res = mfu_write_block(data, datalen, has_auth_key, has_pwd, auth_key_ptr, blockno); + + // Send write Block. + uint8_t *d = data; + int res = 0; + if (datalen == 16) { + // Comp write may take 16bytes, but only write 4bytes. See UL-C datasheet + for (uint8_t i = 0; i < 4; i++ ) { + + res = mfu_write_block(d, 4, has_auth_key, has_pwd, auth_key_ptr, blockno + i); + if ( res == PM3_SUCCESS) { + d += 4; + } else { + PrintAndLogEx(INFO, "Write ( %s )", _RED_("fail")); + return PM3_ESOFT; + } + } + + if (res == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf mfu rdbl -b %u") "` to verify ", blockno); + } + + } else { + res = mfu_write_block(data, datalen, has_auth_key, has_pwd, auth_key_ptr, blockno); switch (res) { case PM3_SUCCESS: { PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )"); @@ -2737,6 +2805,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { break; } } + } return res; } @@ -3700,7 +3769,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { PrintAndLogEx(INFO, "Restoring configuration blocks"); - PrintAndLogEx(INFO, "authentication with keytype[%x] %s\n", (uint8_t)(keytype & 0xff), sprint_hex(p_authkey, 4)); + PrintAndLogEx(INFO, "Authentication with keytype[%x] %s\n", (uint8_t)(keytype & 0xff), sprint_hex(p_authkey, 4)); #if defined ICOPYX // otp, uid, lock, dynlockbits, cfg0, cfg1, pwd, pack @@ -3715,7 +3784,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); wait4response(b); - PrintAndLogEx(INFO, "special block written %u - %s\n", b, sprint_hex(data, 4)); + PrintAndLogEx(INFO, "special block written " _YELLOW_("%u") " - %s", b, sprint_hex(data, 4)); } } @@ -5506,9 +5575,9 @@ static int CmdHF14AMfuWipe(const char *Cmd) { "you will need to call it with password in order to wipe the config and sett default pwd/pack\n" "Abort by pressing a key\n" "New password.... FFFFFFFF\n" - "New 3-DES key... 425245414B4D454946594F5543414E21\n", + "New 3-DES key... 49454D4B41455242214E4143554F5946\n", "hf mfu wipe\n" - "hf mfu wipe -k 425245414B4D454946594F5543414E21\n" + "hf mfu wipe -k 49454D4B41455242214E4143554F5946\n" ); void *argtable[] = { arg_param_begin, @@ -5566,6 +5635,21 @@ static int CmdHF14AMfuWipe(const char *Cmd) { ul_print_type(tagtype, 0); + // GDM / GEN1A / GEN4 / NTAG21x read the key + if (ak_len == 0) { + + DropField(); + + int res = get_ulc_3des_key_magic(tagtype, auth_key_ptr); + if (res != PM3_SUCCESS) { + return res; + } + PrintAndLogEx(SUCCESS, "Using 3DES key... %s", sprint_hex_inrow(auth_key_ptr, 16)); + has_auth_key = true; + } + + DropField(); + PrintAndLogEx(INFO, "Start wiping..."); PrintAndLogEx(INFO, "-----+-----------------------------"); // time to wipe card @@ -5656,6 +5740,7 @@ static int CmdHF14AMfuWipe(const char *Cmd) { res = mfu_write_block(data, MFU_BLOCK_SIZE, has_auth_key, has_pwd, auth_key_ptr, i); } */ + int res = mfu_write_block(data, MFU_BLOCK_SIZE, has_auth_key, has_pwd, auth_key_ptr, i); PrintAndLogEx(INFO, " %3d | %s" NOLF, i, sprint_hex(data, MFU_BLOCK_SIZE)); @@ -5685,8 +5770,8 @@ ulc: if ((tagtype & MFU_TT_UL_C) == MFU_TT_UL_C) { uint8_t key[16] = { - 0x42, 0x52, 0x45, 0x41, 0x4B, 0x4D, 0x45, 0x49, - 0x46, 0x59, 0x4F, 0x55, 0x43, 0x41, 0x4E, 0x21 + 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, + 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }; clearCommandBuffer(); diff --git a/client/src/cmdhfmfu.h b/client/src/cmdhfmfu.h index 00d95dfdd..37dbff558 100644 --- a/client/src/cmdhfmfu.h +++ b/client/src/cmdhfmfu.h @@ -94,7 +94,8 @@ int CmdHF14MfUTamper(const char *Cmd); #define MFU_TT_UL_AES 0x100000000ULL #define MFU_TT_MAGIC_2 0x200000000ULL #define MFU_TT_MAGIC_4 0x400000000ULL -#define MFU_TT_MAGIC_NTAG21X 0x800000000ULL +#define MFU_TT_MAGIC_4_GDM 0x800000000ULL +#define MFU_TT_MAGIC_NTAG21X 0x1000000000ULL #define MFU_TT_UL_MAGIC (MFU_TT_UL | MFU_TT_MAGIC) #define MFU_TT_UL_C_MAGIC (MFU_TT_UL_C | MFU_TT_MAGIC) // Don't forget to fill UL_TYPES_ARRAY and UL_MEMORY_ARRAY if new types are added diff --git a/tools/hitag2crack/crack5opencl/opencl.c b/tools/hitag2crack/crack5opencl/opencl.c index 2265cef2e..deec49e92 100644 --- a/tools/hitag2crack/crack5opencl/opencl.c +++ b/tools/hitag2crack/crack5opencl/opencl.c @@ -185,7 +185,7 @@ int discoverDevices(unsigned int profile_selected, uint32_t device_types_selecte return -7; } - strncpy(tmp_buf, "N/A\0", tmp_len); + strncpy(tmp_buf, "n/a\0", tmp_len); } if (verbose) { @@ -454,7 +454,7 @@ int discoverDevices(unsigned int profile_selected, uint32_t device_types_selecte return -7; } - strncpy(tmp_buf, "N/A\0", tmp_len); + strncpy(tmp_buf, "n/a\0", tmp_len); } if (verbose) {