Remember Umeå’s SMS bus tickets? Well, we didn’t really go all out on that one, considering it is reasonably an online system. Which means we can’t modify the central database and only imitate a legitimate ticket. However, of course, that’s good enough as long as the ticket inspectors don’t actually check the tickets against the central database. But with risk of becoming stale, we’re moving on to the real tickets. Pre-purchased cards containing any given amount of trips (that people can reasonably afford).
Länstrafiken i Västerbotten (though the buses are driven by Nobina) use RFID cards operating at 13.56MHz following the Mifare Classic standard. This is a fairly easy system to use, giving you contact-less tickets operating at a slightly more rapid verification speed than the old magnetic cards that were in use before.
Mifare Classic is also used in several other scenarios, be it other sorts of ticket systems or even security-related such as access control to buildings or computer systems. Thus, knowing how Mifare works is a good start if you want to crack it. Fortunately (so one doesn’t have to get in over one’s head) lots of people have been doing lost of fine work over the last decade. The tools needed to complete a full secret-key recovery of just about any Mifare classic card are all available as open source hardware and software. Thanks to a friend of mine, I now have access to a reader that allows for toying around with the security issues on Mifare cards.
A lot of the RFID technology has been, by me too, perhaps incorrectly bashed upon to be unsafe. Me and others have concluded that “just by walking into a room” you can know who are present through reading their RFID data. This is not true in the sense of immediate access to this knowledge. However, aggregating enough data may definitely resolve information needed to this at a restricted level. Regardless, the fact remains that RFID is contact-less, meaning it WILL transmit data available for interception – without being removed from your pocket – to the general public. It’s not as easy as 1-2-3. Maybe 5 though.
For my part I’m first going to read up on the actual standard, the available security research and whatever else may be necessary to know. In parallell I have started applying the available tools for dumping keys on RFID cards in my personal possession. For example, the crapto1 project (from Mifare Classic’s encryption scheme CRYPTO1) lists these sources as security research reports, it’s as good a start as any:
- Dismantling MIFARE Classic – recover keys with a valid reader [2008-esorics.pdf]
- Wirelessly Pickpocketing a Mifare Classic Card – escalating from 1 key to any without a valid reader [Pickpocketing.Mifare.pdf]
- The Dark Side of Security by Obscurity and Cloning MiFare Classic Rail and Building Passes Anywhere, Anytime – support for the ‘common prefix’ attack. Retrieves a key without a valid reader. Requires more communication than the previous attack and accurate timing [137.pdf]
Also, the documentation provided by the libnfc project is very good and carries the ISO 14443, Mifare dump specifications etcetera. The project which binds crapto1, libnfc etc. together is mfcuk, which I use to maneuver a simple 30€ reader (ACS122 compatible, device ID 072f:2200). Because of WordPress’ disliking of certain file-endings, I’ll tar-gzip just this once and present to you 58127350-initial_payload.tar.gz – straight from nfc-mfclassic
. Remember to take into account big/little endian decoding issues. I’m not dead-certain which order is which in the software versus Mifare specifications etc.
In either case, this is what hexdump
tells me (cutting off the ASCII part):
00000000 67 62 ce fb 30 88 04 00 43 29 9c 43 00 19 08 09 00000010 34 01 14 07 14 07 14 07 14 07 14 07 14 07 14 07 00000020 14 07 14 07 14 07 00 00 00 00 00 00 00 00 00 00 00000030 a0 a1 a2 a3 a4 a5 78 77 88 c1 83 69 85 fa a9 3e 00000040 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000050 00 01 40 16 09 b0 03 76 f3 f6 06 59 08 8e 00 10 * 00000070 71 4a 90 80 b0 9b 78 77 88 00 e0 a8 67 68 31 6f 00000080 13 88 13 88 70 73 dd 70 74 19 00 10 8d 13 88 00 00000090 13 88 13 88 70 74 58 70 74 94 00 90 40 13 88 00 000000a0 1e 20 00 02 02 00 00 00 00 00 00 00 00 00 00 00 000000b0 5b 53 fb 10 d0 0c 78 77 88 00 92 c1 2e fb 21 24 000000c0 1e 1e 00 02 02 00 00 00 00 00 00 00 00 00 00 00 000000d0 10 40 dc 18 aa 1c 18 aa 1c 1c f7 5c 18 9f 70 00 000000e0 10 40 1c 18 aa 1c 18 aa 1c 1c f7 5c 1d 16 30 00 000000f0 32 a9 09 15 8a 1c 78 77 88 00 70 b8 b0 f2 f5 5a 00000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 * 00000130 34 4d 0a 51 12 87 78 77 88 00 fe 8f 9e 57 6d e4 00000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - empty sectors - 000002f0 a0 a1 a2 a3 a4 a5 ff 07 80 69 b0 b1 b2 b3 b4 b5 00000300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - default keys - 0001000
0x30
, I’m not really sure what’s in Sector 0. A friend says it might be a Mifare Application Directory, MAD, sector. This seems reasonable. I’ll still have to read up on how those are specified.0x70
, Sector 1 is most likely relevant data. Note similarities between 0x80-0x8F and 0x90-0x9F0xB0
, Sector 2 is most likely also relevant data. Note similarities between 0xD0-0xDF and 0xE0-0xEF0x130
, from here there are only empty sectors (at least on this specific card)0x2F0
, from here default keys (0xA0A1A2A3A4A5/0xB0B1B2B3B4B5) are used and the sectors contain no data
I haven’t pondered yet at what the various hexes might decode to yet, but the similarities mentioned in sectors 1 and 2 will probably be of interest. Now we need diffs, timestamps, refills etc. This specific card is pretty unknown to me even at this point. But it’s a start and proof of concept.
And we’re out of coffee to brew at Umeå hackerspace. That sucks.
Update 2010-01-07 13.25: Having dumped another card, I verified that they used the very same keys on all sectors. The only difference on the key dump was the following (the first line, 0x0
, being the card’s UID). Below is the payload diff:
1c1 < 00000000 d5 d8 20 f3 de 88 04 00 43 25 b4 53 00 11 0a 05 --- > 00000000 67 62 ce fb 30 88 04 00 43 29 9c 43 00 19 08 09 5,6c5,6 < 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 < 00000050 00 01 40 16 09 b0 03 75 4c 6b 01 51 88 57 80 10 --- > 00000040 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 > 00000050 00 01 40 16 09 b0 03 76 f3 f6 06 59 08 8e 00 10 9,11c9,11 < 00000080 13 88 13 88 6b fc 01 6b fc 3d 00 10 28 13 88 00 < 00000090 13 88 13 88 6b df 2d 6b df 69 00 10 19 13 88 00 < 000000a0 12 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 --- > 00000080 13 88 13 88 70 73 dd 70 74 19 00 10 8d 13 88 00 > 00000090 13 88 13 88 70 74 58 70 74 94 00 90 40 13 88 00 > 000000a0 1e 20 00 02 02 00 00 00 00 00 00 00 00 00 00 00 13,15c13,15 < 000000c0 12 02 00 02 02 00 00 00 00 00 00 00 00 00 00 00 < 000000d0 10 40 9a f7 cb 5a ff 00 5a e4 2a 5a e6 0a 00 00 < 000000e0 10 40 5a f7 cb 5a df eb 9a e4 2a 5a e6 0a 00 00 --- > 000000c0 1e 1e 00 02 02 00 00 00 00 00 00 00 00 00 00 00 > 000000d0 10 40 dc 18 aa 1c 18 aa 1c 1c f7 5c 18 9f 70 00 > 000000e0 10 40 1c 18 aa 1c 18 aa 1c 1c f7 5c 1d 16 30 00
There is no plaintext in any sector. I’ll collect more data for later posts. Once the system is reverse-engineered, there’ll be a post describing the process of interpreting and what all differences are.