NFC relay attacks: using a contactless card that never leaves your pocket

Comic: a card read in a train bag is relayed across the city by a glowing line to an accomplice at a payment terminal

TL;DR

A contactless card and a reader only talk when they are a couple of centimetres apart. A relay attack breaks that assumption: it carries the card’s live conversation over distance, so the card can sit in a pocket on a train while, across town, a terminal is talking to it and opening a door or taking a payment. I built a relay into my Evil-M5Project, and I recently ported it to the Flipper Zero as Flipper-EvilRelay. The twist that makes it work against real terminals is that the Flipper answers with the real card’s own identity, not a phone’s, and chains full EMV responses (EMV is the chip-and-tap standard behind bank-card payments). I validated it end to end against a live payment terminal and a Proxmark3, on my own equipment. The card is never copied. The whole thing lives or dies on distance, which is also exactly where the defense lives.

Comic: a long coiled cord carries a card’s conversation across a wide gap from a phone to a distant payment terminal

What a relay actually is, and what it is not

Cloning gets all the attention, so let me draw the line first. Cloning makes a copy of a card that you can use later, on your own. A relay copies nothing. It is a long wire. One end sits against the real card and reads every question and answer, the other end sits against the reader and replays them live. The card stays exactly where it is, in its owner’s pocket, powered through the air by the attacker’s reader for the length of the transaction, and the moment it moves away the whole thing dies. Nothing is stored, nothing can be replayed tomorrow.

Comic: cloning a card (crossed out) versus relaying, where the real card stays in the wallet and only its live conversation travels

That is why the relay matters: it is the attack for the cards you cannot clone. The encrypted DESFire access badge, the EMV bank card, the phone wallet that hands out a fresh one-time token every tap. You do not break their cryptography, because you never have to. You just borrow the card, live, from a distance, and let it answer the reader’s questions itself.

How a contactless card talks to a reader

When I explain this to someone I start right here, because it is the single assumption the whole attack leans on. Hold a card near a reader and two things happen at once. The reader’s field powers the card (there is no battery in there), and the two start a fast back-and-forth conversation. The reader sends a command, the card answers, the reader sends the next command, and so on, often dozens of times in well under a second. Each of those messages is called an APDU, and the whole exchange is what decides whether a door opens or a payment goes through.

Comic: a contactless card and a reader held close exchange a fast back-and-forth of messages with a spark between them

The one thing holding this together is distance. The card and the reader assume that because they can hear each other at all, they must be right next to each other, a few centimetres apart at most. That assumption is the entire security model of « tap to pay » and « tap to enter ». Proximity is treated as proof of presence. A relay is simply a machine for making that assumption false.

The four links of the relay

My relay is a chain of four parts, and it helps to see them in order. At one end, a reader device (a phone running my app, or an Evil-Cardputer) sits against the real card and reads its APDUs. Those bytes travel over Wi-Fi or over ESP-NOW radio to a tiny ESP32-C3 board, which is nothing more than a byte pipe. The ESP32-C3 passes them down a short wire into a Flipper Zero. The Flipper is the piece held against the reader or payment terminal, and it answers as if it were the card.

Comic: the four-link relay chain, a card, a phone, a small board and a gadget at a terminal, joined by a glowing line

So the terminal’s question travels backward down the chain to the real card wherever it is, the card replies, and the answer travels forward to the Flipper, which hands it to the terminal. The terminal opens up, because from where it stands the card is right there against the glass. The reader side starts nothing of its own, it only forwards. All the hard work is on the Flipper, making it behave like a protocol-correct card.

Technical deep dive: ISO-DEP, the real ATS, and EMV chaining

This is the part worth slowing down on, because it is where a toy demo becomes something a real terminal accepts. Contactless smartcards speak a layered protocol. At the bottom is ISO 14443-3A (anticollision and the card’s basic identity), and on top of it sits ISO-DEP (ISO 14443-4), the half-duplex block layer that actually carries the APDUs. When a reader meets a card it runs a short handshake: anticollision gives it the UID and the SAK, then it sends RATS (Request for Answer To Select) and the card replies with its ATS (Answer To Select), a little block that announces the card’s capabilities, its timing, and its historical bytes. After that, application APDUs flow inside I-blocks, with acknowledgements and block numbers keeping the two sides in step.

