Reverse engineering detail of an RFID/NFC vending machine (2023)

Security expert Pasquale Fiorillo demonstrates how to hack an RFID/NFC vending machine.

The affected vendor did not respond to my request for responsible disclosure, so I'm here to disclose this "hack" without revealing the name of the vendor.

The target machine uses an insecure NFC card,MIFARE-Classic 1k, which is affected by several security vulnerabilitiesnot to be used in critical applications.
In addition, the user's balance was stored on the card, which allowed for different attack scenarios, from double spending to possible data manipulation by storing any balance.

Reverse engineering detail of an RFID/NFC vending machine (1)

Helpful hints from the MIFARE Classic 1K datasheet:

EEPROM: 1 kB is organized into 16 sectors of 4 blocks. A block contains 16 bytes.
The last block of each sector is called a “trailer” which contains two secret keys and programmable access conditions for each block of that sector.

  • Office:This is the first data block (block 0) of the first sector (sector 0). Contains data from the manufacturer of the integrated circuit. This block is read-only.
  • Data Blocks:All sectors contain 3 blocks of 16 bytes for data storage (sector 0 contains only two data blocks and the read-only manufacturer block).
    Data blocks can be configured by access condition bits as follows:
    • Read/Write Blocks: absolutely any data in any format
    • Value Blocks:fixed data format that allows native error detection and correction and backup management.
      A value block can only be created via a write operation in value block format:
      • Value: denotes a 4-byte signed value. The least significant byte of a value is stored in the least significant address byte. Negative values ​​are stored in standard 2's complement format. For data integrity and security, a value is stored three times, twice without inversion and once inverted.
      • Adr: represents a 1-byte address that can be used to store the memory address of a block when implementing powerful backup management. The address byte is stored four times, inverted twice and not inverted.
Reverse engineering detail of an RFID/NFC vending machine (2)

Let's start with the hack:

In this post, I didn't show how to crack the MIFARE Classic keys needed to read/write the card because someone already revealed this some time ago, so Google is your friend.
Finally, use this post to familiarize yourself with the fascinating world of reverse engineering, not to steal things.

To start the analysis I need a dump to compare.
The requirements for this task arenfc-mfclássicotool includedlibnfc, an NFC hardware interface likeACR122U, and a binary diff tool (aka binarydiff) likeIn between.


  • Dump 0:blank card(Not included in the screenshot below as all data bytes were 0x00 except sector 0 which contains UID and vendor information. This sector is read-only so these bytes are the same for all dumps.)
  • Dump 1:Map loaded with single0,10€Currency (Note that the machine displays the balance with 3 decimal places, €0.100)
  • Dump 2:0,00€after spending the entire balance with 4 transactions of €0.025 each
  • Dump 3:0,10€loaded with a single coin
Reverse engineering detail of an RFID/NFC vending machine (3)
Reverse engineering detail of an RFID/NFC vending machine (4)

The fuzzy bytes are keys A and B of MIFARE, except for the 32 bytes with offset 0xE0, whose purpose I don't know.
The 4 bytes between the keys are the access condition and indicate which key must be used for the reading and writing process (key A or B) and the type of block ("read/write block" or "value block" ).

The tooltemerIt is useful for quickly decoding access condition bytes and in general for displaying MIFARE Classic data broken down by sectors and blocks:

Reverse engineering detail of an RFID/NFC vending machine (5)

Initial analysis:

Note: From now on I will refer to offsets with a [bracket] and a value without brackets.

  • Blocks 8, 9, 10, 12 and 13 can also be used as a "value block".
  • Other than the bytes between the [0x80] and [0x9F] offsets, only a few bytes differ between the dumps.
  • Some data is redundant, for example [0x60...0x63] has the same values ​​as [0xA0...0xA3]
  • The values ​​in [0xC0], [0xD0], [0xC8], [0xD8] differ by 4 between the first and second dump (example: 0xFE – 0xFA = 0x4) and differ by 1 between the second and third dump (for Example: 0xFA – 0xF9) = 0x1)
  • The values ​​in [0xC4], [0xD4] differ by 4 between the first and second dump (for example 0x05 – 0x01 = 0x4) and differ by 1 between the second and third dump (for example: 0x06 – 0x05 = 0x1 )
    • 4 is the number of transactions issued the first time and 1 is the number of recharge transactions the second time
  • The sum between the offsets of the yellow square and the red square has a value of 0xFF. In other words, the red square is the inverse (XOR with 0xFF) of the yellow square. For example:
    • 0xFE ⊕ 0xFF = 0x01
    • 0xFF ⊕ 0xFF = 0x00
    • 0x7F ⊕ 0xFF = 0x80
  • The values ​​in [0x60...0x63] are a UNIX TIMESTAMP in little endian notation:
    • Dump 1: 0x4F9E2C27 -> 0x272C9E4F = 657235535 = 29.10.1990 um 21:25
    • Dump 2: 0x71B62C27 -> 0x272CB671 = 657241713 = 29.10.1990 um 23:08
    • Link 3: 0x18592D27 -> 0x272D5918 = 657283352 = 10/30/1990 at 10:42 am. m.
      • Okay, it's not the 90s, but the time difference between transactions is correct, maybe the machine doesn't have UPS 🙂

