From 51f9d799cfecbc5a4a3e071903a2ac13f3ba3306 Mon Sep 17 00:00:00 2001 From: you Date: Mon, 11 Dec 2023 20:29:59 +0100 Subject: [PATCH 1/9] Add fuzzing mode for MF1 tags - firmware --- firmware/application/src/app_cmd.c | 20 +++++++++++++++++-- firmware/application/src/data_cmd.h | 2 ++ .../application/src/rfid/nfctag/hf/nfc_mf1.c | 17 ++++++++++++++++ .../application/src/rfid/nfctag/hf/nfc_mf1.h | 6 +++++- .../application/src/rfid/nfctag/hf/nfc_ntag.c | 1 + 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index 45b833a8..776940fa 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -740,6 +740,19 @@ static data_frame_tx_t *cmd_processor_mf1_get_detection_log(uint16_t cmd, uint16 return data_frame_make(cmd, STATUS_SUCCESS, length, resp); } +static data_frame_tx_t *cmd_processor_mf1_set_mode_fuzzing(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + if (length != 1 || data[0] > 1) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); + } + nfc_tag_mf1_set_mode_fuzzing(data[0]); + return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL); +} + +static data_frame_tx_t *cmd_processor_mf1_get_mode_fuzzing(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + uint8_t is_fuzzing = nfc_tag_mf1_is_mode_fuzzing(); + return data_frame_make(cmd, STATUS_SUCCESS, 1, (uint8_t *)(&is_fuzzing)); +} + static data_frame_tx_t *cmd_processor_mf1_write_emu_block_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { if (length == 0 || (((length - 1) % NFC_TAG_MF1_DATA_SIZE) != 0)) { return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); @@ -864,13 +877,14 @@ static data_frame_tx_t *cmd_processor_delete_slot_tag_nick(uint16_t cmd, uint16_ } static data_frame_tx_t *cmd_processor_mf1_get_emulator_config(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { - uint8_t mf1_info[5] = {}; + uint8_t mf1_info[6] = {}; mf1_info[0] = nfc_tag_mf1_is_detection_enable(); mf1_info[1] = nfc_tag_mf1_is_gen1a_magic_mode(); mf1_info[2] = nfc_tag_mf1_is_gen2_magic_mode(); mf1_info[3] = nfc_tag_mf1_is_use_mf1_coll_res(); mf1_info[4] = nfc_tag_mf1_get_write_mode(); - return data_frame_make(cmd, STATUS_SUCCESS, 5, mf1_info); + mf1_info[5] = nfc_tag_mf1_is_mode_fuzzing(); + return data_frame_make(cmd, STATUS_SUCCESS, 6, mf1_info); } static data_frame_tx_t *cmd_processor_mf1_get_gen1a_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { @@ -1092,6 +1106,8 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_MF1_GET_WRITE_MODE, NULL, cmd_processor_mf1_get_write_mode, NULL }, { DATA_CMD_MF1_SET_WRITE_MODE, NULL, cmd_processor_mf1_set_write_mode, NULL }, { DATA_CMD_HF14A_GET_ANTI_COLL_DATA, NULL, cmd_processor_hf14a_get_anti_coll_data, NULL }, + { DATA_CMD_MF1_SET_MODE_FUZZING, NULL, cmd_processor_mf1_set_mode_fuzzing, NULL }, + { DATA_CMD_MF1_GET_MODE_FUZZING, NULL, cmd_processor_mf1_get_mode_fuzzing, NULL }, { DATA_CMD_EM410X_SET_EMU_ID, NULL, cmd_processor_em410x_set_emu_id, NULL }, { DATA_CMD_EM410X_GET_EMU_ID, NULL, cmd_processor_em410x_get_emu_id, NULL }, diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index e605ff97..65965e14 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -105,6 +105,8 @@ #define DATA_CMD_MF1_GET_WRITE_MODE (4016) #define DATA_CMD_MF1_SET_WRITE_MODE (4017) #define DATA_CMD_HF14A_GET_ANTI_COLL_DATA (4018) +#define DATA_CMD_MF1_SET_MODE_FUZZING (4019) +#define DATA_CMD_MF1_GET_MODE_FUZZING (4020) // // ****************************************************************** diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c index 02776923..d3fa9220 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c @@ -716,6 +716,12 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { memcpy(respTrailerInfo->key_b, m_tag_trailer_info->key_b, 6); } } else { + /* If tag is marked as fuzzer: randomize data for next read */ + if (m_tag_information->config.mode_fuzzing) { + for (uint8_t i = 0; i < 16; i++) { + m_tag_information->memory[CurrentAddress][i] = (uint8_t) rand(); + } + } // For data, just return to the corresponding location sector memcpy(m_tag_tx_buffer.tx_raw_buffer, m_tag_information->memory[CurrentAddress], 16); } @@ -1157,6 +1163,7 @@ bool nfc_tag_mf1_data_factory(uint8_t slot, tag_specific_type_t tag_type) { p_mf1_information->config.use_mf1_coll_res = false; p_mf1_information->config.mode_block_write = NFC_TAG_MF1_WRITE_NORMAL; p_mf1_information->config.detection_enable = false; + p_mf1_information->config.mode_fuzzing = false; // save data to flash tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); @@ -1193,6 +1200,16 @@ uint32_t nfc_tag_mf1_detection_log_count(void) { return m_auth_log.count; } +// Settling whether mode fuzzing is on or off +void nfc_tag_mf1_set_mode_fuzzing(bool fuzzing) { + m_tag_information->config.mode_fuzzing = fuzzing; +} + +// Whether mode fuzzing is on or off +bool nfc_tag_mf1_is_mode_fuzzing(void) { + return m_tag_information->config.mode_fuzzing; +} + // Set gen1a magic mode void nfc_tag_mf1_set_gen1a_magic_mode(bool enable) { m_tag_information->config.mode_gen1a_magic = enable; diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h index 35217149..1fd6ad3a 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h @@ -71,8 +71,10 @@ typedef struct { uint8_t detection_enable: 1; // Allow to write block 0 (CUID/gen2 mode) uint8_t mode_gen2_magic: 1; + // Change content of tag each time it has been read + uint8_t mode_fuzzing: 1; // reserve - uint8_t reserved1: 4; + uint8_t reserved1: 3; uint8_t reserved2; uint8_t reserved3; } nfc_tag_mf1_configure_t; @@ -147,6 +149,8 @@ void nfc_tag_mf1_set_detection_enable(bool enable); bool nfc_tag_mf1_is_detection_enable(void); void nfc_tag_mf1_detection_log_clear(void); uint32_t nfc_tag_mf1_detection_log_count(void); +void nfc_tag_mf1_set_mode_fuzzing(bool fuzzing); +bool nfc_tag_mf1_is_mode_fuzzing(void); nfc_tag_14a_coll_res_reference_t *get_mifare_coll_res(void); nfc_tag_14a_coll_res_reference_t *get_saved_mifare_coll_res(void); void nfc_tag_mf1_set_gen1a_magic_mode(bool enable); diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c index a90f3c7b..b358499c 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c @@ -284,6 +284,7 @@ bool nfc_tag_ntag_data_factory(uint8_t slot, tag_specific_type_t tag_type) { // default ntag config p_ntag_information->config.mode_uid_magic = true; p_ntag_information->config.detection_enable = false; + p_ntag_information->config.mode_fuzzing = false; // save data to flash tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); From be625d82bb884fb8a64e95770c735c51f032b7c7 Mon Sep 17 00:00:00 2001 From: you Date: Mon, 11 Dec 2023 20:31:37 +0100 Subject: [PATCH 2/9] Add CLI option to enable/disable fuzzing mode on MF1 tags --- software/script/chameleon_cli_unit.py | 23 +++++++++++++++++++++++ software/script/chameleon_cmd.py | 17 +++++++++++++++-- software/script/chameleon_enum.py | 2 ++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index b551bb9c..23185599 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -1263,6 +1263,8 @@ def args_parser(self) -> ArgumentParserNoExit: log_group = parser.add_mutually_exclusive_group() log_group.add_argument('--enable-log', action='store_true', help="Enable logging of MFC authentication data") log_group.add_argument('--disable-log', action='store_true', help="Disable logging of MFC authentication data") + log_group.add_argument('--enable-fuzzing', action='store_true', help="Enable fuzzing mode for slot (i.e. changing data at each read)") + log_group.add_argument('--disable-fuzzing', action='store_true', help="Disable fuzzing mode for slot (i.e. changing data at each read)") return parser def on_exec(self, args: argparse.Namespace): @@ -1292,6 +1294,7 @@ def on_exec(self, args: argparse.Namespace): block_anti_coll_mode = mfc_config["block_anti_coll_mode"] write_mode = MifareClassicWriteMode(mfc_config["write_mode"]) detection = mfc_config["detection"] + fuzzing = mfc_config["fuzzing"] change_requested, change_done, uid, atqa, sak, ats = self.update_hf14a_anticoll(args, uid, atqa, sak, ats) if args.enable_gen1a: change_requested = True @@ -1366,6 +1369,22 @@ def on_exec(self, args: argparse.Namespace): change_done = True else: print(f'{CY}Requested logging of MFC authentication data already disabled{C0}') + if args.enable_fuzzing: + change_requested = True + if not fuzzing: + fuzzing = True + self.cmd.mf1_set_mode_fuzzing(fuzzing) + change_done = True + else: + print(f'{CY}Requested fuzzing mode of MFC authentication data already enabled{C0}') + elif args.disable_fuzzing: + change_requested = True + if fuzzing: + fuzzing = False + self.cmd.mf1_set_mode_fuzzing(fuzzing) + change_done = True + else: + print(f'{CY}Requested logging of MFC authentication data already disabled{C0}') if change_done: print(' - MF1 Emulator settings updated') @@ -1390,6 +1409,8 @@ def on_exec(self, args: argparse.Namespace): print(f'- {"Write mode:":40}{CR}invalid value!{C0}') print( f'- {"Log (mfkey32) mode:":40}{f"{CG}enabled{C0}" if detection else f"{CR}disabled{C0}"}') + print( + f'- {"Fuzzing mode:":40}{f"{CG}enabled{C0}" if fuzzing else f"{CR}disabled{C0}"}') @hf_mfu.command('rdpg') @@ -1641,6 +1662,8 @@ def on_exec(self, args: argparse.Namespace): print( f' {"Log (mfkey32) mode:":40}' f'{f"{CG}enabled{C0}" if config["detection"] else f"{CR}disabled{C0}"}') + print( + f' {"Fuzzing mode:":40}{f"{CG}enabled{C0}" if config["fuzzing"] else f"{CR}disabled{C0}"}') # LF field_length = maxnamelength+slotnames[fwslot]["lf"]["metalen"]+1 diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 12c11cc1..d101d184 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -511,6 +511,17 @@ def mf1_get_detection_log(self, index: int): resp.parsed = result_list return resp + @expect_response(Status.SUCCESS) + def mf1_set_mode_fuzzing(self, fuzzing: bool): + """ + Set whether to enable the detection of the current card slot. + + :param enable: Whether to enable + :return: + """ + data = struct.pack('!B', fuzzing) + return self.device.send_cmd_sync(Command.MF1_SET_MODE_FUZZING, data) + @expect_response(Status.SUCCESS) def mf1_write_emu_block_data(self, block_start: int, block_data: bytes): """ @@ -602,17 +613,19 @@ def mf1_get_emulator_config(self): [2] - mf1_is_gen2_magic_mode [3] - mf1_is_use_mf1_coll_res (use UID/BCC/SAK/ATQA from 0 block) [4] - mf1_get_write_mode + [5] - mf1_is_mode_fuzzing :return: """ resp = self.device.send_cmd_sync(Command.MF1_GET_EMULATOR_CONFIG) if resp.status == Status.SUCCESS: - b1, b2, b3, b4, b5 = struct.unpack('!????B', resp.data) + b1, b2, b3, b4, b5, b6 = struct.unpack('!?????B', resp.data) resp.parsed = {'detection': b1, 'gen1a_mode': b2, 'gen2_mode': b3, 'block_anti_coll_mode': b4, - 'write_mode': b5} + 'write_mode': b5, + 'fuzzing': b6} return resp @expect_response(Status.SUCCESS) diff --git a/software/script/chameleon_enum.py b/software/script/chameleon_enum.py index 58d63595..85d59874 100644 --- a/software/script/chameleon_enum.py +++ b/software/script/chameleon_enum.py @@ -94,6 +94,8 @@ class Command(enum.IntEnum): MF1_GET_WRITE_MODE = 4016 MF1_SET_WRITE_MODE = 4017 HF14A_GET_ANTI_COLL_DATA = 4018 + MF1_SET_MODE_FUZZING = 4019 + MF1_GET_MODE_FUZZING = 4020 EM410X_SET_EMU_ID = 5000 EM410X_GET_EMU_ID = 5001 From 66c6a7b5169f6ba657a61e301580f98ce74cc97e Mon Sep 17 00:00:00 2001 From: you Date: Mon, 11 Dec 2023 20:42:02 +0100 Subject: [PATCH 3/9] (Fix) Remove line committed by mistake --- firmware/application/src/rfid/nfctag/hf/nfc_ntag.c | 1 - 1 file changed, 1 deletion(-) diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c index b358499c..a90f3c7b 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c @@ -284,7 +284,6 @@ bool nfc_tag_ntag_data_factory(uint8_t slot, tag_specific_type_t tag_type) { // default ntag config p_ntag_information->config.mode_uid_magic = true; p_ntag_information->config.detection_enable = false; - p_ntag_information->config.mode_fuzzing = false; // save data to flash tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); From 129ea884c5c4935dd1c9bb96c7ed4030735596ce Mon Sep 17 00:00:00 2001 From: you Date: Tue, 12 Dec 2023 01:14:22 +0100 Subject: [PATCH 4/9] Add CLI command to generate a fuzzing tag with keys --- software/script/chameleon_cli_unit.py | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index 23185599..538658ce 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -850,6 +850,45 @@ def on_exec(self, args: argparse.Namespace): return +@hf_mf.command('fuzz') +class HFMFFuzz(ReaderRequiredUnit): + + def args_parse_key(self, arg): + key_re = re.compile(r"^(?P([0-9]|1[0-5])):(?P(A|B)):(?P([0-9A-Fa-f]{12}))$") + m = key_re.match(arg) + if not m: + raise argparse.ArgumentTypeError("Expected format: 0-15:A-B:") + return (int(m.group('idx')), m.group('ab'), bytes.fromhex(m.group('key'))) + + def args_parser(self) -> ArgumentParserNoExit: + parser = ArgumentParserNoExit() + parser.description = 'Mifare Classic fuzzer tag' + parser.add_argument('-k', '--key', type=self.args_parse_key, required=False, action="extend", nargs="*", + help="Key to use for a given block") + return parser + + def on_exec(self, args: argparse.Namespace): + keys = [] + for i in range(16): + keys.append({ + 'a': bytes.fromhex("FFFFFFFFFFFF"), + 'b': bytes.fromhex("000000000000"), + }) + for keyarg in args.key: + keys[keyarg[0]][keyarg[1].lower()] = keyarg[2] + # generate and write blocks to emulate + for block_idx in range(64): + # key block + if block_idx % 4 == 3: + data = keys[block_idx // 4]['a'] + b'\xff' * 4 + keys[block_idx // 4]['b'] + else: + data = b'\x00' * 16 + self.cmd.mf1_write_emu_block_data(block_idx, data) + # set fuzzer mode + self.cmd.mf1_set_mode_fuzzing(True) + return + + @hf_mf.command('rdbl') class HFMFRDBL(MF1AuthArgsUnit): def args_parser(self) -> ArgumentParserNoExit: From b02475cbce5c2e80be0d4adbd8ed309a1bd6a20f Mon Sep 17 00:00:00 2001 From: you Date: Fri, 29 Dec 2023 12:20:21 +0100 Subject: [PATCH 5/9] Improve CLI argument parsing and help message --- software/script/chameleon_cli_unit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index ab23a2ec..82b24076 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -858,14 +858,14 @@ def args_parse_key(self, arg): key_re = re.compile(r"^(?P([0-9]|1[0-5])):(?P(A|B)):(?P([0-9A-Fa-f]{12}))$") m = key_re.match(arg) if not m: - raise argparse.ArgumentTypeError("Expected format: 0-15:A-B:") + raise argparse.ArgumentTypeError("Expected format: :: where is between 0-15 and is 6 bytes long") return (int(m.group('idx')), m.group('ab'), bytes.fromhex(m.group('key'))) def args_parser(self) -> ArgumentParserNoExit: parser = ArgumentParserNoExit() parser.description = 'Mifare Classic fuzzer tag' - parser.add_argument('-k', '--key', type=self.args_parse_key, required=False, action="extend", nargs="*", - help="Key to use for a given block") + parser.add_argument('-k', '--key', type=self.args_parse_key, required=False, action="extend", nargs="+", + help="Key to use for a given sector") return parser def on_exec(self, args: argparse.Namespace): From 3c1744b045117f3fb563c3f5cbff07409ce91e22 Mon Sep 17 00:00:00 2001 From: you Date: Fri, 29 Dec 2023 12:56:34 +0100 Subject: [PATCH 6/9] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6781907a..c3dc51df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ 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] + - Add per-slot fuzzing-mode setting to randomize data at each read for MF - Skip already used items `hf mf elog --decrypt` (@p-l-) - Parallelize mfkey32v2 processes called from CLI (@p-l-) - Added support for mifare classic value block operations (@taichunmin) From 06c07729debaec2922d9c7c896dea7184a3f2deb Mon Sep 17 00:00:00 2001 From: rickNmorty2 <155145184+rickNmorty2@users.noreply.github.com> Date: Sun, 28 Jan 2024 13:02:32 +0100 Subject: [PATCH 7/9] Update software/script/chameleon_cli_unit.py Thanks Co-authored-by: Pierre --- software/script/chameleon_cli_unit.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index 82b24076..d3075cdd 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -854,9 +854,10 @@ def on_exec(self, args: argparse.Namespace): @hf_mf.command('fuzz') class HFMFFuzz(ReaderRequiredUnit): + key_re = re.compile(r"^(?P([0-9]|1[0-5])):(?P(A|B)):(?P([0-9A-Fa-f]{12}))$") + def args_parse_key(self, arg): - key_re = re.compile(r"^(?P([0-9]|1[0-5])):(?P(A|B)):(?P([0-9A-Fa-f]{12}))$") - m = key_re.match(arg) + m = cls.key_re.match(arg) if not m: raise argparse.ArgumentTypeError("Expected format: :: where is between 0-15 and is 6 bytes long") return (int(m.group('idx')), m.group('ab'), bytes.fromhex(m.group('key'))) From 6a03449044557ec239d1d5be7b20538e121360f2 Mon Sep 17 00:00:00 2001 From: rickNmorty2 <155145184+rickNmorty2@users.noreply.github.com> Date: Sun, 28 Jan 2024 13:03:10 +0100 Subject: [PATCH 8/9] Update software/script/chameleon_cli_unit.py Co-authored-by: Pierre --- software/script/chameleon_cli_unit.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index d3075cdd..33c8ee2b 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -870,12 +870,7 @@ def args_parser(self) -> ArgumentParserNoExit: return parser def on_exec(self, args: argparse.Namespace): - keys = [] - for i in range(16): - keys.append({ - 'a': bytes.fromhex("FFFFFFFFFFFF"), - 'b': bytes.fromhex("000000000000"), - }) + keys = [{'a': b'\xff\xff\xff\xff\xff\xff', 'b': b'\x00\x00\x00\x00\x00\x00'} for _ in range(16)] for keyarg in args.key: keys[keyarg[0]][keyarg[1].lower()] = keyarg[2] # generate and write blocks to emulate From 86c41ad1f2f5525030013a8c4a677ba43599cb54 Mon Sep 17 00:00:00 2001 From: rickNmorty2 <155145184+rickNmorty2@users.noreply.github.com> Date: Tue, 23 Apr 2024 23:18:20 +0200 Subject: [PATCH 9/9] Update software/script/chameleon_cli_unit.py Co-authored-by: Pierre --- software/script/chameleon_cli_unit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index 33c8ee2b..648735d0 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -857,7 +857,7 @@ class HFMFFuzz(ReaderRequiredUnit): key_re = re.compile(r"^(?P([0-9]|1[0-5])):(?P(A|B)):(?P([0-9A-Fa-f]{12}))$") def args_parse_key(self, arg): - m = cls.key_re.match(arg) + m = self.key_re.match(arg) if not m: raise argparse.ArgumentTypeError("Expected format: :: where is between 0-15 and is 6 bytes long") return (int(m.group('idx')), m.group('ab'), bytes.fromhex(m.group('key')))