Comic: a gadget presents the real card’s identity to a terminal, which is convinced

Now, the obvious question: a phone can already emulate a card with Android HCE (Host Card Emulation), so why drag a Flipper into it? Because HCE is limited on purpose. Android assigns its own random UID, and it never lets the emulation layer set the card’s real UID, ATS or SAK. A terminal that fingerprints the card by its ATS or SAK sees a phone’s generic identity, not the card’s, and rejects it. That is the wall most phone-to-phone relays (like NFCGate) hit.

Flipper-EvilRelay gets around it by refusing to use the SDK’s convenient layer-4 listener at all. That listener only ever sends one unchained block per response and offers no outbound chaining, so the first EMV READ RECORD that is bigger than the reader’s frame size makes it error out and the app crashes. Instead the FAP drops down to the raw ISO 14443-3A listener and runs the entire ISO-DEP state machine by hand: it answers RATS with a crafted ATS that carries the real card’s own historical bytes (so fingerprinting still sees the genuine card), reassembles the reader’s chained commands, and sends the card’s response back as several correctly chained I-blocks, waiting for each acknowledgement and toggling the block number exactly as a real card does. A 157-byte response against a 128-byte frame goes out as two clean chained blocks instead of a crash.

The last piece is time. A local card answers in microseconds, but my relay round trip (terminal to Flipper to wire to ESP32 to Wi-Fi to phone to card, and all the way back) takes far longer, and a reader only waits as long as the Frame Waiting Time the card promised in its ATS. So the FAP advertises a deliberately long FWT, about 4.9 seconds, by forcing one timing nibble in the ATS. Over the wire the three message types are almost comically simple: IDENT (the card’s identity, sent once at tap), REQ (a command from the terminal), and RESP (the card’s answer), strictly one in flight at a time. Simple protocol, fiddly protocol-correctness. That is the whole game.

Why a Flipper, and not just a phone

I want to be precise about what this buys and what it does not, because I am not going to oversell it. Presenting the real card’s ATS defeats identity fingerprinting, the check that asks « is this actually the card it claims to be? ». That is the thing a plain phone relay fails. It is a real step up, and it is why the Flipper, not a second phone, is the device touching the terminal.

Comic: a phone with a generic mask is rejected by a terminal, while a dedicated gadget presenting the real card identity is accepted

But it does nothing against timing. A terminal running EMV RRP (Relay Resistance Protocol) measures how long the card takes to answer and rejects anything too slow, and a relay is always too slow. RRP is the documented, deliberate defense against exactly this attack, and no amount of identity trickery gets past it. So the honest framing is this: Flipper-EvilRelay shows that identity checks alone are not enough, and that the thing you actually have to measure is distance, not identity. My app even keeps an HCE mode for phone-to-phone experiments, but the real-terminal path is phone-as-reader to Flipper-as-emulator.

View from a victim

Say you are on a packed evening train, card in the front pocket of the bag on your shoulder. Someone stands a little too close behind you, the way everyone does at rush hour, holding their phone near their own chest. For the few seconds their phone is next to your bag, it is reading your card, and that conversation is being carried to an accomplice standing at a shop counter on the other side of town, holding what looks like an ordinary gadget to the terminal. The payment goes through on your card while the card never leaves your bag. You feel nothing, and nothing on your phone lights up, because it was never your phone that was involved. This is why contactless limits and extra checks on bigger amounts exist, and it is a good argument for keeping cards somewhere they cannot be casually read.

Comic: on a crowded train a stranger holds a phone against a passenger’s bag, secretly reading the card inside

Why it works, and where it hits a wall

It works because the whole contactless world quietly agreed that « I can hear you » means « you are right here », and most readers never check whether that is actually true. Proximity stands in for presence, and a relay turns proximity into a lie. That is the root of it, and it is the same shape as a lot of attacks in this series: a system trusting a signal instead of verifying the thing the signal is supposed to prove.