First discoveries:

  • The last transaction timestamp was stored as a 32-bit integer in MIFARE block 6 and was redundant in MIFARE block 10
  • Only MIFARE blocks 12 and 13 are in "Value Block" format and are used to store the remaining transaction counter in 32-bit format.
    This counter starts at 0x7FFFFFFF (2,147,483,647) and is decremented with each transaction
  • Blocks 1, 4 and 14 contain some data that will be corrected between dumps
  • Blocks 8 and 9 change completely with each transaction

The credit:

If there is any credit stored on the card, it has been encoded in blocks 8 and 9 and the number of bytes involved between a small difference in credit (for example between €0.00 and €0.10) may indicate that there is a certain value credit is involved.

At that point, a double-spending attack can confirm that the funds are actually stored on the card.
So after I used up all the credit I wrote a previous dump on the card and went to the machine to try it out. The card was fully functional with the previous balance stored in this dump. Now I'm pretty sure the credit is encrypted (and probably encrypted) in blocks 8 and 9.


Although the credit encoding format is still unknown, a double-spending attack was possible.

This eliminates the seller's attempt to disguise the credit 🙁

Adding a single token on the card, which is invalidated after each transaction on the backend, means that this token has to be shared by all the seller's vending machines, but if we add an internet connection to the vending machine, there is no need for the balance to be saved anymore. in the map.

Therefore, the only sensible remedy is:DO NOT SAVE BALANCE ON THE CARD!And in general: DO NOT TRUST THE CUSTOMER!

Path to Arbitrary Credit:

Spending €1 non-stop is not the scope of this trick. The only real scope is FUN!
To proceed with this analysis, I need to collect a large number of dumpsters to anticipate a hypothesis. So when I have other material I will make another post.

A simpler map example:

Some providers take a simpler approach, using MIFARE "Block of Value" to store funds without obfuscation or encryption.

Reverse engineering detail of an RFID/NFC vending machine (6)

The screenshot above, taken with "MIFARE Classic Tool" on an Android smartphone, represents a block of values ​​used to store credit:

0x00000CE4 = 3300 is the value in thousandths of euros (€3.30).

This particular provider doesn't use key A and key B is a default key 0xFFFFFFFFFFFFFFFF, so the attacker doesn't need to break anything.

Reverse engineering and cracking a vending machine is always fun.

The original post was published here.

About or author: Pasquale Fiorillo

I am a security auditor forIS groupand an independent security researcher. As a security auditor, my job is to conduct security activities such as:penetration testjvulnerability analysisin networks and web applications to identify security issues that could be exploited by an attacker to perform malicious actions on your resources.

As a teenager, I started an underground e-zine on IRC called Italian Hard Phreaking with some friends and wrote many articles about hacking and reverse engineering in the telecommunications world. Later, I started a new adventure as a security researcher, discovering vulnerabilities in commonly used software, web applications and websites in collaboration with other important people.USH

Pierluigi Paganini

(safety problems Chop)

Chopnews about hackersNFCPierluigi PaganiniRFIDsafety problemssecurity newsvending machine


Top Articles
Latest Posts
Article information

Author: Moshe Kshlerin

Last Updated: 11/18/2023

Views: 6015

Rating: 4.7 / 5 (57 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Moshe Kshlerin

Birthday: 1994-01-25

Address: Suite 609 315 Lupita Unions, Ronnieburgh, MI 62697

Phone: +2424755286529

Job: District Education Designer

Hobby: Yoga, Gunsmithing, Singing, 3D printing, Nordic skating, Soapmaking, Juggling

Introduction: My name is Moshe Kshlerin, I am a gleaming, attractive, outstanding, pleasant, delightful, outstanding, famous person who loves writing and wants to share my knowledge and understanding with you.