mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 05:13:46 -07:00
fm11rf08s_recovery: now usable as main or imported
This commit is contained in:
parent
37e6f2dea7
commit
59b6c0353d
1 changed files with 546 additions and 511 deletions
|
@ -44,17 +44,22 @@ NUM_SECTORS = 16
|
||||||
NUM_EXTRA_SECTORS = 1
|
NUM_EXTRA_SECTORS = 1
|
||||||
DICT_DEF = "mfc_default_keys.dic"
|
DICT_DEF = "mfc_default_keys.dic"
|
||||||
DEFAULT_KEYS = set()
|
DEFAULT_KEYS = set()
|
||||||
if os.path.basename(os.path.dirname(os.path.dirname(sys.argv[0]))) == 'client':
|
if __name__ == '__main__':
|
||||||
|
DIR_PATH = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||||
|
else:
|
||||||
|
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
if os.path.basename(os.path.dirname(DIR_PATH)) == 'client':
|
||||||
# dev setup
|
# dev setup
|
||||||
TOOLS_PATH = os.path.normpath(os.path.join(f"{os.path.dirname(sys.argv[0])}",
|
TOOLS_PATH = os.path.normpath(os.path.join(DIR_PATH,
|
||||||
"..", "..", "tools", "mfc", "card_only"))
|
"..", "..", "tools", "mfc", "card_only"))
|
||||||
DICT_DEF_PATH = os.path.normpath(os.path.join(f"{os.path.dirname(sys.argv[0])}",
|
DICT_DEF_PATH = os.path.normpath(os.path.join(DIR_PATH,
|
||||||
"..", "dictionaries", DICT_DEF))
|
"..", "dictionaries", DICT_DEF))
|
||||||
else:
|
else:
|
||||||
# assuming installed
|
# assuming installed
|
||||||
TOOLS_PATH = os.path.normpath(os.path.join(f"{os.path.dirname(sys.argv[0])}",
|
TOOLS_PATH = os.path.normpath(os.path.join(DIR_PATH,
|
||||||
"..", "tools"))
|
"..", "tools"))
|
||||||
DICT_DEF_PATH = os.path.normpath(os.path.join(f"{os.path.dirname(sys.argv[0])}",
|
DICT_DEF_PATH = os.path.normpath(os.path.join(DIR_PATH,
|
||||||
"dictionaries", DICT_DEF))
|
"dictionaries", DICT_DEF))
|
||||||
|
|
||||||
tools = {
|
tools = {
|
||||||
|
@ -70,45 +75,38 @@ for tool, bin in tools.items():
|
||||||
print(f"Cannot find {bin}, abort!")
|
print(f"Cannot find {bin}, abort!")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='A script combining staticnested* tools '
|
|
||||||
'to recover all keys from a FM11RF08S card.')
|
|
||||||
parser.add_argument('-x', '--init-check', action='store_true', help='Run an initial fchk for default keys')
|
|
||||||
parser.add_argument('-y', '--final-check', action='store_true', help='Run a final fchk with the found keys')
|
|
||||||
parser.add_argument('-k', '--keep', action='store_true', help='Keep generated dictionaries after processing')
|
|
||||||
parser.add_argument('-d', '--debug', action='store_true', help='Enable debug mode')
|
|
||||||
parser.add_argument('-s', '--supply-chain', action='store_true', help='Enable supply-chain mode. Look for hf-mf-XXXXXXXX-default_nonces.json')
|
|
||||||
# Such json can be produced from the json saved by
|
|
||||||
# "hf mf isen --collect_fm11rf08s --key A396EFA4E24F" on a wiped card, then processed with
|
|
||||||
# jq '{Created: .Created, FileType: "fm11rf08s_default_nonces", nt: .nt | del(.["32"]) | map_values(.a)}'
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
start_time = time.time()
|
def recovery(init_check=False, final_check=False, keep=False, debug=False, supply_chain=False, quiet=True):
|
||||||
p = pm3.pm3()
|
def show(*args, **kwargs):
|
||||||
|
if not quiet:
|
||||||
|
print(*args, **kwargs)
|
||||||
|
|
||||||
p.console("hf 14a read")
|
start_time = time.time()
|
||||||
uid = None
|
p = pm3.pm3()
|
||||||
|
|
||||||
for line in p.grabbed_output.split('\n'):
|
p.console("hf 14a read")
|
||||||
|
uid = None
|
||||||
|
|
||||||
|
for line in p.grabbed_output.split('\n'):
|
||||||
if "UID:" in line:
|
if "UID:" in line:
|
||||||
uid = int(line[10:].replace(' ', '')[-8:], 16)
|
uid = int(line[10:].replace(' ', '')[-8:], 16)
|
||||||
|
|
||||||
if uid is None:
|
if uid is None:
|
||||||
print("Card not found")
|
show("Card not found")
|
||||||
exit()
|
return
|
||||||
print("UID: " + color(f"{uid:08X}", fg="green"))
|
show("UID: " + color(f"{uid:08X}", fg="green"))
|
||||||
|
|
||||||
|
def show_key(sec, key_type, key):
|
||||||
def print_key(sec, key_type, key):
|
|
||||||
kt = ['A', 'B'][key_type]
|
kt = ['A', 'B'][key_type]
|
||||||
print(f"Sector {sec:2} key{kt} = " + color(key, fg="green"))
|
show(f"Sector {sec:2} key{kt} = " + color(key, fg="green"))
|
||||||
|
|
||||||
p.console("prefs show --json")
|
p.console("prefs show --json")
|
||||||
prefs = json.loads(p.grabbed_output)
|
prefs = json.loads(p.grabbed_output)
|
||||||
save_path = prefs['file.default.dumppath'] + os.path.sep
|
save_path = prefs['file.default.dumppath'] + os.path.sep
|
||||||
|
|
||||||
found_keys = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
found_keys = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
if args.init_check:
|
if init_check:
|
||||||
print("Checking default keys...")
|
show("Checking default keys...")
|
||||||
p.console("hf mf fchk")
|
p.console("hf mf fchk")
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
if "[+] 0" in line:
|
if "[+] 0" in line:
|
||||||
|
@ -116,14 +114,14 @@ if args.init_check:
|
||||||
sec = int(res[0][4:])
|
sec = int(res[0][4:])
|
||||||
if res[3] == '1':
|
if res[3] == '1':
|
||||||
found_keys[sec][0] = res[2]
|
found_keys[sec][0] = res[2]
|
||||||
print_key(sec, 0, found_keys[sec][0])
|
show_key(sec, 0, found_keys[sec][0])
|
||||||
if res[5] == '1':
|
if res[5] == '1':
|
||||||
found_keys[sec][1] = res[4]
|
found_keys[sec][1] = res[4]
|
||||||
print_key(sec, 1, found_keys[sec][1])
|
show_key(sec, 1, found_keys[sec][1])
|
||||||
|
|
||||||
print("Getting nonces...")
|
show("Getting nonces...")
|
||||||
nonces_with_data = ""
|
nonces_with_data = ""
|
||||||
for key in BACKDOOR_KEYS:
|
for key in BACKDOOR_KEYS:
|
||||||
cmd = f"hf mf isen --collect_fm11rf08s_with_data --key {key}"
|
cmd = f"hf mf isen --collect_fm11rf08s_with_data --key {key}"
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
|
@ -134,23 +132,23 @@ for key in BACKDOOR_KEYS:
|
||||||
if nonces_with_data != "":
|
if nonces_with_data != "":
|
||||||
break
|
break
|
||||||
|
|
||||||
if (nonces_with_data == ""):
|
if (nonces_with_data == ""):
|
||||||
print("Error getting nonces, abort.")
|
show("Error getting nonces, abort.")
|
||||||
exit()
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(nonces_with_data, 'r') as file:
|
with open(nonces_with_data, 'r') as file:
|
||||||
# Load and parse the JSON data
|
# Load and parse the JSON data
|
||||||
dict_nwd = json.load(file)
|
dict_nwd = json.load(file)
|
||||||
except json.decoder.JSONDecodeError:
|
except json.decoder.JSONDecodeError:
|
||||||
print(f"Error parsing {nonces_with_data}, abort.")
|
show(f"Error parsing {nonces_with_data}, abort.")
|
||||||
exit()
|
return
|
||||||
|
|
||||||
nt = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
nt = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
nt_enc = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
nt_enc = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
par_err = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
par_err = [["", ""] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
data = ["" for _ in range(NUM_SECTORS * 4)]
|
data = ["" for _ in range(NUM_SECTORS * 4)]
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
real_sec = sec
|
real_sec = sec
|
||||||
if sec >= NUM_SECTORS:
|
if sec >= NUM_SECTORS:
|
||||||
real_sec += 16
|
real_sec += 16
|
||||||
|
@ -160,12 +158,12 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
nt_enc[sec][1] = dict_nwd["nt_enc"][f"{real_sec}"]["b"].lower()
|
nt_enc[sec][1] = dict_nwd["nt_enc"][f"{real_sec}"]["b"].lower()
|
||||||
par_err[sec][0] = dict_nwd["par_err"][f"{real_sec}"]["a"]
|
par_err[sec][0] = dict_nwd["par_err"][f"{real_sec}"]["a"]
|
||||||
par_err[sec][1] = dict_nwd["par_err"][f"{real_sec}"]["b"]
|
par_err[sec][1] = dict_nwd["par_err"][f"{real_sec}"]["b"]
|
||||||
for blk in range(NUM_SECTORS * 4):
|
for blk in range(NUM_SECTORS * 4):
|
||||||
data[blk] = dict_nwd["blocks"][f"{blk}"]
|
data[blk] = dict_nwd["blocks"][f"{blk}"]
|
||||||
|
|
||||||
print("Generating first dump file")
|
show("Generating first dump file")
|
||||||
dumpfile = f"{save_path}hf-mf-{uid:08X}-dump.bin"
|
dumpfile = f"{save_path}hf-mf-{uid:08X}-dump.bin"
|
||||||
with (open(dumpfile, "wb")) as f:
|
with (open(dumpfile, "wb")) as f:
|
||||||
for sec in range(NUM_SECTORS):
|
for sec in range(NUM_SECTORS):
|
||||||
for b in range(4):
|
for b in range(4):
|
||||||
d = data[(sec * 4) + b]
|
d = data[(sec * 4) + b]
|
||||||
|
@ -178,26 +176,26 @@ with (open(dumpfile, "wb")) as f:
|
||||||
kb = "FFFFFFFFFFFF"
|
kb = "FFFFFFFFFFFF"
|
||||||
d = ka + d[12:20] + kb
|
d = ka + d[12:20] + kb
|
||||||
f.write(bytes.fromhex(d))
|
f.write(bytes.fromhex(d))
|
||||||
print(f"Data has been dumped to `{dumpfile}`")
|
show(f"Data has been dumped to `{dumpfile}`")
|
||||||
|
|
||||||
elapsed_time1 = time.time() - start_time
|
elapsed_time1 = time.time() - start_time
|
||||||
minutes = int(elapsed_time1 // 60)
|
minutes = int(elapsed_time1 // 60)
|
||||||
seconds = int(elapsed_time1 % 60)
|
seconds = int(elapsed_time1 % 60)
|
||||||
print("----Step 1: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
show("----Step 1: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
||||||
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
||||||
|
|
||||||
if os.path.isfile(DICT_DEF_PATH):
|
if os.path.isfile(DICT_DEF_PATH):
|
||||||
print(f"Loading {DICT_DEF}")
|
show(f"Loading {DICT_DEF}")
|
||||||
with open(DICT_DEF_PATH, 'r', encoding='utf-8') as file:
|
with open(DICT_DEF_PATH, 'r', encoding='utf-8') as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
if line[0] != '#' and len(line) >= 12:
|
if line[0] != '#' and len(line) >= 12:
|
||||||
DEFAULT_KEYS.add(line[:12])
|
DEFAULT_KEYS.add(line[:12])
|
||||||
else:
|
else:
|
||||||
print(f"Warning, {DICT_DEF} not found.")
|
show(f"Warning, {DICT_DEF} not found.")
|
||||||
|
|
||||||
dict_dnwd = None
|
dict_dnwd = None
|
||||||
def_nt = ["" for _ in range(NUM_SECTORS)]
|
def_nt = ["" for _ in range(NUM_SECTORS)]
|
||||||
if args.supply_chain:
|
if supply_chain:
|
||||||
try:
|
try:
|
||||||
default_nonces = f'{save_path}hf-mf-{uid:04X}-default_nonces.json'
|
default_nonces = f'{save_path}hf-mf-{uid:04X}-default_nonces.json'
|
||||||
with open(default_nonces, 'r') as file:
|
with open(default_nonces, 'r') as file:
|
||||||
|
@ -205,20 +203,20 @@ if args.supply_chain:
|
||||||
dict_dnwd = json.load(file)
|
dict_dnwd = json.load(file)
|
||||||
for sec in range(NUM_SECTORS):
|
for sec in range(NUM_SECTORS):
|
||||||
def_nt[sec] = dict_dnwd["nt"][f"{sec}"].lower()
|
def_nt[sec] = dict_dnwd["nt"][f"{sec}"].lower()
|
||||||
print(f"Loaded default nonces from {default_nonces}.")
|
show(f"Loaded default nonces from {default_nonces}.")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
except json.decoder.JSONDecodeError:
|
except json.decoder.JSONDecodeError:
|
||||||
print(f"Error parsing {default_nonces}, skipping.")
|
show(f"Error parsing {default_nonces}, skipping.")
|
||||||
|
|
||||||
print("Running staticnested_1nt & 2x1nt when doable...")
|
show("Running staticnested_1nt & 2x1nt when doable...")
|
||||||
keys = [[set(), set()] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
keys = [[set(), set()] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
all_keys = set()
|
all_keys = set()
|
||||||
duplicates = set()
|
duplicates = set()
|
||||||
# Availability of filtered dicts
|
# Availability of filtered dicts
|
||||||
filtered_dicts = [[False, False] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
filtered_dicts = [[False, False] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
found_default = [[False, False] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
found_default = [[False, False] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
real_sec = sec
|
real_sec = sec
|
||||||
if sec >= NUM_SECTORS:
|
if sec >= NUM_SECTORS:
|
||||||
real_sec += 16
|
real_sec += 16
|
||||||
|
@ -228,12 +226,12 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
for key_type in [0, 1]:
|
for key_type in [0, 1]:
|
||||||
cmd = [tools["staticnested_1nt"], f"{uid:08X}", f"{real_sec}",
|
cmd = [tools["staticnested_1nt"], f"{uid:08X}", f"{real_sec}",
|
||||||
nt[sec][key_type], nt_enc[sec][key_type], par_err[sec][key_type]]
|
nt[sec][key_type], nt_enc[sec][key_type], par_err[sec][key_type]]
|
||||||
if args.debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
subprocess.run(cmd, capture_output=True)
|
subprocess.run(cmd, capture_output=True)
|
||||||
cmd = [tools["staticnested_2x1nt"],
|
cmd = [tools["staticnested_2x1nt"],
|
||||||
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][0]}.dic", f"keys_{uid:08x}_{real_sec:02}_{nt[sec][1]}.dic"]
|
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][0]}.dic", f"keys_{uid:08x}_{real_sec:02}_{nt[sec][1]}.dic"]
|
||||||
if args.debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
subprocess.run(cmd, capture_output=True)
|
subprocess.run(cmd, capture_output=True)
|
||||||
filtered_dicts[sec][key_type] = True
|
filtered_dicts[sec][key_type] = True
|
||||||
|
@ -247,8 +245,9 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
all_keys.update(keys_set)
|
all_keys.update(keys_set)
|
||||||
if dict_dnwd is not None and sec < NUM_SECTORS:
|
if dict_dnwd is not None and sec < NUM_SECTORS:
|
||||||
# Prioritize keys from supply-chain attack
|
# Prioritize keys from supply-chain attack
|
||||||
cmd = [tools["staticnested_2x1nt1key"], def_nt[sec], "FFFFFFFFFFFF", f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"]
|
cmd = [tools["staticnested_2x1nt1key"], def_nt[sec], "FFFFFFFFFFFF",
|
||||||
if args.debug:
|
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"]
|
||||||
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
||||||
keys_def_set = set()
|
keys_def_set = set()
|
||||||
|
@ -279,7 +278,7 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
key_type = 1
|
key_type = 1
|
||||||
cmd = [tools["staticnested_1nt"], f"{uid:08X}", f"{real_sec}",
|
cmd = [tools["staticnested_1nt"], f"{uid:08X}", f"{real_sec}",
|
||||||
nt[sec][key_type], nt_enc[sec][key_type], par_err[sec][key_type]]
|
nt[sec][key_type], nt_enc[sec][key_type], par_err[sec][key_type]]
|
||||||
if args.debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
subprocess.run(cmd, capture_output=True)
|
subprocess.run(cmd, capture_output=True)
|
||||||
keys_set = set()
|
keys_set = set()
|
||||||
|
@ -291,8 +290,9 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
all_keys.update(keys_set)
|
all_keys.update(keys_set)
|
||||||
if dict_dnwd is not None and sec < NUM_SECTORS:
|
if dict_dnwd is not None and sec < NUM_SECTORS:
|
||||||
# Prioritize keys from supply-chain attack
|
# Prioritize keys from supply-chain attack
|
||||||
cmd = [tools["staticnested_2x1nt1key"], def_nt[sec], "FFFFFFFFFFFF", f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"]
|
cmd = [tools["staticnested_2x1nt1key"], def_nt[sec], "FFFFFFFFFFFF",
|
||||||
if args.debug:
|
f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"]
|
||||||
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
||||||
keys_def_set = set()
|
keys_def_set = set()
|
||||||
|
@ -312,25 +312,25 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
for k in keys_set:
|
for k in keys_set:
|
||||||
f.write(f"{k}\n")
|
f.write(f"{k}\n")
|
||||||
|
|
||||||
print("Looking for common keys across sectors...")
|
show("Looking for common keys across sectors...")
|
||||||
keys_filtered = [[set(), set()] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
keys_filtered = [[set(), set()] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
for dup in duplicates:
|
for dup in duplicates:
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
for key_type in [0, 1]:
|
for key_type in [0, 1]:
|
||||||
if dup in keys[sec][key_type]:
|
if dup in keys[sec][key_type]:
|
||||||
keys_filtered[sec][key_type].add(dup)
|
keys_filtered[sec][key_type].add(dup)
|
||||||
|
|
||||||
# Availability of duplicates dicts
|
# Availability of duplicates dicts
|
||||||
duplicates_dicts = [[False, False] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
duplicates_dicts = [[False, False] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
first = True
|
first = True
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
real_sec = sec
|
real_sec = sec
|
||||||
if sec >= NUM_SECTORS:
|
if sec >= NUM_SECTORS:
|
||||||
real_sec += 16
|
real_sec += 16
|
||||||
for key_type in [0, 1]:
|
for key_type in [0, 1]:
|
||||||
if len(keys_filtered[sec][key_type]) > 0:
|
if len(keys_filtered[sec][key_type]) > 0:
|
||||||
if first:
|
if first:
|
||||||
print("Saving duplicates dicts...")
|
show("Saving duplicates dicts...")
|
||||||
first = False
|
first = False
|
||||||
with (open(f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_duplicates.dic", "w")) as f:
|
with (open(f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_duplicates.dic", "w")) as f:
|
||||||
keys_set = keys_filtered[sec][key_type].copy()
|
keys_set = keys_filtered[sec][key_type].copy()
|
||||||
|
@ -342,9 +342,9 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
f.write(f"{k}\n")
|
f.write(f"{k}\n")
|
||||||
duplicates_dicts[sec][key_type] = True
|
duplicates_dicts[sec][key_type] = True
|
||||||
|
|
||||||
print("Computing needed time for attack...")
|
show("Computing needed time for attack...")
|
||||||
candidates = [[0, 0] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
candidates = [[0, 0] for _ in range(NUM_SECTORS + NUM_EXTRA_SECTORS)]
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
real_sec = sec
|
real_sec = sec
|
||||||
if sec >= NUM_SECTORS:
|
if sec >= NUM_SECTORS:
|
||||||
real_sec += 16
|
real_sec += 16
|
||||||
|
@ -354,12 +354,14 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_duplicates.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_duplicates.dic"
|
||||||
with open(dic, 'r') as file:
|
with open(dic, 'r') as file:
|
||||||
count = sum(1 for _ in file)
|
count = sum(1 for _ in file)
|
||||||
# print(f"dic {dic} size {count}")
|
# print(f"dic {dic} size {count}")
|
||||||
candidates[sec][key_type] = count
|
candidates[sec][key_type] = count
|
||||||
if nt[sec][0] == nt[sec][1]:
|
if nt[sec][0] == nt[sec][1]:
|
||||||
candidates[sec][key_type ^ 1] = 1
|
candidates[sec][key_type ^ 1] = 1
|
||||||
for key_type in [0, 1]:
|
for key_type in [0, 1]:
|
||||||
if found_keys[sec][0] == "" and found_keys[sec][1] == "" and filtered_dicts[sec][key_type] and candidates[sec][0] == 0 and candidates[sec][1] == 0:
|
if ((found_keys[sec][0] == "" and found_keys[sec][1] == "" and
|
||||||
|
filtered_dicts[sec][key_type] and candidates[sec][0] == 0 and
|
||||||
|
candidates[sec][1] == 0)):
|
||||||
if found_default[sec][key_type]:
|
if found_default[sec][key_type]:
|
||||||
# We assume the default key is correct
|
# We assume the default key is correct
|
||||||
candidates[sec][key_type] = 1
|
candidates[sec][key_type] = 1
|
||||||
|
@ -368,9 +370,11 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"
|
||||||
with open(dic, 'r') as file:
|
with open(dic, 'r') as file:
|
||||||
count = sum(1 for _ in file)
|
count = sum(1 for _ in file)
|
||||||
# print(f"dic {dic} size {count}")
|
# print(f"dic {dic} size {count}")
|
||||||
candidates[sec][key_type] = count
|
candidates[sec][key_type] = count
|
||||||
if found_keys[sec][0] == "" and found_keys[sec][1] == "" and nt[sec][0] == nt[sec][1] and candidates[sec][0] == 0 and candidates[sec][1] == 0:
|
if ((found_keys[sec][0] == "" and found_keys[sec][1] == "" and
|
||||||
|
nt[sec][0] == nt[sec][1] and candidates[sec][0] == 0 and
|
||||||
|
candidates[sec][1] == 0)):
|
||||||
if found_default[sec][0]:
|
if found_default[sec][0]:
|
||||||
# We assume the default key is correct
|
# We assume the default key is correct
|
||||||
candidates[sec][0] = 1
|
candidates[sec][0] = 1
|
||||||
|
@ -381,35 +385,35 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"
|
||||||
with open(dic, 'r') as file:
|
with open(dic, 'r') as file:
|
||||||
count = sum(1 for _ in file)
|
count = sum(1 for _ in file)
|
||||||
# print(f"dic {dic} size {count}")
|
# print(f"dic {dic} size {count}")
|
||||||
candidates[sec][0] = count
|
candidates[sec][0] = count
|
||||||
candidates[sec][1] = 1
|
candidates[sec][1] = 1
|
||||||
|
|
||||||
if args.debug:
|
if debug:
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
real_sec = sec
|
real_sec = sec
|
||||||
if sec >= NUM_SECTORS:
|
if sec >= NUM_SECTORS:
|
||||||
real_sec += 16
|
real_sec += 16
|
||||||
print(f" {real_sec:03} | {real_sec*4+3:03} | {candidates[sec][0]:6} | {candidates[sec][1]:6} ")
|
show(f" {real_sec:03} | {real_sec*4+3:03} | {candidates[sec][0]:6} | {candidates[sec][1]:6} ")
|
||||||
total_candidates = sum(candidates[sec][0] + candidates[sec][1] for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS))
|
total_candidates = sum(candidates[sec][0] + candidates[sec][1] for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS))
|
||||||
|
|
||||||
elapsed_time2 = time.time() - start_time - elapsed_time1
|
elapsed_time2 = time.time() - start_time - elapsed_time1
|
||||||
minutes = int(elapsed_time2 // 60)
|
minutes = int(elapsed_time2 // 60)
|
||||||
seconds = int(elapsed_time2 % 60)
|
seconds = int(elapsed_time2 % 60)
|
||||||
print("----Step 2: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
show("----Step 2: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
||||||
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
||||||
|
|
||||||
# fchk: 147 keys/s. Correct key found after 50% of candidates on average
|
# fchk: 147 keys/s. Correct key found after 50% of candidates on average
|
||||||
FCHK_KEYS_S = 147
|
FCHK_KEYS_S = 147
|
||||||
foreseen_time = (total_candidates / 2 / FCHK_KEYS_S) + 5
|
foreseen_time = (total_candidates / 2 / FCHK_KEYS_S) + 5
|
||||||
minutes = int(foreseen_time // 60)
|
minutes = int(foreseen_time // 60)
|
||||||
seconds = int(foreseen_time % 60)
|
seconds = int(foreseen_time % 60)
|
||||||
print("Still about " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
show("Still about " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
||||||
color(f"{seconds:2}", fg="yellow") + " seconds to run...")
|
color(f"{seconds:2}", fg="yellow") + " seconds to run...")
|
||||||
|
|
||||||
abort = False
|
abort = False
|
||||||
print("Brute-forcing keys... Press any key to interrupt")
|
show("Brute-forcing keys... Press any key to interrupt")
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
real_sec = sec
|
real_sec = sec
|
||||||
if sec >= NUM_SECTORS:
|
if sec >= NUM_SECTORS:
|
||||||
real_sec += 16
|
real_sec += 16
|
||||||
|
@ -421,7 +425,7 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
kt = ['a', 'b'][key_type]
|
kt = ['a', 'b'][key_type]
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_duplicates.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_duplicates.dic"
|
||||||
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} -f {dic} --no-default"
|
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} -f {dic} --no-default"
|
||||||
if args.debug:
|
if debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
|
@ -429,10 +433,10 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
abort = True
|
abort = True
|
||||||
if "found:" in line:
|
if "found:" in line:
|
||||||
found_keys[sec][key_type] = line[30:].strip()
|
found_keys[sec][key_type] = line[30:].strip()
|
||||||
print_key(real_sec, key_type, found_keys[sec][key_type])
|
show_key(real_sec, key_type, found_keys[sec][key_type])
|
||||||
if nt[sec][0] == nt[sec][1] and found_keys[sec][key_type ^ 1] == "":
|
if nt[sec][0] == nt[sec][1] and found_keys[sec][key_type ^ 1] == "":
|
||||||
found_keys[sec][key_type ^ 1] = found_keys[sec][key_type]
|
found_keys[sec][key_type ^ 1] = found_keys[sec][key_type]
|
||||||
print_key(real_sec, key_type ^ 1, found_keys[sec][key_type ^ 1])
|
show_key(real_sec, key_type ^ 1, found_keys[sec][key_type ^ 1])
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
if abort:
|
if abort:
|
||||||
|
@ -447,7 +451,7 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
kt = ['a', 'b'][key_type]
|
kt = ['a', 'b'][key_type]
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}_filtered.dic"
|
||||||
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} -f {dic} --no-default"
|
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} -f {dic} --no-default"
|
||||||
if args.debug:
|
if debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
|
@ -455,7 +459,7 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
abort = True
|
abort = True
|
||||||
if "found:" in line:
|
if "found:" in line:
|
||||||
found_keys[sec][key_type] = line[30:].strip()
|
found_keys[sec][key_type] = line[30:].strip()
|
||||||
print_key(real_sec, key_type, found_keys[sec][key_type])
|
show_key(real_sec, key_type, found_keys[sec][key_type])
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
if abort:
|
if abort:
|
||||||
|
@ -468,7 +472,7 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
kt = ['a', 'b'][key_type]
|
kt = ['a', 'b'][key_type]
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type]}.dic"
|
||||||
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} -f {dic} --no-default"
|
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} -f {dic} --no-default"
|
||||||
if args.debug:
|
if debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
|
@ -477,8 +481,8 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
if "found:" in line:
|
if "found:" in line:
|
||||||
found_keys[sec][0] = line[30:].strip()
|
found_keys[sec][0] = line[30:].strip()
|
||||||
found_keys[sec][1] = line[30:].strip()
|
found_keys[sec][1] = line[30:].strip()
|
||||||
print_key(real_sec, 0, found_keys[sec][key_type])
|
show_key(real_sec, 0, found_keys[sec][key_type])
|
||||||
print_key(real_sec, 1, found_keys[sec][key_type])
|
show_key(real_sec, 1, found_keys[sec][key_type])
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -497,7 +501,7 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
else:
|
else:
|
||||||
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type_target]}.dic"
|
dic = f"keys_{uid:08x}_{real_sec:02}_{nt[sec][key_type_target]}.dic"
|
||||||
cmd = [tools["staticnested_2x1nt1key"], nt[sec][key_type_source], found_keys[sec][key_type_source], dic]
|
cmd = [tools["staticnested_2x1nt1key"], nt[sec][key_type_source], found_keys[sec][key_type_source], dic]
|
||||||
if args.debug:
|
if debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
result = subprocess.run(cmd, capture_output=True, text=True).stdout
|
||||||
keys = set()
|
keys = set()
|
||||||
|
@ -509,7 +513,7 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} --no-default"
|
cmd = f"hf mf fchk --blk {real_sec * 4} -{kt} --no-default"
|
||||||
for k in keys:
|
for k in keys:
|
||||||
cmd += f" -k {k}"
|
cmd += f" -k {k}"
|
||||||
if args.debug:
|
if debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
|
@ -520,32 +524,32 @@ for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
elif len(keys) == 1:
|
elif len(keys) == 1:
|
||||||
found_keys[sec][key_type_target] = keys.pop()
|
found_keys[sec][key_type_target] = keys.pop()
|
||||||
if found_keys[sec][key_type_target] != "":
|
if found_keys[sec][key_type_target] != "":
|
||||||
print_key(real_sec, key_type_target, found_keys[sec][key_type_target])
|
show_key(real_sec, key_type_target, found_keys[sec][key_type_target])
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
|
|
||||||
if abort:
|
if abort:
|
||||||
print("Brute-forcing phase aborted via keyboard!")
|
show("Brute-forcing phase aborted via keyboard!")
|
||||||
args.final_check = False
|
final_check = False
|
||||||
|
|
||||||
plus = "[" + color("+", fg="green") + "] "
|
plus = "[" + color("+", fg="green") + "] "
|
||||||
if args.final_check:
|
if final_check:
|
||||||
print("Letting fchk do a final dump, just for confirmation and display...")
|
show("Letting fchk do a final dump, just for confirmation and display...")
|
||||||
keys_set = set([i for sl in found_keys for i in sl if i != ""])
|
keys_set = set([i for sl in found_keys for i in sl if i != ""])
|
||||||
with (open(f"keys_{uid:08x}.dic", "w")) as f:
|
with (open(f"keys_{uid:08x}.dic", "w")) as f:
|
||||||
for k in keys_set:
|
for k in keys_set:
|
||||||
f.write(f"{k}\n")
|
f.write(f"{k}\n")
|
||||||
cmd = f"hf mf fchk -f keys_{uid:08x}.dic --no-default --dump"
|
cmd = f"hf mf fchk -f keys_{uid:08x}.dic --no-default --dump"
|
||||||
if args.debug:
|
if debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
p.console(cmd, capture=False, quiet=False)
|
p.console(cmd, capture=False, quiet=False)
|
||||||
else:
|
else:
|
||||||
print()
|
show()
|
||||||
print(plus + color("found keys:", fg="green"))
|
show(plus + color("found keys:", fg="green"))
|
||||||
print()
|
show()
|
||||||
print(plus + "-----+-----+--------------+---+--------------+----")
|
show(plus + "-----+-----+--------------+---+--------------+----")
|
||||||
print(plus + " Sec | Blk | key A |res| key B |res")
|
show(plus + " Sec | Blk | key A |res| key B |res")
|
||||||
print(plus + "-----+-----+--------------+---+--------------+----")
|
show(plus + "-----+-----+--------------+---+--------------+----")
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
real_sec = sec
|
real_sec = sec
|
||||||
if sec >= NUM_SECTORS:
|
if sec >= NUM_SECTORS:
|
||||||
|
@ -556,12 +560,13 @@ else:
|
||||||
keys[key_type] = [color("------------", fg="red"), color("0", fg="red")]
|
keys[key_type] = [color("------------", fg="red"), color("0", fg="red")]
|
||||||
else:
|
else:
|
||||||
keys[key_type] = [color(found_keys[sec][key_type], fg="green"), color("1", fg="green")]
|
keys[key_type] = [color(found_keys[sec][key_type], fg="green"), color("1", fg="green")]
|
||||||
print(plus + f" {real_sec:03} | {real_sec*4+3:03} | {keys[0][0]} | {keys[0][1]} | {keys[1][0]} | {keys[1][1]} ")
|
show(plus + f" {real_sec:03} | {real_sec*4+3:03} | " +
|
||||||
print(plus + "-----+-----+--------------+---+--------------+----")
|
f"{keys[0][0]} | {keys[0][1]} | {keys[1][0]} | {keys[1][1]} ")
|
||||||
print(plus + "( " + color("0", fg="red") + ":Failed / " +
|
show(plus + "-----+-----+--------------+---+--------------+----")
|
||||||
|
show(plus + "( " + color("0", fg="red") + ":Failed / " +
|
||||||
color("1", fg="green") + ":Success )")
|
color("1", fg="green") + ":Success )")
|
||||||
print()
|
show()
|
||||||
print(plus + "Generating binary key file")
|
show(plus + "Generating binary key file")
|
||||||
keyfile = f"{save_path}hf-mf-{uid:08X}-key.bin"
|
keyfile = f"{save_path}hf-mf-{uid:08X}-key.bin"
|
||||||
unknown = False
|
unknown = False
|
||||||
with (open(keyfile, "wb")) as f:
|
with (open(keyfile, "wb")) as f:
|
||||||
|
@ -572,11 +577,11 @@ else:
|
||||||
k = "FFFFFFFFFFFF"
|
k = "FFFFFFFFFFFF"
|
||||||
unknown = True
|
unknown = True
|
||||||
f.write(bytes.fromhex(k))
|
f.write(bytes.fromhex(k))
|
||||||
print(plus + "Found keys have been dumped to `" + color(keyfile, fg="yellow")+"`")
|
show(plus + "Found keys have been dumped to `" + color(keyfile, fg="yellow")+"`")
|
||||||
if unknown:
|
if unknown:
|
||||||
print("[" + color("=", fg="yellow") + "] --[ " + color("FFFFFFFFFFFF", fg="yellow") +
|
show("[" + color("=", fg="yellow") + "] --[ " + color("FFFFFFFFFFFF", fg="yellow") +
|
||||||
" ]-- has been inserted for unknown keys")
|
" ]-- has been inserted for unknown keys")
|
||||||
print(plus + "Generating final dump file")
|
show(plus + "Generating final dump file")
|
||||||
dumpfile = f"{save_path}hf-mf-{uid:08X}-dump.bin"
|
dumpfile = f"{save_path}hf-mf-{uid:08X}-dump.bin"
|
||||||
with (open(dumpfile, "wb")) as f:
|
with (open(dumpfile, "wb")) as f:
|
||||||
for sec in range(NUM_SECTORS):
|
for sec in range(NUM_SECTORS):
|
||||||
|
@ -591,11 +596,11 @@ else:
|
||||||
kb = "FFFFFFFFFFFF"
|
kb = "FFFFFFFFFFFF"
|
||||||
d = ka + d[12:20] + kb
|
d = ka + d[12:20] + kb
|
||||||
f.write(bytes.fromhex(d))
|
f.write(bytes.fromhex(d))
|
||||||
print(plus + "Data has been dumped to `" + color(dumpfile, fg="yellow")+"`")
|
show(plus + "Data has been dumped to `" + color(dumpfile, fg="yellow")+"`")
|
||||||
|
|
||||||
# Remove generated dictionaries after processing
|
# Remove generated dictionaries after processing
|
||||||
if not args.keep:
|
if not keep:
|
||||||
print(plus + "Removing generated dictionaries...")
|
show(plus + "Removing generated dictionaries...")
|
||||||
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
for sec in range(NUM_SECTORS + NUM_EXTRA_SECTORS):
|
||||||
real_sec = sec
|
real_sec = sec
|
||||||
if sec >= NUM_SECTORS:
|
if sec >= NUM_SECTORS:
|
||||||
|
@ -606,14 +611,44 @@ if not args.keep:
|
||||||
if os.path.isfile(file_name):
|
if os.path.isfile(file_name):
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
|
|
||||||
elapsed_time3 = time.time() - start_time - elapsed_time1 - elapsed_time2
|
elapsed_time3 = time.time() - start_time - elapsed_time1 - elapsed_time2
|
||||||
minutes = int(elapsed_time3 // 60)
|
minutes = int(elapsed_time3 // 60)
|
||||||
seconds = int(elapsed_time3 % 60)
|
seconds = int(elapsed_time3 % 60)
|
||||||
print("----Step 3: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
show("----Step 3: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
||||||
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
||||||
|
|
||||||
elapsed_time = time.time() - start_time
|
elapsed_time = time.time() - start_time
|
||||||
minutes = int(elapsed_time // 60)
|
minutes = int(elapsed_time // 60)
|
||||||
seconds = int(elapsed_time % 60)
|
seconds = int(elapsed_time % 60)
|
||||||
print("---- TOTAL: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
show("---- TOTAL: " + color(f"{minutes:2}", fg="yellow") + " minutes " +
|
||||||
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
color(f"{seconds:2}", fg="yellow") + " seconds -----------")
|
||||||
|
|
||||||
|
return (found_keys, data)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='A script combining staticnested* tools '
|
||||||
|
'to recover all keys from a FM11RF08S card.')
|
||||||
|
parser.add_argument('-x', '--init-check', action='store_true', help='Run an initial fchk for default keys')
|
||||||
|
parser.add_argument('-y', '--final-check', action='store_true', help='Run a final fchk with the found keys')
|
||||||
|
parser.add_argument('-k', '--keep', action='store_true', help='Keep generated dictionaries after processing')
|
||||||
|
parser.add_argument('-d', '--debug', action='store_true', help='Enable debug mode')
|
||||||
|
parser.add_argument('-s', '--supply-chain', action='store_true', help='Enable supply-chain mode. '
|
||||||
|
'Look for hf-mf-XXXXXXXX-default_nonces.json')
|
||||||
|
# Such json can be produced from the json saved by
|
||||||
|
# "hf mf isen --collect_fm11rf08s --key A396EFA4E24F" on a wiped card, then processed with
|
||||||
|
# jq '{Created: .Created, FileType: "fm11rf08s_default_nonces", nt: .nt | del(.["32"]) | map_values(.a)}'
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
recovery(
|
||||||
|
init_check=args.init_check,
|
||||||
|
final_check=args.final_check,
|
||||||
|
keep=args.keep,
|
||||||
|
debug=args.debug,
|
||||||
|
supply_chain=args.supply_chain,
|
||||||
|
quiet=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue