Skip to content

Instantly share code, notes, and snippets.

@HDR
Created June 10, 2025 11:46
Show Gist options
  • Save HDR/6746ab7a958171411d1bd0e955100784 to your computer and use it in GitHub Desktop.
Save HDR/6746ab7a958171411d1bd0e955100784 to your computer and use it in GitHub Desktop.
A Proxmark3 pyscripts python script that dumps bambu rfid tags in one go.
#!/usr/bin/env python3
import time
import json
from hkdf import Hkdf
import hashlib
import pm3
from datetime import datetime
import struct
try:
from colors import color
except ModuleNotFoundError:
def color(s, fg=None):
_ = fg
return str(s)
def hex_to_little_endian(hex_value):
hex_array = [hex_value[i:i+2] for i in range(0, len(hex_value), 2)]
flipped_hex = ''.join(hex_array[::-1])
return int(flipped_hex, 16)
def decode_text(hex_string):
byte_array = bytes.fromhex(hex_string)
return byte_array.decode("utf-8", errors="ignore").strip("\x00")
def build_spool_data(file_path):
with open(file_path, "r") as file:
data = json.load(file)
blocks = data.get("blocks", {})
serial = blocks["9"]
filament_type = decode_text(blocks["4"][:32])
red = int(blocks["5"][0:2], 16)
green = int(blocks["5"][2:4], 16)
blue = int(blocks["5"][4:6], 16)
alpha = int(blocks["5"][6:8], 16)
spool_color = f"R:{red}, G:{green}, B:{blue}, A:{alpha}"
fg_color = red, green, blue
prod_timedate = decode_text(blocks["12"][:32])
struct_time = time.strptime(prod_timedate, "%Y_%m_%d_%H_%M")
production_date = time.strftime("%B %d, %Y %H:%M", struct_time)
return serial, filament_type, production_date, spool_color, fg_color
def invert_color(rgb):
return tuple(255 - component for component in rgb)
def generate_keys(uid):
hkdf = Hkdf(salt=bytes.fromhex("9A759CF2C4F7CAFF222CB9769B41BC96"), input_key_material=uid, hash=hashlib.sha256)
num_keys = 2 * 7 + 2
derived = hkdf.expand(length=6 * num_keys, info=b"RFID-A\0")
keys = [derived[i:i+6].hex().upper() for i in range(0, len(derived), 6)]
return [[keys[i], keys[i+1]] for i in range(0, len(keys), 2)]
def dump():
def show(s='', prompt=f"[{color('=', fg='yellow')}] ", **kwargs):
s = f"{prompt}" + f"\n{prompt}".join(s.split('\n'))
print(s, **kwargs)
start_time = time.time()
p = pm3.pm3()
p.console("hf 14a read")
uid = None
for line in p.grabbed_output.split('\n'):
if "UID:" in line:
uid = int(line[10:].replace(' ', '')[-8:], 16)
if uid is None:
show("Card not found")
return False
show(f"UID: {color(f'{uid:08X}', fg='green')}")
found_keys = generate_keys(uid.to_bytes(4, 'big'))
dic_path = f"client/dictionaries/{uid:08X}.dic"
with open(dic_path, "w") as f:
for pair in found_keys:
for key in pair:
f.write(f"{key}\n")
show(f"Dictionary written to {color(dic_path, fg='cyan')}")
p.console("prefs show --json")
raw = p.grabbed_output.strip()
prefs = json.loads(raw)
dump_path = prefs.get("file.default.dumppath", ".")
show("Dumping keys")
p.console(f"hf mf fchk --1k -f {uid:08X} --dump")
show(f"Keyfile written to {color(f'{dump_path}/hf-mf-{uid:08X}-key.bin', fg='cyan')}")
keyfile = f"hf-mf-{uid:08X}-key.bin"
show("Dumping Spool Data")
p.console(f"hf mf dump -k {keyfile}")
show(f"hf-mf-{uid:08X}-dump.bin & hf-mf-{uid:08X}-dump.json written to {color(dump_path, fg='cyan')}")
elapsed = time.time() - start_time
minutes = int(elapsed // 60)
seconds = int(elapsed % 60)
show(f"---- DONE: {minutes:2} minutes {seconds:2} seconds ----")
spool_dump = f"{dump_path}/hf-mf-{uid:08X}-dump.json"
serial, filament_type, production_date, spool_color, fg_color = build_spool_data(spool_dump)
show(f"Serial Number: {color(serial, fg='green')}")
show(f"Filament Type: {color(filament_type, fg='green')}")
show(f"Color: {color(spool_color, fg=invert_color(fg_color), bg=fg_color)}")
show(f"Production Date: {color(production_date, fg='green')}")
def main():
dump()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment