Emulating NFC tags with the Proxmark
This post's intended audience is those who are familiar with low-level data structures, the basics of NFC and Mifare Classic technologies, and the basic usage of Proxmark hardware.
Proxmark devices are pieces of RFID test equipment commonly used in security research and penetration testing. Each model of device—of which there are several, including some third-party clones—contains antennas suitable for interacting with LF and HF RFID tags; an FPGA used to emulate, communicate, debug, and attack said tags; and an ARM processor used to communicate with a computer over USB, control the FPGA, and perform other functions. Proxmark devices are versatile tools for the RFID or electronic access control enthusiast, but are largely documented with the assumption that the user is abundantly familiar with the underlying RFID and access control technologies.
One feature of the Proxmark is that it can emulate Mifare Classic RFID tags, including the data memory of these tags. This, combined with the ability of Mifare Classic cards to store NFC data, means that one can emulate an NFC tag using a Proxmark.
How to do it
Download mifare-ndef-blank.json. Modify it to your liking by adding NDEF data to empty blocks, starting with block 4. Then, in the Proxmark client, type
1[usb] pm3 --> hf mf eclr
2[usb] pm3 --> hf mf eload --1k -f /path/to/mifare-ndef-blank.json
3[=] Upload 64 blocks 1024 bytes
4[+] loaded `/path/to/mifare-ndef-blank.json`
5[=] Uploading to emulator memory
6[=] ....
7[?] You are ready to simulate. See `hf mf sim -h`
8[=] Done!
9[usb] pm3 --> # Write more stuff to the tag using `hf mf esetblk`.
10[usb] pm3 --> # Remember that indices are 0-based and every 4th block is a special
11[usb] pm3 --> # special sector trailer
12[usb] pm3 --> #hf mf esetblk -b 4 -d 0337D1013355047475636b65722e7468
13[usb] pm3 --> #hf mf esetblk -b 5 -d 652d74776f6d6579732e636f6d2f626c
14[usb] pm3 --> #hf mf esetblk -b 6 -d 6f672f706f7374732f70726f786d6172
15[usb] pm3 --> #hf mf esetblk -b 8 -d 6b2d656d752d6e6663FE000000000000
16[usb] pm3 --> # and/or view the contents of memory
17[usb] pm3 --> #hf mf eview --1k
18[usb] pm3 --> hf mf sim -i
19[=] MIFARE 1K | UID n/a
20[=] Options [ numreads: 0, flags: 273 (0x111) ]
21[=] Press pm3 button or send another cmd to abort simulation
22[#] Enforcing Mifare 1K ATQA/SAK
23[#] 4B UID: e68487f3
24[#] ATQA : 00 04
25[#] SAK : 08
Then, interact with the emulated tag as desired.
Both reading and writing are supported.
Once emulation is stopped,
one can inspect and dump the emulator's memory using hf mf eview --1k
and
hf mf esave --1k -f /path/to/dump.json
to inspect how the tag data were
modified, and
one can run hf mf eload --1k -f /path/to/mifare-ndef-blank.json
again to reset
data on the emulated tag.
The mifare-ndef-blank.json file is an image of a 1K Mifare Classic card formatted to accept NFC data but with no data present. Data must be added to the emulated tag's memory using the TLV (type-length-value) and NDEF (NFC Data Exchange Format) formats. An Adafruit article provides a good overview of NDEF. I also have written a short primer on NDEF and TLV.
Eventually, I will write a Javascript widget that allows one to encode arbitrary data as NDEF and TLV blocks ready to be written to a Mifare Classic card (or the memory of an emulator), but that's out of the scope of this post.
How it works
The stock Proxmark software has an hf mf ndefformat
command that formats a
Mifare Classic card for NFC usage, but no equivalent that operates on the
emulator memory.
The mifare-ndef-blank.json file is the rough
equivalent of what running hf mf ndefformat
does to a card's memory.
To prepare a Mifare Classic card for NFC use, it needs to be formatted to store NDEF records and allow NFC readers to access the card's data blocks1. Doing that requires two things: Mifare Application Directory (MAD) entries must be made to mark all memory blocks as containing NDEF (NFC Data Exchange Format) data, and the keys and permission information of the MAD and NDEF blocks must be set properly.
Two NXP (the manufacturer of the Mifare Classic chip) application notes were helpful when I was setting this up. AN1305 details how to format the card for NFC usage, and AN10787 explains the MAD block.
Setting up the Mifare Application Directory
The Mifare Application Directory (MAD) describes what each sector of the card
memory is used for.
It is stored on sector 0, blocks 1-2 and starts with an info byte, then a CRC
checksum, and then has one sixteen-bit
application identifier for each sector.
(NDEF data are identified with an application identifier of 0x03 E1
.)
Bits 0-5 of the info byte point to a sector used to identify the publisher of
the card; bits 6-7 are unused.
In this application, the info byte is set to 0x00
and each application
identifier is set to 0x03 E1
.
The CRC is computed as shown below and is 0x73
.
Thus, the MAD sector's contents are as follows:
1-----+-----+-------------------------------------------------+-----------------
2 sec | blk | data | ascii
3-----+-----+-------------------------------------------------+-----------------
4 0 | 0 | E6 84 87 F3 16 88 04 00 46 8E 45 55 4D 70 41 04 | ........F.EUMpA.
5 | 1 | 73 00 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1 | s...............
6 | 2 | 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1 | ................
7 | 3 | A0 A1 A2 A3 A4 A5 FF 07 80 C1 FF FF FF FF FF FF | .........@......
The Sector Trailer (block 3) of Sector 0 contains first Key A (6 bytes),
the Access Bits (3 bytes), a General Purpose Byte (which identifies the contents
of the sector and is 0xC1
here), and Key B (6 bytes).
Key A of Sector 0 must be 0xA0 A1 A3 A3 A4 A5
when the MAD is in use,
and Sector 0's Access Bits (here 0xFF 07 80
) must be set to allow Key A to
read Sector 0.
The recommended Access Bits value is 0x78 77 88
, but the default of
0xFF 07 80 40
works for our purposes.
CRC computation
Byte 1 (0-based) of Block 1 contains a CRC of the MAD. It is computed by feeding
the bytes of the MAD, starting from the last byte of Block 2, to an 8-bit
CRC
function with polynomial $x^8+x^4+x^3+x^2+1$ and initial value of 0xE3
.
This can be computed using the Mifare Classic's onboard CRC function or using
the Proxmark's reveng
command.
For the latter case, use reveng -m CRC-8/MIFARE-MAD -c <bytes>
.
In either case, the info byte is fed in first, the CRC byte is skipped, and the
directory bytes are then fed in, starting with the LSB of the first sector byte.
If using the reveng
command on the Proxmark, this means that the bytes given
must be in reverse order to how they would appear in a hex dump.
Setting up the data blocks
Each sector marked for NDEF use in the MAD must have a Key A of
0xD3 F7 D3 F7 D3 F7
and
Access Bits that allow Key A to read Sector 0.
The recommended Access Bits value is 0x7F 07 88
, but the default of
0xFF 07 80 40
works for our purposes.
Sector 1 must start with 0x03 00 FE
, followed by 0x00
bytes.
Further sectors must also contain 0x00
.
Thus, the first two sectors will contain
1-----+-----+-------------------------------------------------+-----------------
2 sec | blk | data | ascii
3-----+-----+-------------------------------------------------+-----------------
4 1 | 4 | 03 00 FE 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
5 | 5 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
6 | 6 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
7 | 7 | D3 F7 D3 F7 D3 F7 FF 07 80 40 FF FF FF FF FF FF | .........@......
8 2 | 8 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
9 | 9 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
10 | 10 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
11 | 11 | D3 F7 D3 F7 D3 F7 FF 07 80 40 FF FF FF FF FF FF | .........@......
The Mifare Classic 1K memory is divided into 16 sectors, each with 4 16-byte blocks. The fourth block of each sector contains encryption keys and access information.