Comic: a payment terminal times a slow relayed response with a stopwatch and slams a barrier down, defeating it on distance

The wall is real, though, and I want to name it clearly. A relay cannot beat a reader that measures distance. EMV RRP times the exchange tightly, down to the microsecond, and rejects the lag a relay always adds. On the payment side, low contactless limits and step-up authentication (a PIN or a phone unlock for larger amounts) cap what a silent relay can take. And the card must be physically present and powered the entire time, so this is a live, in-the-moment attack, never a stored one. Distance bounding is the actual fix. Everything else just raises the cost.

How to protect yourself

If you carry contactless cards

Comic: a card in a shielded wallet with a padlock blocks a reader’s waves, cutting the relay off
  • Keep cards you rarely tap in a shielded sleeve or wallet (the metal-lined kind). It blocks the reader field, so a card that cannot be powered cannot be relayed.
  • Prefer paying with a phone or watch wallet over tapping the bare card. Those require an unlock or a fingerprint per transaction, which a silent relay cannot provide.
  • Be aware of someone crowding unusually close to a bag or pocket in a queue or on transport, which is the one physical tell.
  • Keep contactless limits low where your bank lets you, and turn on transaction alerts so an odd tap shows up immediately.

If you run the readers or the system

  • Deploy distance bounding where it exists. EMV RRP (Relay Resistance Protocol) is the designed countermeasure and defeats the relay on timing regardless of what identity it presents.
  • Enforce low contactless ceilings and step-up authentication for anything above them, so a relay cannot quietly clear a large amount.
  • For access control, do not trust proximity alone for anything that matters. Pair the badge with a PIN or a second factor on sensitive doors, and watch for the latency and behaviour a relay introduces.

Doing it with Evil-M5Project and Flipper-EvilRelay

I first built this relay into Evil-M5Project, the firmware I maintain, where an Evil-Cardputer can play the reader side over ESP-NOW. Then I ported the whole thing to the Flipper Zero and released it as Flipper-EvilRelay, because the Flipper makes a far better emulator than a phone for the reasons above. It is three small parts: a Flipper FAP that emulates the card at the ISO-DEP layer, a roughly 3 USD ESP32-C3 that bridges the radio to the Flipper’s wire, and a reader (the Android app, or an Evil-Cardputer). The card is read by the phone or the Cardputer, the Flipper answers the terminal, and the ESP32 just shuttles bytes between them.

Comic flat-lay of the relay kit, a handheld gadget, a small board and a phone cabled together beside a payment terminal

The honest limits, which are the whole point:

  • The real card has to be physically present and powered at the reader side for every single transaction. Nothing is cloned or stored, and it stops the instant the card leaves the field.
  • It presents the real card’s identity, which beats fingerprinting, but it does nothing against a terminal that measures response time. EMV RRP rejects it on latency, by design.
  • It is a research and teaching tool for understanding a documented class of attack and reasoning about the countermeasures, not a shortcut around them.

Flipper-EvilRelay and Evil-M5Project are for ethical and educational use only. Relay only cards, readers and terminals you own or are explicitly authorized to test, with the cardholder’s consent. Relaying someone else’s card is fraud and is illegal in most places. See the project’s legal notes.

Flipper-EvilRelay: https://github.com/7h30th3r0n3/Flipper-EvilRelay. Evil-M5Project: https://github.com/7h30th3r0n3/Evil-M5Project. PoC demo (YouTube Short): https://youtube.com/shorts/lc6wKesM4Y0.

Close enough is not the same as here

What I like about the relay is that it is almost philosophical. It does not break any lock. It attacks a single quiet assumption, that being close enough to talk is the same as being present, and that assumption is baked into nearly everything we tap. The fix is not stronger crypto or a cleverer card. It is to stop trusting proximity and start measuring distance, which is exactly what RRP does and what more readers should. I built this, and ported it to the Flipper, so the lesson stops being abstract: once you have watched a terminal happily talk to a card that is sitting in another room, you never quite trust a tap the same way again.

Comic: scissors cut the long relay cord between a card and a terminal, severing it by distance

Publié

dans

par

Étiquettes :

Commentaires

Laisser un commentaire