In the last post I got a Proxmark3 reading and writing Mifare Classic cards. But a successful dump is really just 1024 bytes of hex — and hex on its own tells you nothing. This time I take one card from that drawer that turned out to be genuinely interesting — a real public-transport ticket that also runs on a Fudan Mifare-compatible chip with a known hardware backdoor — and walk through how you actually read a dump: identify the chip, find the structure, decode the content, and tell from the card itself what you are allowed to touch.
Everything below was read from a card I own. The account number, certificate id and the secret write keys are replaced with placeholders; the public keys, structure and ASCII are shown as-is. In the terminal snippets, what I typed is bold and the tool’s output is italic.
Step 0: get the dump
Recovering the keys and dumping the card is covered in the previous post — in short, hf mf autopwn cracks the keys and writes a dump file. hf mf dump (or hf mf view -f <file> on a saved dump) prints the layout below: sector, block, 16 bytes of hex, and an ASCII column. Read the ASCII column first — it hands you URLs, type names and structure for free.
Step 1: identify the chip (a plot twist)
Before decoding anything, ask what you are holding. hf mf info fingerprints the chip — and this one is a surprise:
[usb] pm3 --> hf mf info
[+] UID: AC 0A C1 DC
[+] SAK: 08 [2]
[+] Sector 0 key A... A0A1A2A3A4A5
[+] Sector 1 key A... D3F7D3F7D3F7
[+] Backdoor key..... A396EFA4E24F
[=] --- Fingerprint
[+] Fudan FM11RF08S 0490
[=] --- Magic Tag Information
[=] <n/a>
[=] --- PRNG Information
[+] Prng....... weak
[+] Static enc nonce... yes
So this is not a genuine NXP card at all — it is a Fudan FM11RF08S, a non-NXP, Mifare Classic 1K-compatible chip (a third-party compatible IC, not a counterfeit or “magic” card) (hf 14a info confirms MIFARE Classic 1K). Two lines matter enormously:
- Backdoor key
A396EFA4E24F— in 2024, security researchers (Quarkslab) revealed that these Fudan chips ship with a hardware backdoor key that authenticates to any sector. It is the same on every FM11RF08S. In other words: you don’t even have to crack the keys — the chip hands them to you. - Static encrypted nonce = yes — the FM11RF08S tries to resist the classic nested attack by using static nonces. The Proxmark has a dedicated attack for it (
hf mf sen), and the backdoor key makes recovery trivial regardless.
Already a theme is forming that the rest of the card confirms: key secrecy is not what protects this card. Hold that thought.
Step 2: the map — the MIFARE Application Directory (MAD)
How does a reader know where an application lives on the card? Mifare Classic answers with the MAD, in sector 0. Two tells identify it: Key A is the public MAD key A0A1A2A3A4A5, and the trailer’s GPB byte is C1 (MAD v1 present).
sec | blk | data | ascii
----+-----+-------------------------------------------------+---------
0 | 0 | AC 0A C1 DC BB 08 04 00 04 FD 34 49 DA 7C C2 90 | .. <- UID + BCC/SAK + maker data
| 1 | B0 00 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1 00 00 | .. <- MAD: CRC, info, AIDs
| 2 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | .. <- MAD: AIDs for sectors 8-15 (none)
| 3 | A0 A1 A2 A3 A4 A5 0F 07 8F C1 xx xx xx xx xx xx | .. <- trailer: KeyA=MAD key, GPB=C1
Block 1 is the directory: a CRC (B0), an info byte (00), then 2-byte Application IDs, one per sector. The bytes 03 E1 are stored little-endian, so the AID is 0xE103. Rather than decode that by hand, let the Proxmark parse it:
[usb] pm3 --> hf mf mad
[=] ------------ MAD v1 details -------------
[=] 00 MAD v1
[=] 01 [E103] NFC applications [NXP Semiconductors]
[=] 02 [E103] continuation
[=] 03 [E103] continuation
[=] 04 [E103] continuation
[=] 05 [E103] continuation
[=] 06 [E103] continuation
[=] 07 [0000] free
[=] ...
[=] 15 [0000] free
Now the card has told us its own layout: sectors 1–6 hold the E103 “NFC applications” data (the ticket), and sectors 7–15 are free. That is the essence of reading a dump: find the structure first, so you know which bytes are worth decoding.
Step 3: the payload — an NDEF message
Sectors 1–6 share Key A D3F7D3F7D3F7 — the well-known public NFC/transport read key — and hold an NDEF message, the standard NFC data container. You can spot it by its framing: it begins with 03 (the “NDEF message” TLV tag) and ends with FE (the terminator). Read the ASCII and the meaning appears:
1 | 4 | 03 FF 01 01 94 11 38 70 69 6C 65 74 2E 65 65 3A | ......8pilet.ee:
| 5 | 65 6B 61 61 72 74 3A 32 66 19 5F 26 06 32 34 30 | ekaart:2f._&.240
| 6 | 32 32 39 59 04 20 20 20 20 5F 28 03 32 33 33 5F | 229Y. _(.233_
2 | 8 | 27 01 31 6E 1B 5A 13 31 32 33 34 35 36 37 38 39 | '.1n.Z.123456789 (serial redacted)
| 9 | 30 31 32 33 34 35 36 37 38 39 53 04 AC 0A C1 DC | 0123456789S..... (redacted; note UID!)
| 10 | 41 03 00 00 00 AC 53 69 67 01 02 00 80 5D 42 54 | A.....Sig....]BT <- "Sig" = signature
The 03 FF 01 01 header reads “NDEF message, length 257 bytes,” followed by an NFC Forum External Type record — but you don’t have to parse the TLV by hand. hf mf ndefread decodes the whole thing:
[usb] pm3 --> hf mf ndefread
[+] Found NDEF message ( 257 bytes )
[+] Record 1
[=] External Record
[=] URN... urn:nfc:ext:pilet.ee:ekaart:2
[+] Ekaart detected - Trying ASN1 decode...
[=] -- 66 [19]
[=] -- 5F26 [06] 240229
[=] -- 59 [04] (four spaces)
[=] -- 5F28 [03] 233
[=] -- 5F27 [01] 1
[=] -- 6E [1B]
[=] -- 5A [13] 1234567890123456789 (serial redacted)
[=] -- 53 [04] AC 0A C1 DC (the card UID, again)
So Record 1 is an NFC Forum External Type named urn:nfc:ext:pilet.ee:ekaart:2, whose payload is ASN.1-encoded: a few small fields, the card serial (redacted), and — there it is again — the card’s own UID copied into the data. Remember that; it is the whole trick.
Step 4: the parts you can’t read — the signature
Some sectors look like noise — and that itself is information. High-entropy blocks with no ASCII structure are almost always cryptographic data. Here, ndefread identifies exactly what it is — Record 2 of the message:
[+] Record 2
[=] Signature
[+] Version... 0x01
[+] Type...... RSASSA_PKCS1_v1_5_WITH_SHA_1 (1024)
[+] Data [128]... (128-byte RSA-1024 signature)
[=] 5D425425D09E135CBC156A56A303FBB37FAFC2D3074506D4DD1849406F3A642A
[=] ... (truncated)
[=] Certificate
[+] Format............ X_509
[+] Certificate URI... http://pilet.ee/crt/<id>.crt
So Record 2 is a 1024-bit RSA signature (RSASSA-PKCS1-v1.5 with SHA-1) over the ticket data, plus a reference to an X.509 certificate at http://pilet.ee/crt/<id>.crt. In the raw dump, that is the random-looking blocks and the plain URL:
3 | 12 | 25 D0 9E 13 5C BC 15 6A 56 A3 03 FB B3 7F AF C2 | %...\..jV....... <- signature (random-looking)
| 13 | D3 07 45 06 D4 DD 18 49 40 6F 3A 64 2A 9A 1D 56 | ..E....I@o:d*..V
5 | 22 | 68 74 74 70 3A 2F 2F 70 69 6C 65 74 2E 65 65 2F | http://pilet.ee/ <- certificate URL
6 | 24 | 63 72 74 2F 31 32 33 34 35 36 37 38 2D 30 30 30 | crt/12345678-000 (id redacted)
| 25 | 31 2E 63 72 74 FE 00 00 00 00 00 00 00 00 00 00 | 1.crt. <- FE = NDEF terminator
Step 5: the empty space
Sectors 7–15 are unused: all-zero data and factory-default trailers. Learn to recognise “default” at a glance — Key A and Key B both FFFFFFFFFFFF, access bits FF 07 80, GPB 69 — it means “blank, wide-open sector.”
8 | 32 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................
| 35 | FF FF FF FF FF FF FF 07 80 69 FF FF FF FF FF FF | .........i...... <- default trailer
Step 6: the access bits — what can I actually touch?
This is the part people skip, and it is the most useful. The three bytes before the GPB in every trailer (0F 07 8F or FF 07 80 here) are the access bits. They encode, per block, which key may read, write, increment, etc. — and the chip enforces them, so holding the key is not enough. hf mf acl decodes the bytes for you; here is what the two values on this card mean:
| Sectors | Access bits | Data-block condition | Read? | Write data? |
|---|---|---|---|---|
| 0 (MAD) | 0F 07 8F | 010 | ✅ Key A/B | ❌ never |
| 1–6 (ticket) | 0F 07 8F | 010 | ✅ Key A/B | ❌ never |
| 7–15 (empty) | FF 07 80 | 000 | ✅ | ✅ Key A/B |
Condition 010 on a data block means “read with Key A or B, write never” — the ticket data is permanently read-only, with any key. Condition 000 (default) means read and write with either key. So on this card:
- Read: every sector — trivially, since the backdoor key alone already unlocks all of them.
- Write: only the empty sectors 7–15. The ticket data (0–6) refuses writes at the hardware level; a
wrblthere fails even with the correct key — that is the access bits, not a key problem. The backdoor does not change this — it defeats key secrecy, not the access-bit write protection. - Block 0 / UID is read-only (this is not a “magic” card).
Why this design still holds — even with a backdoor
Put the pieces together and something neat emerges. On this card the keys are public, crackable, and backdoored — confidentiality of the data is essentially zero, and it was never meant to be otherwise (the read keys are public by design). Yet you still cannot forge a ticket, because integrity rests on two things the backdoor doesn’t touch:
- The access bits make the data blocks write-never — you can read and copy, but not edit in place, even via the backdoor.
- The signature is bound to the UID (the UID is inside the signed ASN.1 payload). Copy the data to another card and the UID no longer matches, so the RSA signature no longer verifies; and block 0 can’t be rewritten on a normal card anyway.
So you can freely read and copy this card but cannot usefully forge it: a clone onto an ordinary blank has the wrong UID, and even a clone onto a magic card with a matching UID still fails an online check. Broken cipher, public keys, a literal hardware backdoor — and a security model that still works, because it never relied on the keys in the first place.
Let the tools do the decoding
I decoded things by hand to show the method, but the Proxmark parses most of it for you:
hf mf info— fingerprints the chip (this is how we caught the Fudan FM11RF08S and its backdoor).hf mf mad— parses the MAD and names the application owning each sector.hf mf ndefread— decodes the NDEF message into records (type, ASN.1 fields, signature, certificate).hf mf acl— decodes the access-rights bytes so you don’t have to do the bit math;hf mf view -f <dump>re-displays a saved dump.
Knowing how to do it by hand, though, is what lets you read a card the tools don’t recognise — which is most of the interesting ones.
Takeaways
- Identify the chip first (
hf mf info) — “Mifare Classic” may be a Fudan clone with a backdoor. - Read the ASCII column — it reveals URLs, type names and structure for free.
- Find the map before the data: the MAD (Key A
A0A1A2A3A4A5, GPBC1) says which sectors matter. - Known framing is a gift: NDEF starts with
03and ends withFE; default trailers areFF…FF / FF0780. - High entropy = crypto, not readable data — here, an RSA-1024 signature.
- Access bits, not keys, decide writes — and the chip enforces them, backdoor or not.
Next time: what happens when I try to clone one of these onto a magic card — and how the UID binding bites back.
