Created
June 10, 2025 11:46
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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