예제 #1
0
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
예제 #2
0
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)
예제 #3
0
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)
예제 #4
0
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)
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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