mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
fm11rf08s_recovery: now with help, args & colors
This commit is contained in:
parent
fe3901b69b
commit
494a201e9d
1 changed files with 76 additions and 48 deletions
|
@ -15,22 +15,25 @@
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import argparse
|
||||||
|
# pip install ansicolors
|
||||||
|
from colors import color
|
||||||
import pm3
|
import pm3
|
||||||
from output_grabber import OutputGrabber
|
from output_grabber import OutputGrabber
|
||||||
|
|
||||||
BACKDOOR_RF08S = "A396EFA4E24F"
|
BACKDOOR_RF08S = "A396EFA4E24F"
|
||||||
NUM_SECTORS = 16
|
NUM_SECTORS = 16
|
||||||
# Run an initial check with the default keys
|
|
||||||
INITIAL_CHECK = True
|
|
||||||
# Run a final check with the found keys, mostly for validation
|
|
||||||
FINAL_CHECK = True
|
|
||||||
|
|
||||||
TOOLS_PATH = "tools/mfc/card_only"
|
TOOLS_PATH = "tools/mfc/card_only"
|
||||||
STATICNESTED_1NT = f"{TOOLS_PATH}/staticnested_1nt"
|
STATICNESTED_1NT = f"{TOOLS_PATH}/staticnested_1nt"
|
||||||
STATICNESTED_2X1NT = f"{TOOLS_PATH}/staticnested_2x1nt_rf08s"
|
STATICNESTED_2X1NT = f"{TOOLS_PATH}/staticnested_2x1nt_rf08s"
|
||||||
STATICNESTED_2X1NT1KEY = f"{TOOLS_PATH}/staticnested_2x1nt_rf08s_1key"
|
STATICNESTED_2X1NT1KEY = f"{TOOLS_PATH}/staticnested_2x1nt_rf08s_1key"
|
||||||
DEBUG = False
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='A script combining staticnested* tools '
|
||||||
|
'to recover all keys from a FM11RF08S card.')
|
||||||
|
parser.add_argument('-x', '--no-init-check', action='store_true', help='Do not run an initial fchk for default keys')
|
||||||
|
parser.add_argument('-y', '--no-final-check', action='store_true', help='Do not run a final fchk with the found keys')
|
||||||
|
parser.add_argument('-d', '--debug', action='store_true', help='Enable debug mode')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
out = OutputGrabber()
|
out = OutputGrabber()
|
||||||
|
@ -55,10 +58,16 @@ if uid is None:
|
||||||
with out:
|
with out:
|
||||||
p.console("prefs set color --ansi")
|
p.console("prefs set color --ansi")
|
||||||
exit()
|
exit()
|
||||||
print(f"UID: {uid:08X}")
|
print("UID: " + color(f"{uid:08X}", fg="green"))
|
||||||
|
|
||||||
|
|
||||||
|
def print_key(sec, key_type, key):
|
||||||
|
kt = ['A', 'B'][key_type]
|
||||||
|
print(f"Sector {sec:2} key{kt} = " + color(key, fg="green"))
|
||||||
|
|
||||||
|
|
||||||
found_keys = [["", ""] for _ in range(NUM_SECTORS)]
|
found_keys = [["", ""] for _ in range(NUM_SECTORS)]
|
||||||
if INITIAL_CHECK:
|
if not args.no_init_check:
|
||||||
print("Checking default keys...")
|
print("Checking default keys...")
|
||||||
with out:
|
with out:
|
||||||
p.console("hf mf fchk")
|
p.console("hf mf fchk")
|
||||||
|
@ -68,10 +77,10 @@ if INITIAL_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(f"Sector {sec:2} keyA = {found_keys[sec][0]}")
|
print_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(f"Sector {sec:2} keyB = {found_keys[sec][1]}")
|
print_key(sec, 1, found_keys[sec][1])
|
||||||
|
|
||||||
nt = [["", ""] for _ in range(NUM_SECTORS)]
|
nt = [["", ""] for _ in range(NUM_SECTORS)]
|
||||||
nt_enc = [["", ""] for _ in range(NUM_SECTORS)]
|
nt_enc = [["", ""] for _ in range(NUM_SECTORS)]
|
||||||
|
@ -115,12 +124,12 @@ for sec in range(NUM_SECTORS):
|
||||||
for key_type in [0, 1]:
|
for key_type in [0, 1]:
|
||||||
cmd = [STATICNESTED_1NT, f"{uid:08X}", f"{sec}",
|
cmd = [STATICNESTED_1NT, f"{uid:08X}", f"{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 DEBUG:
|
if args.debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
subprocess.run(cmd, capture_output=True)
|
subprocess.run(cmd, capture_output=True)
|
||||||
cmd = [STATICNESTED_2X1NT,
|
cmd = [STATICNESTED_2X1NT,
|
||||||
f"keys_{uid:08x}_{sec:02}_{nt[sec][0]}.dic", f"keys_{uid:08x}_{sec:02}_{nt[sec][1]}.dic"]
|
f"keys_{uid:08x}_{sec:02}_{nt[sec][0]}.dic", f"keys_{uid:08x}_{sec:02}_{nt[sec][1]}.dic"]
|
||||||
if DEBUG:
|
if args.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
|
||||||
|
@ -140,7 +149,7 @@ for sec in range(NUM_SECTORS):
|
||||||
key_type = 1
|
key_type = 1
|
||||||
cmd = [STATICNESTED_1NT, f"{uid:08X}", f"{sec}",
|
cmd = [STATICNESTED_1NT, f"{uid:08X}", f"{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 DEBUG:
|
if args.debug:
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
subprocess.run(cmd, capture_output=True)
|
subprocess.run(cmd, capture_output=True)
|
||||||
with (open(f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type]}.dic")) as f:
|
with (open(f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type]}.dic")) as f:
|
||||||
|
@ -188,7 +197,7 @@ for sec in range(NUM_SECTORS):
|
||||||
kt = ['a', 'b'][key_type]
|
kt = ['a', 'b'][key_type]
|
||||||
dic = f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type]}_duplicates.dic"
|
dic = f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type]}_duplicates.dic"
|
||||||
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
||||||
if DEBUG:
|
if args.debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
with out:
|
with out:
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
|
@ -197,12 +206,10 @@ for sec in range(NUM_SECTORS):
|
||||||
abort = True
|
abort = True
|
||||||
if "found:" in line:
|
if "found:" in line:
|
||||||
found_keys[sec][key_type] = line[30:]
|
found_keys[sec][key_type] = line[30:]
|
||||||
kt = ['A', 'B'][key_type]
|
print_key(sec, key_type, found_keys[sec][key_type])
|
||||||
print(f"Sector {sec:2} key{kt} = {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]
|
||||||
kt = ['A', 'B'][key_type ^ 1]
|
print_key(sec, key_type ^ 1, found_keys[sec][key_type ^ 1])
|
||||||
print(f"Sector {sec:2} key{kt} = {found_keys[sec][key_type ^ 1]}")
|
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
if abort:
|
if abort:
|
||||||
|
@ -217,7 +224,7 @@ for sec in range(NUM_SECTORS):
|
||||||
kt = ['a', 'b'][key_type]
|
kt = ['a', 'b'][key_type]
|
||||||
dic = f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type]}_filtered.dic"
|
dic = f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type]}_filtered.dic"
|
||||||
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
||||||
if DEBUG:
|
if args.debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
with out:
|
with out:
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
|
@ -226,8 +233,7 @@ for sec in range(NUM_SECTORS):
|
||||||
abort = True
|
abort = True
|
||||||
if "found:" in line:
|
if "found:" in line:
|
||||||
found_keys[sec][key_type] = line[30:]
|
found_keys[sec][key_type] = line[30:]
|
||||||
kt = ['A', 'B'][key_type]
|
print_key(sec, key_type, found_keys[sec][key_type])
|
||||||
print(f"Sector {sec:2} key{kt} = {found_keys[sec][key_type]}")
|
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
if abort:
|
if abort:
|
||||||
|
@ -240,7 +246,7 @@ for sec in range(NUM_SECTORS):
|
||||||
kt = ['a', 'b'][key_type]
|
kt = ['a', 'b'][key_type]
|
||||||
dic = f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type]}.dic"
|
dic = f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type]}.dic"
|
||||||
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
||||||
if DEBUG:
|
if args.debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
with out:
|
with out:
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
|
@ -250,8 +256,8 @@ for sec in range(NUM_SECTORS):
|
||||||
if "found:" in line:
|
if "found:" in line:
|
||||||
found_keys[sec][0] = line[30:]
|
found_keys[sec][0] = line[30:]
|
||||||
found_keys[sec][1] = line[30:]
|
found_keys[sec][1] = line[30:]
|
||||||
print(f"Sector {sec:2} keyA = {found_keys[sec][key_type]}")
|
print_key(sec, 0, found_keys[sec][key_type])
|
||||||
print(f"Sector {sec:2} keyB = {found_keys[sec][key_type]}")
|
print_key(sec, 1, found_keys[sec][key_type])
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -270,7 +276,7 @@ for sec in range(NUM_SECTORS):
|
||||||
else:
|
else:
|
||||||
dic = f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type_target]}.dic"
|
dic = f"keys_{uid:08x}_{sec:02}_{nt[sec][key_type_target]}.dic"
|
||||||
cmd = [STATICNESTED_2X1NT1KEY, nt[sec][key_type_source], found_keys[sec][key_type_source], dic]
|
cmd = [STATICNESTED_2X1NT1KEY, nt[sec][key_type_source], found_keys[sec][key_type_source], dic]
|
||||||
if DEBUG:
|
if args.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()
|
||||||
|
@ -283,7 +289,7 @@ for sec in range(NUM_SECTORS):
|
||||||
cmd = f"hf mf fchk --blk {sec * 4} -{kt} --no-default"
|
cmd = f"hf mf fchk --blk {sec * 4} -{kt} --no-default"
|
||||||
for k in keys:
|
for k in keys:
|
||||||
cmd += f" -k {k}"
|
cmd += f" -k {k}"
|
||||||
if DEBUG:
|
if args.debug:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
with out:
|
with out:
|
||||||
p.console(cmd)
|
p.console(cmd)
|
||||||
|
@ -295,8 +301,7 @@ for sec in range(NUM_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] != "":
|
||||||
kt = ['A', 'B'][key_type_target]
|
print_key(sec, key_type_target, found_keys[sec][key_type_target])
|
||||||
print(f"Sector {sec:2} key{kt} = {found_keys[sec][key_type_target]}")
|
|
||||||
if abort:
|
if abort:
|
||||||
break
|
break
|
||||||
if restore_color:
|
if restore_color:
|
||||||
|
@ -305,36 +310,59 @@ if restore_color:
|
||||||
|
|
||||||
if abort:
|
if abort:
|
||||||
print("Brute-forcing phase aborted via keyboard!")
|
print("Brute-forcing phase aborted via keyboard!")
|
||||||
FINAL_CHECK = False
|
args.no_final_check = True
|
||||||
|
|
||||||
if FINAL_CHECK:
|
if args.no_final_check:
|
||||||
print("Letting fchk do a final dump, just for confirmation and display...")
|
plus = "[" + color("+", fg="green") + "] "
|
||||||
keys_set = set([i for sl in found_keys for i in sl if i != ""])
|
print()
|
||||||
with (open(f"keys_{uid:08x}.dic", "w")) as f:
|
print(plus + color("found keys:", fg="green"))
|
||||||
for k in keys_set:
|
print()
|
||||||
f.write(f"{k}\n")
|
print(plus + "-----+-----+--------------+---+--------------+----")
|
||||||
cmd = f"hf mf fchk -f keys_{uid:08x}.dic --no-default --dump"
|
print(plus + " Sec | Blk | key A |res| key B |res")
|
||||||
if DEBUG:
|
print(plus + "-----+-----+--------------+---+--------------+----")
|
||||||
print(cmd)
|
for sec in range(NUM_SECTORS):
|
||||||
with out:
|
keys = [["", 0], ["", 0]]
|
||||||
p.console(cmd)
|
for key_type in [0, 1]:
|
||||||
for line in out.captured_output.split('\n'):
|
if found_keys[sec][key_type] == "":
|
||||||
print(line)
|
keys[key_type] = [color("------------", fg="red"), color("0", fg="red")]
|
||||||
else:
|
else:
|
||||||
print(found_keys)
|
keys[key_type] = [color(found_keys[sec][0], fg="green"), color("1", fg="green")]
|
||||||
print("Generating binary key file")
|
print(plus + f" {sec:03} | {sec*4+3:03} | {keys[0][0]} | {keys[0][1]} | {keys[1][0]} | {keys[1][1]} ")
|
||||||
|
print(plus + "-----+-----+--------------+---+--------------+----")
|
||||||
|
print(plus + "( " + color("0", fg="red") + ":Failed / " +
|
||||||
|
color("1", fg="green") + ":Success )")
|
||||||
|
print()
|
||||||
|
print(plus + "Generating binary key file")
|
||||||
keyfile = f"hf-mf-{uid:08X}-key.bin"
|
keyfile = f"hf-mf-{uid:08X}-key.bin"
|
||||||
|
unknown = False
|
||||||
with (open(keyfile, "wb")) as f:
|
with (open(keyfile, "wb")) as f:
|
||||||
for key_type in [0, 1]:
|
for key_type in [0, 1]:
|
||||||
for sec in range(NUM_SECTORS):
|
for sec in range(NUM_SECTORS):
|
||||||
k = found_keys[sec][key_type]
|
k = found_keys[sec][key_type]
|
||||||
if k == "":
|
if k == "":
|
||||||
k = "FFFFFFFFFFFF"
|
k = "FFFFFFFFFFFF"
|
||||||
|
unknown = True
|
||||||
f.write(bytes.fromhex(k))
|
f.write(bytes.fromhex(k))
|
||||||
print(f"Found keys have been dumped to `{keyfile}`")
|
print(plus + "Found keys have been dumped to `" + color(keyfile, fg="yellow")+"`")
|
||||||
print(" --[ FFFFFFFFFFFF ]-- has been inserted for unknown keys")
|
if unknown:
|
||||||
|
print("[" + color("=", fg="yellow") + "] --[ " + color("FFFFFFFFFFFF", fg="yellow") +
|
||||||
|
" ]-- has been inserted for unknown keys")
|
||||||
|
else:
|
||||||
|
print("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 != ""])
|
||||||
|
with (open(f"keys_{uid:08x}.dic", "w")) as f:
|
||||||
|
for k in keys_set:
|
||||||
|
f.write(f"{k}\n")
|
||||||
|
cmd = f"hf mf fchk -f keys_{uid:08x}.dic --no-default --dump"
|
||||||
|
if args.debug:
|
||||||
|
print(cmd)
|
||||||
|
with out:
|
||||||
|
p.console(cmd)
|
||||||
|
for line in out.captured_output.split('\n'):
|
||||||
|
print(line)
|
||||||
|
|
||||||
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(f"--- {minutes} minutes {seconds} seconds ---")
|
print("--- " + color(minutes, fg="yellow") + " minutes " +
|
||||||
|
color(seconds, fg="yellow") + " seconds ---")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue