diff --git a/docs/protocol.md b/docs/protocol.md index 8d333d9..eaee7dc 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -241,7 +241,7 @@ Notes: * Response: 4+N*8 bytes: `uid[4]` followed by N tuples of `nt[4]|nt_enc[4]`. All values as U32. * CLI: cf `hf mf nested` on static nonce tag ### 2004: MF1_DARKSIDE_ACQUIRE -* Command: 4 bytes: `type_target|block_target|first_recover|sync_max` +* Command: 4 bytes: `type_target|block_target|first_recover|sync_max`. Type=0x60 for key A, 0x61 for key B. * Response: 1 byte if Darkside failed, according to `mf1_darkside_status_t` enum, else 33 bytes `darkside_status|uid[4]|nt1[4]|par[8]|ks1[8]|nr[4]|ar[4]` * `darkside_status` @@ -253,29 +253,29 @@ Notes: * `ar[4]` U32 * CLI: cf `hf mf darkside` ### 2005: MF1_DETECT_NT_DIST -* Command: 8 bytes: `type_known|block_known|key_known[6]`. Key as 6 bytes. +* Command: 8 bytes: `type_known|block_known|key_known[6]`. Key as 6 bytes. Type=0x60 for key A, 0x61 for key B. * Response: 8 bytes: `uid[4]|dist[4]` * `uid[4]` U32 (format expected by `nested` tool) * `dist[4]` U32 * CLI: cf `hf mf nested` ### 2006: MF1_NESTED_ACQUIRE -* Command: 10 bytes: `type_known|block_known|key_known[6]|type_target|block_target`. Key as 6 bytes. +* Command: 10 bytes: `type_known|block_known|key_known[6]|type_target|block_target`. Key as 6 bytes. Type=0x60 for key A, 0x61 for key B. * Response: N*9 bytes: N tuples of `nt[4]|nt_enc[4]|par` * `nt[4]` U32 * `nt_enc[4]` U32 * `par` * CLI: cf `hf mf nested` ### 2007: MF1_AUTH_ONE_KEY_BLOCK -* Command: 8 bytes: `type|block|key[6]`. Key as 6 bytes. +* Command: 8 bytes: `type|block|key[6]`. Key as 6 bytes. Type=0x60 for key A, 0x61 for key B. * Response: no data * Status will be `HF_TAG_OK` if auth succeeded, else `MF_ERR_AUTH` * CLI: cf `hf mf nested` ### 2008: MF1_READ_ONE_BLOCK -* Command: 8 bytes: `type|block|key[6]`. Key as 6 bytes. +* Command: 8 bytes: `type|block|key[6]`. Key as 6 bytes. Type=0x60 for key A, 0x61 for key B. * Response: 16 bytes: `block_data[16]` * CLI: cf `hf mf rdbl` ### 2009: MF1_WRITE_ONE_BLOCK -* Command: 24 bytes: `type|block|key[6]|block_data[16]`. Key as 6 bytes. +* Command: 24 bytes: `type|block|key[6]|block_data[16]`. Key as 6 bytes. Type=0x60 for key A, 0x61 for key B. * Response: no data * CLI: cf `hf mf wrbl` ### 2010: HF14A_RAW diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index 2e4da45..7ad2a5a 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -378,21 +378,19 @@ class HF14AInfo(ReaderRequiredUnit): @hf_mf.command('nested') class HFMFNested(ReaderRequiredUnit): def args_parser(self) -> ArgumentParserNoExit: - type_choices = ['A', 'B', 'a', 'b'] parser = ArgumentParserNoExit() parser.description = 'Mifare Classic nested recover key' - parser.add_argument('-o', '--one', action='store_true', default=False, - help="one sector key recovery. Use block 0 Key A to find block 4 Key A") - parser.add_argument('--block-known', type=int, required=True, metavar="", - help="The block where the key of the card is known") - parser.add_argument('--type-known', type=str, required=True, choices=type_choices, - help="The key type of the tag") - parser.add_argument('--key-known', type=str, required=True, metavar="", help="tag sector key") - parser.add_argument('--block-target', type=int, metavar="", - help="The key of the target block to recover") - parser.add_argument('--type-target', type=str, choices=type_choices, - help="The type of the target block to recover") - # hf mf nested -o --block-known 0 --type-known A --key FFFFFFFFFFFF --block-target 4 --type-target A + parser.add_argument('--blk', '--known-block', type=int, required=True, metavar="", + help="Known key block number") + srctype_group = parser.add_mutually_exclusive_group() + srctype_group.add_argument('-a', '-A', action='store_true', help="Known key is A key (default)") + srctype_group.add_argument('-b', '-B', action='store_true', help="Known key is B key") + parser.add_argument('-k', '--key', type=str, required=True, metavar="", help="Known key") + # tblk required because only single block mode is supported for now + parser.add_argument('--tblk', '--target-block', type=int, required=True, metavar="", help="Target key block number") + dsttype_group = parser.add_mutually_exclusive_group() + dsttype_group.add_argument('--ta', '--tA', action='store_true', help="Target A key (default)") + dsttype_group.add_argument('--tb', '--tB', action='store_true', help="Target B key") return parser def from_nt_level_code_to_str(self, nt_level): @@ -474,34 +472,27 @@ class HFMFNested(ReaderRequiredUnit): return None def on_exec(self, args: argparse.Namespace): - block_known = args.block_known + block_known = args.blk + # default to A + type_known = 0x61 if args.b else 0x60 - type_known = args.type_known - type_known = 0x60 if type_known == 'A' or type_known == 'a' else 0x61 - - key_known: str = args.key_known + key_known: str = args.key if not re.match(r"^[a-fA-F0-9]{12}$", key_known): print("key must include 12 HEX symbols") return key_known: bytearray = bytearray.fromhex(key_known) - - if args.one: - block_target = args.block_target - type_target = args.type_target - if block_target is not None and type_target is not None: - type_target = 0x60 if type_target == 'A' or type_target == 'a' else 0x61 - print(f" - {C0}Nested recover one key running...{C0}") - key = self.recover_a_key(block_known, type_known, key_known, block_target, type_target) - if key is None: - print("No keys found, you can retry recover.") - else: - print(f" - Key Found: {key}") - else: - print("Please input block_target and type_target") - self.args_parser().print_help() + block_target = args.tblk + # default to A + type_target = 0x61 if args.tb else 0x60 + if block_known == block_target and type_known == type_target: + print(f"{CR}Target key already known{C0}") + return + print(f" - {C0}Nested recover one key running...{C0}") + key = self.recover_a_key(block_known, type_known, key_known, block_target, type_target) + if key is None: + print(f"{CY}No key found, you can retry.{C0}") else: - raise NotImplementedError("hf mf nested recover all key not implement.") - + print(f" - Block {block_target} Type {'A' if type_target == 0x60 else 'B'} Key Found: {CG}{key}{C0}") return