diff --git a/CHANGELOG.md b/CHANGELOG.md index bc5da24d9..fda262dde 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] +- Fixed `intertic.py` - missing comma in array (@iceman1001) - Added improved algorithm for `hf iclass legrec` leveraging reduced entropy from hash0 constraints (@antiklesys) - Fixed `hf iclass configcard` when generating elite or keyroll elite configcards for Rev.C legacy readers (@antiklesys) - Changed `hf mf c*` - now accepts a --gdm flag to write using uscuid/gdm 20/23 alt magic wakeup (@nvx) diff --git a/client/pyscripts/fm11rf08_full.py b/client/pyscripts/fm11rf08_full.py index aa55889ef..1d37d9abc 100644 --- a/client/pyscripts/fm11rf08_full.py +++ b/client/pyscripts/fm11rf08_full.py @@ -13,12 +13,7 @@ import json from fm11rf08s_recovery import recovery -# ------------------------------------------------------------------------------ -# Revision log & Licence -# ------------------------------------------------------------------------------ -''' -1.2.0 - BC - Proxmark3 Submission -''' +author = "@csBlueChip" script_ver = "1.2.0" # Copyright @csBlueChip @@ -123,7 +118,7 @@ globals: # No logfile name yet lprint("Fudan FM11RF08[S] full card recovery") - lprint(f"\nDump folder: {dpath}") + lprint(f"\nDump folder... " + color(f"{dpath}", fg="yellow")) # FIXME: script is announced as for RF08 and for RF08S but it comprises RF32N key # and if RF08 is supported, all other NXP/Infineon with same backdoor can be treated @@ -143,7 +138,8 @@ globals: # Currently loadKeys is hardcoded for RF08S if args.force or (key := loadKeys(keyfile)) is None: if args.recover is False: - lprint("* Keys not loaded, use --recover to run recovery script [slow]") + s = color("--recover", fg="yellow") + lprint(f"Keys not loaded, use {s} to run recovery script [slow]") else: # FIXME: recovery() is only for RF08S. TODO for the other ones with a "darknested" attack keyfile = recoverKeys() @@ -153,7 +149,8 @@ globals: ret, mad, key = verifyKeys(key) if ret is False: if args.nokeys is False: - lprint("! Use --nokeys to keep going past this point") + s = color("--nokeys", fg="yellow") + lprint(f"Use {s} to keep going past this point") return # FIXME: nr of blocks depend on the tag. RF32 is 256, RF08 is 64, RF08S is 64+8 @@ -375,7 +372,7 @@ If keys cannot be loaded AND --recover is specified, then run key recovery """ key = [[b'' for _ in range(2)] for _ in range(17)] # create a fresh array - lprint(f"\nLoad Keys from file: |{keyfile}|") + lprint(f"\n Load keys from file... " + color(f"{keyfile}", fg="yellow")) try: with (open(keyfile, "rb")) as fh: @@ -434,7 +431,7 @@ globals: badk = 0 mad = False - lprint("Check keys...") + lprint("Checking keys...") for sec in range(0, 16+1): # 16 normal, 1 dark sn = sec @@ -450,11 +447,13 @@ globals: lprint(f" `{cmd}`", end='', flush=True) res = p.console(cmd, capture=False) - lprint(" " * (3-len(str(bn))), end="", prompt='') + lprint(" " * (3-len(str(bn))), end='', prompt='') if res == 0: - lprint(" ... PASS", end="", prompt='') + s = color("ok", fg="green") + lprint(f" ( {s} )", end='', prompt='') else: - lprint(" ... FAIL", end="", prompt='') + s = color("fail", fg="red") + lprint(f" ( {s} )", end='', prompt='') badk += 1 key[sec][ab] = b'' @@ -467,8 +466,9 @@ globals: lprint("", prompt='') if badk > 0: - lprint(f"! {badk} bad key", end='') - lprint("s exist" if badk != 1 else " exists") + s = color(f'{badk}', fg="red") + e = "s exist" if badk != 1 else " exists" + lprint(f" {s} bad key{e}", prompt='[!]') rv = False, mad, key else: @@ -920,9 +920,9 @@ def dumpAcl(data): def diskDump(data, uid, dpath): """Full Dump""" - dump18 = f"{dpath}hf-mf-{uid.hex().upper()}-dump18.bin" + dump18 = color(f"{dpath}hf-mf-{uid.hex().upper()}-dump18.bin", fg="yellow") - lprint(f"\nDump Card Data to file: {dump18}") + lprint(f"\nDump Card Data to file... {dump18}") bad = False with open(dump18, 'wb') as f: diff --git a/client/pyscripts/intertic.py b/client/pyscripts/intertic.py index 88a2be07b..8d6d865d6 100644 --- a/client/pyscripts/intertic.py +++ b/client/pyscripts/intertic.py @@ -90,11 +90,11 @@ def Describe_Usage_1(Usage, ContractMediumEndDate, Certificate): unk = Usage.nom_bits(65) EventValidityTimeFirstStamp = Usage.nom(11) - print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))); + print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))) print(' EventTimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60)) - print(' unk1... :', unk); + print(' unk1... :', unk) print(' EventValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60)) - print(' left... :', Usage.nom_bits_left()); + print(' left... :', Usage.nom_bits_left()) print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) def Describe_Usage_1_1(Usage, ContractMediumEndDate, Certificate): @@ -110,18 +110,18 @@ def Describe_Usage_1_1(Usage, ContractMediumEndDate, Certificate): EventCountPassengers_mb = Usage.nom(4) EventValidityTimeFirstStamp = Usage.nom(11) - print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))); + print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))) print(' TimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60)) - print(' unk0... :', unk0); + print(' unk0... :', unk0) print(' Code/Nature : 0x{:x} ({})'.format(EventCode_Nature, TYPE_EventCode_Nature.get(EventCode_Nature, '?'))) print(' Code/Type : 0x{:x} ({})'.format(EventCode_Type, TYPE_EventCode_Type.get(EventCode_Type, '?'))) - print(' unk1... :', unk1); + print(' unk1... :', unk1) print(' GeoVehicleId : {}'. format(EventGeoVehicleId)) print(' GeoRouteId : {}'. format(EventGeoRouteId)) print(' Direction : {} ({})'. format(EventGeoRoute_Direction, TYPE_EventGeoRoute_Direction.get(EventGeoRoute_Direction, '?'))) print(' Passengers(?) : {}'. format(EventCountPassengers_mb)) print(' ValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60)) - print(' left... :', Usage.nom_bits_left()); + print(' left... :', Usage.nom_bits_left()) print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) def Describe_Usage_1_2(Usage, ContractMediumEndDate, Certificate): @@ -143,19 +143,19 @@ def Describe_Usage_1_2(Usage, ContractMediumEndDate, Certificate): 0x1: 'tramway', } - print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))); + print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))) print(' TimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60)) print(' Count(?) : {}'. format(EventCount_mb)) - print(' unk0... :', unk0); + print(' unk0... :', unk0) print(' Code/Nature(?) : 0x{:x} ({})'.format(EventCode_Nature_mb, TYPE_EventCode_Nature_Reims.get(EventCode_Nature_mb, '?'))) print(' Code/Type(?) : 0x{:x} ({})'.format(EventCode_Type_mb, TYPE_EventCode_Type.get(EventCode_Type_mb, '?'))) - print(' unk1... :', unk1); + print(' unk1... :', unk1) print(' GeoVehicleId : {}'. format(EventGeoVehicleId)) print(' GeoRouteId : {}'. format(EventGeoRouteId)) print(' Direction : {} ({})'. format(EventGeoRoute_Direction, TYPE_EventGeoRoute_Direction.get(EventGeoRoute_Direction, '?'))) print(' Passengers(?) : {}'. format(EventCountPassengers_mb)) print(' ValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60)) - print(' left... :', Usage.nom_bits_left()); + print(' left... :', Usage.nom_bits_left()) print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) @@ -171,17 +171,17 @@ def Describe_Usage_2(Usage, ContractMediumEndDate, Certificate): EventCountPassengers_mb = Usage.nom(4) EventValidityTimeFirstStamp = Usage.nom(11) - print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))); + print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))) print(' TimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60)) - print(' unk0... :', unk0); + print(' unk0... :', unk0) print(' Code/Nature : 0x{:x} ({})'.format(EventCode_Nature, TYPE_EventCode_Nature.get(EventCode_Nature, '?'))) print(' Code/Type : 0x{:x} ({})'.format(EventCode_Type, TYPE_EventCode_Type.get(EventCode_Type, '?'))) - print(' unk1... :', unk1); + print(' unk1... :', unk1) print(' GeoRouteId : {}'. format(EventGeoRouteId)) print(' Direction : {} ({})'. format(EventGeoRoute_Direction, TYPE_EventGeoRoute_Direction.get(EventGeoRoute_Direction, '?'))) print(' Passengers(?) : {}'. format(EventCountPassengers_mb)) print(' ValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60)) - print(' left... :', Usage.nom_bits_left()); + print(' left... :', Usage.nom_bits_left()) print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) def Describe_Usage_3(Usage, ContractMediumEndDate, Certificate): @@ -190,11 +190,11 @@ def Describe_Usage_3(Usage, ContractMediumEndDate, Certificate): unk = Usage.nom_bits(27) EventValidityTimeFirstStamp = Usage.nom(11) - print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))); + print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))) print(' EventTimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60)) - print(' unk1... :', unk); + print(' unk1... :', unk) print(' EventValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60)) - print(' left... :', Usage.nom_bits_left()); + print(' left... :', Usage.nom_bits_left()) print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) def Describe_Usage_4(Usage, ContractMediumEndDate, Certificate): @@ -203,16 +203,16 @@ def Describe_Usage_4(Usage, ContractMediumEndDate, Certificate): unk = Usage.nom_bits(63) EventValidityTimeFirstStamp = Usage.nom(11) - print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))); + print(' EventDateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))) print(' EventTimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60)) - print(' unk1... :', unk); + print(' unk1... :', unk) print(' EventValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60)) - print(' left... :', Usage.nom_bits_left()); + print(' left... :', Usage.nom_bits_left()) print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) def Describe_Usage_Generic(Usage, ContractMediumEndDate, Certificate): print(' !!! GENERIC DUMP - please provide full file dump to benjamin@gentilkiwi.com - especially if NOT empty !!!') - print(' left... :', Usage.nom_bits_left()); + print(' left... :', Usage.nom_bits_left()) print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) print(' !!! Trying Usage_1 (the most common) !!!') Usage.reset() @@ -241,7 +241,7 @@ FRA_OrganizationalAuthority_Contract_Provider = { }, 0x013: { 1: InterticHelper('Avignon', 'Orizo'), - } + }, 0x021: { 1: InterticHelper('Bordeaux', 'TBM / Keolis', Describe_Usage_1_1), }, @@ -378,7 +378,7 @@ def main(): return 3 - print('PID (product): 0x{:02x} (flipflop?: {})'.format(PID, (PID & 0x10) != 0)); + print('PID (product): 0x{:02x} (flipflop?: {})'.format(PID, (PID & 0x10) != 0)) print('KeyId : 0x{:1x}'.format(KeyId)) print() @@ -401,10 +401,11 @@ def main(): Distribution_left = Distribution_Data.nom_bits_left() print('DISTRIBUTION') - print(' CountryCode : {:03x} - {}'.format(CountryCode, ISO_Countries.get(CountryCode, '?'))); - print(' OrganizationalAuthority : {:03x}'.format(OrganizationalAuthority)); - print(' ContractApplicationVersionNumber:', ContractApplicationVersionNumber); - print(' ContractProvider :', ContractProvider); + print(' CountryCode : {:03x} - {}'.format(CountryCode, ISO_Countries.get(CountryCode, '?'))) + print(' OrganizationalAuthority : {:03x}'.format(OrganizationalAuthority)) + print(' ContractApplicationVersionNumber:', ContractApplicationVersionNumber) + print(' ContractProvider :', ContractProvider) + if (CountryCode == 0x250): oa = FRA_OrganizationalAuthority_Contract_Provider.get(OrganizationalAuthority) if (oa is not None): @@ -412,9 +413,10 @@ def main(): if (s is not None): print(' ~ Authority & Provider ~ : {} ({})'.format(s.OrganizationalAuthority, s.ContractProvider)) Describe_Usage = s.UsageDescribeFunction - print(' ContractTariff :', ContractTariff); - print(' ContractMediumEndDate : {} ({})'.format(ContractMediumEndDate, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate)).strftime('%Y-%m-%d'))); - print(' left... :', Distribution_left); + + print(' ContractTariff :', ContractTariff) + print(' ContractMediumEndDate : {} ({})'.format(ContractMediumEndDate, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate)).strftime('%Y-%m-%d'))) + print(' left... :', Distribution_left) print(' [CER] Distribution : {:08x}'.format(Distribution_Cer.nom(32))) print()