What is written inside the contactless cards of the Kiev metro?

    Contactless cards in the Kiev metro began to be introduced in 2007 ( information on the metro website, Ukrainian ), but they were widely distributed and introduced only by the end of 2008. To date, there are two main types of tickets: tickets with a validity period, and tickets for the number of trips. Travel cards use MIFARE Classic 1K proximity cards .


    Photo - Metromuseum.net

    MIFARE Classic chip vulnerabilities became known in 2007. A detailed history of vulnerability discovery can be found in the article.. Although the article was published in 2008, it is still relevant, and it lists the main stages of finding vulnerabilities. Combining this knowledge, you can see what is written on the maps of the Kiev metro on the example of a travel card for the number of trips.

    Disclaimer: All actions and information described below are provided solely to broaden one's personal horizons and are not intended for personal gain.


    Set up a workplace


    To read contactless cards, we will use:
    • reader - SCL3711 ;
    • open library for working with contactless cards - libnfc ;
    • a utility for obtaining keys is mfoc from the nfc-tools bundle .

    Reader



    So, as we will use libnfc, the reader must be chosen from those with which the library is best compatible. We select the suitable one on the compatibility page and buy. I settled on the SCL3711 reader with a PN533 v2.7 chip (in the photo, I bought on eBay for $ 35).

    Libnfc library

    I will describe the assembly procedure for libnfc for Ubuntu 12.04, for other platforms detailed installation instructions are on the site .

    We install the dependencies necessary for building packages and working with SVN (for those who are not installed):
    sudo apt-get install subversion dpkg-dev debhelper dh-autoreconf libtool

    Install the packages that are needed to build libnfc:
    sudo apt-get install libuсsb-dev libpcsclite-dev

    Download and unpack the latest version of the library (1.6.0-rc1), from the repository download the files necessary for building the deb package:
    wget http://libnfc.googlecode.com/files/libnfc-1.6.0-rc1.tar.gz
    tar -xvzf libnfc-1.6.0-rc1.tar.gz
    cd libnfc-1.6.0-rc1 /
    svn checkout http : //libnfc.googlecode.com/svn/tags/libnfc-1.6.0-rc1/debian

    I recommend removing debugging output. To do this, remove the --enable-debug switch in the dh_auto_configure line in the debian / rules file . We collect packages:


    dpkg-buildpackage -b -us -uc

    Install dependencies and packages:
    sudo apt-get install libusb-0.1-4 libpcsclite1 libccid pcscd
    sudo dpkg -i ../libnfc*.deb

    To check the reader must be connected and next to it (in the radius of its action) lie a card. We check the operability by the nfc-list command, which displays a list of readers and cards, in the reader field:
    $ nfc-list
    nfc-list uses libnfc 1.6.0-rc1 (rexported)
    NFC device: SCM Micro / SCL3711-NFC & RW - PN533 v2.7 (0x07) opened
        ATQA (SENS_RES): 00 04
           UID (NFCID1): 5b b8 5f 28
          SAK (SEL_RES): 08

    If you saw something like that, then it all works. At first I got the error " libnfc.driver.pn53x_usb Unable to set USB configuration (Device or resource busy) ". The fact is that in Ubuntu 12.04, by default, some drivers for the PN533 chip are installed, and libnfc can not access the device. It is treated by disabling the built-in driver " sudo modprobe -r pn533 ".

    Mfoc utility

    We will use the mfoc utility from the latest version of nfc-tools from the repository. Problems should not arise:
    svn checkout http://nfc-tools.googlecode.com/svn/trunk/mfoc/ mfoc
    cd mfoc
    dpkg-buildpackage -b -us -uc
    sudo dpkg -i mfoc_0.10.2pre3.1-0_amd64.deb


    Look inside


    Theoretical part

    MIFARE Classic 1K cards have 1 KB of memory, which is divided into 16 sectors. Each sector consists of 4 blocks of 16 bytes. Each sector is protected by two 48-bit keys A and B (which are stored in 4 blocks).



    For operations with a specific sector, the reader must be authorized using one of the keys (A or B) for this sector. Each key can be assigned independent read and write permissions. The vulnerability that mfoc uses is that if a key is known to at least one sector, then after authorization for this sector, mfoc tries to authenticate for another sector, and this attempt reveals 32 bits of the key for a new sector. You can read more and correctly in the article Wirelessly Pickpocketing a Mifare Classic Card .

    Practical part

    We get the keys to the card using the mfoc utility:
    mfoc -O keys.mfd

    After about a minute, you will get the answer " Auth with all sectors succeeded, dumping keys to a file! ". After that, the keys to the map are in the keys.mfd file . The keys for all cards are the same , and by the way, they have been posted on the Internet for a long time (obviously, by one of the employees) .

    For analysis, merge the dump map:
    nfc-mfclassic r a new00-04-11.mfd keys.mfd

    We repeat the procedure after each trip on the subway or topping up the account, and we get a sufficient set of dumps for analysis.

    Analysis

    I will not give long thoughts, I will dwell on the conclusions. After each operation, two sections of the memory header and the history of the operation change.

    The header of the card is two identical blocks at the addresses 0x2D0 and 0x2E0. Each block contains information about the sequence number of the card transaction, the remaining number of trips and the date and time of the last operation. The date and time are recorded strangely: bitwise, and for some reason the seconds are divided by 2 (see code below).

    Blocks containing the history of the last six operations are located at 0xC0, 0xD0, 0xE0, 0x100, 0x110, 0x120. Each entry contains:
    • date and time of the operation,
    • number of the terminal that recorded
    • terminal journal entry number,
    • number of trips.

    The terminal number should depend on the metro station, but I'm not completely sure. Date and time are recorded in a different, but in the same wonderful format, as in the title.

    Example


    A python program that reads data from a dump obtained using nfc-mfclassic:
    #! / usr / bin / env python
    import sys
    from struct import unpack 
    from datetime import datetime
     
    def get_crc (block):
        "" "XOR all bytes in block" ""
        return reduce (lambda x, y: x ^ ord (y) , block, 0)
     
    def get_bits (i, s, l):
        "" "Get l bits starting at s" ""
        mask = (1 << (l)) - 1 
        return int ((i >> s) & mask )
     
    def print_info (data):
        # card number
        number = unpack ('<4H', data [0x46: 0x4E])
        print "Card #: tt {3: 04X} {2: 04X} {1: 04X} {0: 04X} ". Format (* number)
     
        # card header blocks
        header_block = data [0x2D0:0x2E0]
        crc_2d = get_crc (header_block)
        crc_2e = get_crc (data [0x2E0: 0x2F0])
        print "nHeader: t" + ("ok" if crc_2d == crc_2e else "err")
        print "Block 0x2D CRC: t {: # x}". format (crc_2d)
        print "Block 0x2E CRC: t {: # x } ". format (crc_2e)
     
        # last activity
        activity_number, activity2, activity1 = unpack ('> HLH', data [0x2E2: 0x2EA])
        activity = activity1 + (activity2 << 16)
        activity_count = get_bits (activity, 38, 10)
        y = get_bits (activity, 6, 5) + 2000
        M = get_bits (activity, 11, 4)
        d = get_bits (activity, 15, 5)
        h = get_bits (activity, 20, 5)
        m = get_bits (activity, 25, 6)
        s = get_bits (activity, 31, 5) * 2
        activity_date = datetime (y, M, d, h, m, s)
        activity_position, = unpack ('> H', data [0x147: 0x149])
        activity_index = (activity_position / 0x40) - 32
        print "nLast activity #t {}". format (activity_number)
        print "Positiont {: # x} ({ }) ". format (activity_position, activity_index)
        print" Date: tt "+ activity_date.isoformat ()
        print" Counter: t {} ". format (activity_count)
     
        # last activities positions
        positions = [0xC0, 0xD0, 0xE0, 0x100, 0x110, 0x120]
        print "n {: ^ 20} {: ^ 5} {: ^ 20} {: ^ 12}". Format ("Date", "unk", "Terminal", "Operation")
        print "{ :> 31} {:> 5} {:> 4} {:> 10} {:> 7} ". Format (" ID "," Type "," Cnt "," Type ","Cnt")
     
        # get correct order
        i = 5 if activity_index> 5 else activity_index
        positions_ordered = positions [(i + 1):] + positions [:( i + 1)]
        for pos in positions_ordered:
            block = data [pos: pos + 0x10]
            # if undefined or empty block
            if (get_crc (block) <> 0) or (ord (block [0]) == 0):
                continue
            date_i, unk = unpack ('> LH', block [1: 7])
            term_id, term_type, term_cnt = unpack ('> BBH', block [ 7:11])
            op_type, op_cnt_i = unpack ('> HH', block [11:15])
            op_cnt = op_cnt_i / 0x40
            h = get_bits (date_i, 2, 5)
            m = get_bits (date_i, 7, 6)
            s = get_bits (date_i, 13, 5) * 2
            y = 2000 + get_bits (date_i, 18, 5)
            M = get_bits (date_i, 23, 4)
            d = get_bits (date_i, 27, 5)
            date = datetime (y, M, d, h, m, s)
            print "{} {:> # 5x} {:> # 7x} {:> # 5x} {: > # 7x} {:> # 9x} {:> 4}
            ".format (date.isoformat (), unk, term_id, term_type, term_cnt, op_type, op_cnt)
     
    def main (filename):
        with open (filename," rb ") as f:
            data = f.read (1024)
            print_info (data)
     
    if __name__ ==" __main__ ":
        main (sys.argv [1])

    An example of the program:



    How can i use


    The record of the last 6 trips can be used to view the movements. Even if the station is not visible, the exact date and time of the trip can be seen.

    On the other hand, you can collect metro statistics. Since each turnstile records its transaction number on the card, you can see how many people passed through the turnstile. For example, on the dump above it is visible that approximately 1000 people passed through the turnstile at the Polytechnic Institute (Terminal number 0x14) per day.

    Also popular now: