def auth_card(mf_reader: MFRC522, uid, key_bin, block, key_a, format): cmd = mf_reader.PICC_AUTHENT1A if key_a else mf_reader.PICC_AUTHENT1B if key_bin is not None: trailer_block = get_trailer_block(block) if key_a: key = key_bin[trailer_block * 16:(trailer_block * 16) + 6] else: key = key_bin[(trailer_block * 16) + 10:(trailer_block * 16) + 16] if mf_reader.MFRC522_Auth(cmd, block, key, uid) == mf_reader.MI_OK: return True, key if format or key_bin is None: for key in GUESS_KEYS: if mf_reader.MFRC522_Auth(cmd, block, key, uid) == mf_reader.MI_OK: return True, key # Try to anticol again. mf_reader.MFRC522_HaltA() mf_reader.antennaOff() time.sleep(0.1) mf_reader.antennaOn() (success, _) = anticol(mf_reader, print_info=False, wakeup=True, no_rats=True) if not success: print('tag was removed', end='') return False, None # Faild to find keys. return False, None
def re_anticol(mf_reader: MFRC522): # Try to anticol again. mf_reader.MFRC522_HaltA() mf_reader.antennaOff() mf_reader.antennaOn() (success, _) = anticol(mf_reader, print_info=False, wakeup=True, no_rats=True) if not success: print('Tag has been removed') exit(-1)
def set_uid(format=False, recovery=False, lock=False): # Create an object of the class MFRC522 port = auto_find_port() mf_reader = MFRC522.MFRC522(dev=port) # Welcome message print_hex("MFRC522(%s) opened, will change UID to " % port, abt_data[:4]) if recovery or anticol(mf_reader)[0]: # Stop encrypted traffic so we can send raw bytes mf_reader.MFRC522_HaltA() if mf_reader.MFRC522_OpenUidBackdoor(): print("Card unlocked!") mf_reader.MFRC522_Write(0, abt_data) print("New Sector[00]\t%s" % (' '.join([('%02x' % x) for x in abt_data]))) if format: for i in range(3, 64, 4): print('Format Sector[%02d]' % i) mf_reader.MFRC522_Write(i, abt_blank) # Make sure to stop reading for cards mf_reader.MFRC522_HaltA() if lock: print( 'Warning: Locking card will make card no longer able to modify UID!' ) mf_reader.MFRC522_LockUidSector() # Halt again. mf_reader.MFRC522_HaltA() else: print('Error: No tag available') exit(-2)
def main(): if len(sys.argv) < 5: usage(sys.argv[0]) exit(-1) command = sys.argv[1] action_write = False if command in ['r', 'R', 'ra']: unlock = command == 'R' format_card = False no_auth = command == 'ra' elif command in ['w', 'W', 'f', 'wa']: unlock = command == 'W' format_card = command == 'f' action_write = True no_auth = command == 'rw' else: usage(sys.argv[0]) exit(-1) key_a = sys.argv[2] in ['a', 'A'] allow_failure = sys.argv[2] in ['A', 'B'] key_file = len(sys.argv) > 5 force_key_file = len(sys.argv) > 6 and sys.argv[6] == 'f' if sys.argv[3][0] == 'U': if len(sys.argv[3]) != 9: print( 'Error, illegal tag specification, use U01ab23cd for example.') usage(sys.argv[0]) exit(-1) tag_uid = [0] * 4 for i in range(0, 8, 2): tag_uid[int(i / 2)] = int(sys.argv[3][i + 1:(i + 3)], 16) print("Attempting to use specific UID: %02x %02x %02x %02x" % (tag_uid[0], tag_uid[1], tag_uid[2], tag_uid[3])) else: tag_uid = None # We don't know yet the card size so let's read only the UID from the keyfile for the moment key_bin = None if key_file: try: with open(sys.argv[5], 'rb') as key_fp: key_bin = list(key_fp.read()) if len(key_bin) < 4: print("Could not read UID from key file: %s" % sys.argv[5]) exit(-1) except IOError as err: print('Could not open keys file: %s, err = %s' % (sys.argv[5], err)) exit(-1) port = auto_find_port() mf_reader = MFRC522.MFRC522(dev=port) # Welcome message print("MFRC522(%s) opened." % port) (success, card_info) = anticol(mf_reader, no_rats=True) if not success: print('Error: no tag was found') exit(-1) (uid, sak, atqa, ats) = card_info if sak & 0x08 == 0: print('Warning: tag is probably not a MFC!') if key_file: if uid != key_bin[:4]: print_hex("Expected MIFARE Classic card with UID starting as: ", key_bin[:4]) print_hex("Got card with UID starting as: ", uid) if not force_key_file: print("Aborting!") exit(-1) print_hex('Found MIFARE Classic card: ', uid) # Guess size. if atqa[1] & 0x02 == 0x02 or sak == 0x18: # 4K blocks = 0xff elif sak == 0x09: # 320b blocks = 0x13 else: # 1K/2K, checked through RATS blocks = 0x3f # Testing RATS magic2 = False if ats != None: if len(ats) > 10 and ats[5:9] == [0xc1, 0x05, 0x2f, 0x2f ] and (atqa[1] & 0x02 == 0): # MIFARE Plus 2K blocks = 0x7f elif len(ats) == 9 and ats[5:9] == [0xda, 0xbc, 0x19, 0x10]: # // Chinese magic emulation card, ATS=0978009102:dabc1910 magic2 = True print('Guessing size: seems to be a %lu-byte card' % ((blocks + 1) * 16)) if key_file: if len(key_bin) != (blocks + 1) * 16: print('Could not read key file: %s, should %d vs %d' % (sys.argv[5], (blocks + 1) * 16, len(key_bin))) exit(-1) dump_bin = None if action_write: try: with open(sys.argv[4], 'rb') as dump_fp: dump_bin = list(dump_fp.read((blocks + 1) * 16)) if len(dump_bin) != (blocks + 1) * 16: print('Could not read key file: %s, should %d vs %d' % (sys.argv[4], (blocks + 1) * 16, len(dump_bin))) exit(-1) except IOError as err: print('Could not open dump file: %s, err = %s' % (sys.argv[4], err)) exit(-1) # Begin the real work. if not action_write: (success, dump_bin) = read_card(mf_reader, uid, unlock, key_bin, magic2, blocks, key_a, allow_failure, no_auth) if success: print('Writing data to file: %s ...' % sys.argv[4], end='', flush=True) try: with open(sys.argv[4], 'wb') as dump_fp: write_cnt = dump_fp.write(bytearray(dump_bin)) if write_cnt != (blocks + 1) * 16: print('Could not write to file: %s, should %d vs %d' % (sys.argv[4], (blocks + 1) * 16, write_cnt)) success = False else: print('Done.') except IOError as err: print('Could not open dump file: %s, err = %s' % (sys.argv[4], err)) success = False else: success = write_card(mf_reader, uid, unlock, key_bin, magic2, blocks, key_a, allow_failure, dump_bin, format_card, no_auth) mf_reader.MFRC522_HaltA() mf_reader.MFRC522_StopCrypto1() exit(0 if success else -1)
def write_card(mf_reader, uid, write_block_zero, key_bin, magic2, blocks, key_a, allow_failure, dump_bin, format_card, no_auth): if write_block_zero: if magic2: print('Note: This card does not require an unlocked write (W)') write_block_zero = False else: mf_reader.MFRC522_HaltA() if mf_reader.MFRC522_OpenUidBackdoor(): print("Card unlocked!") else: return False print('Writing %d blocks |' % (blocks + 1), end='', flush=True) failure = False success_blocks = 0 for block in range(0, blocks + 1): if is_first_block(block): if failure: (success, _) = anticol(mf_reader, print_info=False, wakeup=True, no_rats=True) if not success: print('!\nError: tag was removed') return False if not write_block_zero and not no_auth and not auth_card( mf_reader, uid, key_bin, block, key_a, format_card) and not allow_failure: print('!\nError: authentication failed for block 0x%02x' % block) return False if is_trailer_block(block): if format_card: # Copy the default key and reset the access bits trailer = DEFAULT_KEY + DEFAULT_ACL + DEFAULT_KEY else: trailer = dump_bin[block * 16:(block + 1) * 16] # Try to write the trailer if mf_reader.MFRC522_Write(block, trailer) != mf_reader.MI_OK: print('failed to write trailer block %d' % block, end='', flush=True) failure = True else: if block == 0 and not write_block_zero and not magic2: continue # Make sure a earlier write did not fail if not failure: if format_card and block: data = [0x00] * 16 else: data = dump_bin[block * 16:(block + 1) * 16] if block == 0: if data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[ 4] != 0x0 and not magic2: print('!\nError: incorrect BCC in MFD file!') print('Expecting BCC=%02X' % data[0] ^ data[1] ^ data[2] ^ data[3]) return False if mf_reader.MFRC522_Write(block, data) != mf_reader.MI_OK: failure = True # Show if the write went well for each block success_blocks = print_success_or_failure(failure, success_blocks) if not allow_failure and failure: return False print('|') print('Done, %d of %d blocks written.' % (success_blocks, blocks + 1)) return True
def read_card(mf_reader, uid, read_unlock, key_bin, magic2, blocks, key_a, allow_failure, no_auth): if read_unlock: if magic2: print('Note: This card does not require an unlocked write (R)') read_unlock = False else: mf_reader.MFRC522_HaltA() if mf_reader.MFRC522_OpenUidBackdoor(): print("Card unlocked!") else: return False, None print('Reading out %d blocks |' % (blocks + 1), end='', flush=True) failure = False dump_bin = [] success_blocks = 0 # Read the card from end to begin for block in range(blocks, -1, -1): # Authenticate everytime we reach a trailer block if is_trailer_block(block): if failure: # When a failure occured we need to redo the anti-collision (success, _) = anticol(mf_reader, print_info=False, wakeup=True, no_rats=True) if not success: print('!\nError: tag was removed') return False, None if not read_unlock and not no_auth: (success, key) = auth_card(mf_reader, uid, key_bin, block, key_a, False) if not success: print('!\nError: authentication failed for block 0x%02x' % block) return False, None if no_auth: # Try to collect as default key. key = DEFAULT_KEY (status, data) = mf_reader.MFRC522_Read(block) if status == mf_reader.MI_OK: # We read in reverse order, so we append data in front of last data. if read_unlock: dump_bin = data[1] + dump_bin elif key_bin: dump_bin = (key_bin[block * 16:(block * 16) + 6] + data[1][6:10] + key_bin[(block * 16) + 10: (block * 16) + 16]) + dump_bin else: dump_bin = ( (key if key_a else DEFAULT_KEY) + data[1][6:10] + (DEFAULT_KEY if key_a else key)) + dump_bin else: print('!\nfailed to read trailer block 0x%02x' % block) failure = True else: # Make sure a earlier readout did not fail if not failure: (status, data) = mf_reader.MFRC522_Read(block) if status == mf_reader.MI_OK: # We read in reverse order, so we append data in front of last data. dump_bin = data[1] + dump_bin else: print('!\nError: unable to read block 0x%02x' % block) failure = True # Show if the readout went well for each block success_blocks = print_success_or_failure(failure, success_blocks) if not allow_failure and failure: return False, None print('|') print('Done, %d of %d blocks read.' % (success_blocks, blocks + 1)) return True, dump_bin
def main(): d = Denonce(None, 0, DEFAULT_DIST_NR, DEFAULT_TOLERANCE, [0x00, 0x00, 0x00]) t = MfTag() optlist, args = getopt.getopt(sys.argv[1:], 'hD:s:BP:T:S:O:k:t:f:') fp_dump = None fp_key = None customer_keys = [] for (opt_key, opt_value) in optlist: if opt_key == '-P': probes = int(opt_value) if probes < 1: print('The number of probes must be a positive number') exit(-1) elif opt_key == '-T': res = int(opt_value) if res < 0: print( 'The nonce distances range must be a zero or a positive number' ) exit(-1) d.tolerance = res elif opt_key == '-f': try: with open(opt_value, 'r') as fp: lines = fp.readlines() for line in lines: key_match = re.match(KEY_REGEX, line) if key_match is not None: customer_keys.append(str_to_key( key_match.group(1))) print( 'The custom key 0x%s has been added to the default keys' % key_match.group(1)) except IOError as err: print('Cannot open keyfile: %s, err = %s, exiting' % (opt_value, err)) exit(-1) elif opt_key == '-k': key_match = re.match(KEY_REGEX, opt_value) if key_match is not None: customer_keys.append(str_to_key(key_match.group(1))) print( 'The custom key 0x%s has been added to the default keys' % key_match.group(1)) else: print('Custom key %s invalid, ignored' % opt_value) elif opt_key == '-O': # File output try: fp_dump = open(opt_value, 'wb') except IOError as err: print('Cannot open output file: %s, err = %s, exiting' % (opt_value, err)) exit(-1) elif opt_key == '-D': # Partial file output try: fp_key = open(opt_value, 'wb') except IOError as err: print('Cannot open key file: %s, err = %s, exiting' % (opt_value, err)) exit(-1) elif opt_key == '-h': usage(0) else: usage(1) if fp_dump is None: print('Parameter -O is mandatory') exit(-1) port = auto_find_port() mf_reader = MFRC522.MFRC522(dev=port) (success, card_info) = anticol(mf_reader, no_rats=True) if not success: print('No tag found') exit(-1) (uid, sak, atqa, ats) = card_info if sak & 0x08 == 0 and sak != 0x01: print('Only Mifare Classic is supported') exit(-1) # Use last full bytes. t.auth_uid = uid[-4:] if sak in [0x01, 0x08, 0x88, 0x28]: # Check if MIFARE Plus 2K if ats is not None and len(ats) >= 10 and ats[5:9] == [ 0xc1, 0x05, 0x2f, 0x2f ] and (atqa[1] & 0x02 == 0): print('Found Mifare Plus 2k tag') t.num_sectors = NR_TRAILERS_2k t.num_blocks = NR_BLOCKS_2k else: print('Found Mifare Classic 1k tag') t.num_sectors = NR_TRAILERS_1k t.num_blocks = NR_BLOCKS_1k elif sak == 0x09: print('Found Mifare Classic Mini tag') t.num_sectors = NR_TRAILERS_MINI t.num_blocks = NR_BLOCKS_MINI elif sak == 0x18: print('Found Mifare Classic 4k tag') t.num_sectors = NR_TRAILERS_4k t.num_blocks = NR_BLOCKS_4k else: print('Cannot determine card type from SAK') exit(-1) t.sectors = [Sector() for _ in range(t.num_sectors)] p_keys = [] b_keys = [] d.distances = [0 for _ in range(d.num_distances)] print('Try to authenticate to all sectors with default keys...') print( "Symbols: '.' no key found, '/' A key found, '\\' B key found, 'x' both keys found" ) # Try customer_keys first, than default GUESS_KEYS for key in customer_keys + GUESS_KEYS: print_hex('[Key: ', key, end='') print('] -> [', end='', flush=True) i = 0 # Sector counter # Iterate over every block, where we haven't found a key yet for block in range(t.num_blocks + 1): if is_trailer_block(block): if not t.sectors[i].found_keyA: if mf_reader.MFRC522_Auth(mf_reader.PICC_AUTHENT1A, block, key, t.auth_uid) != mf_reader.MI_OK: # Try to anticol again. re_anticol(mf_reader) else: # Save all information about successfull keyA authentization t.sectors[i].keyA = key t.sectors[i].found_keyA = True # Although KeyA can never be directly read from the data sector, KeyB can, so # if we need KeyB for this sector, it should be revealed by a data read with KeyA # todo - check for duplicates in cracked key list (do we care? will not be huge overhead) # todo - make code more modular! :) if not t.sectors[i].found_keyB: (status, data) = mf_reader.MFRC522_Read(block) if status == mf_reader.MI_OK: keyB = data[1][10:16] if mf_reader.MFRC522_Auth( mf_reader.PICC_AUTHENT1B, block, keyB, t.auth_uid) != mf_reader.MI_OK: re_anticol(mf_reader) else: t.sectors[i].keyB = keyB t.sectors[i].found_keyB = True b_keys.append(keyB) else: # Try to anticol again. re_anticol(mf_reader) # if key reveal failed, try other keys if not t.sectors[i].found_keyB: if mf_reader.MFRC522_Auth(mf_reader.PICC_AUTHENT1B, block, key, t.auth_uid) != mf_reader.MI_OK: # Try to anticol again. re_anticol(mf_reader) # No success, try next block t.sectors[i].trailer = block else: t.sectors[i].keyB = key t.sectors[i].found_keyB = True if t.sectors[i].found_keyA and t.sectors[i].found_keyB: print('x', end='', flush=True) elif t.sectors[i].found_keyA: print('/', end='', flush=True) elif t.sectors[i].found_keyB: print('\\', end='', flush=True) else: print('.', end='', flush=True) # Save position of a trailer block to sector struct t.sectors[i].trailer = block i += 1 print("]") print() known_key = None known_key_letter = None known_section = None unknown_key_letter = None unknown_sector = None for i in range(t.num_sectors): if t.sectors[i].found_keyA: print_hex('Sector %02d - Found Key A: ' % i, t.sectors[i].keyA, end='') known_key = t.sectors[i].keyA known_key_letter = 'A' known_section = i else: print('Sector %02d - Unknown Key A ' % i, end='', flush=True) unknown_key_letter = 'A' unknown_sector = i if t.sectors[i].found_keyB: print_hex(' Sector %02d - Found Key B: ' % i, t.sectors[i].keyB) known_key = t.sectors[i].keyB known_key_letter = 'B' known_section = i else: print(' Sector %02d - Unknown Key B' % i) unknown_key_letter = 'B' unknown_sector = i