SYS: FANTASI WIKI PAGE: RFID_
← HOME

RFID

rfid launches an on-device RFID application and opens an interactive rfid> sub-prompt for reading, writing, sniffing, and emulating LF and HF tags. The same commands and dump-file formats are used on every device that has an RFID frontend (the Proxmark3, the Flipper Zero and Kiisu, and the Chameleon Ultra), so a card read on one device can be written or emulated from another.

Devices and frontends

Each platform implements its own driver in platforms/*/rfid.c. The drivers meet at the HAL in hal/hal_rfid.h, where HF is a framed transceive and LF is a raw acquire plus modulate. The protocol layer above the HAL - anticollision, EM4100 decode, CRC, Crypto1 - lives in the RFID app and is shared across platforms. Each platform reports which operations it supports through capability bits, and the CLI adapts at runtime.

DeviceRFID frontend
Proxmark3Xilinx Spartan-II XC2S30 FPGA driven by the AT91SAM7S512
Flipper Zero / KiisuST25R3916 in transparent mode
Chameleon UltranRF52840 NFCT + MFRC522

Each frontend covers both LF and HF. On the Proxmark3, the FPGA bitstreams are stored compressed under /fpga; they are streamed from the host the first time a band is used.

Running the app

rfid is a command in the Fantasi host CLI. It requires the protobuf transport, so start the client with --usb or --ble. Over plain --serial it reports:

fantasi> rfid
rfid: needs the protobuf transport - start the CLI with --usb or --ble

With a protobuf transport, rfid launches the on-device app and opens the rfid> sub-prompt, which has its own command history and TAB completion. Use exit to leave the app and return to the main CLI.

fantasi> rfid
rfid> read mfc
rfid> read t5577
rfid> exit

To run a single RFID command without entering the sub-prompt, pass it to the host CLI's -c flag. This launches the app, runs the one command, and exits:

fantasi --usb -c "rfid read mfc"
fantasi --usb -c "rfid emulate lf-t55xx-1A2B3C4D-dump.json"

Only one app runs on the device at a time. If a previous rfid session did not exit cleanly, later commands report rfid: an app is already running; run kill from the main CLI to stop it.

Commands

help lists the available verbs:

rfid> help
commands:
  search [protocol]                                        scan for tags (bare = every band)
  sniff <protocol>                                         passively watch a reader<->card exchange
  raw <protocol> [-c][-k][-s] <hex>                        send a raw frame to a protocol
  write <protocol> -b <block> -d <hex>                     write a block to a tag
  read <protocol> [-b <block>]                             read a block, or all blocks, from a tag
  collect <protocol> <card|reader|sniff> [-u UID][-k key]  gather key material (nonces, sniffed keys)
  emulate <dump.json>                                      emulate a card from a saved dump (MIFARE Classic)
  list [band|sub]                                          list supported protocols (band > sub-cat > protocol)
  trace [clear]                                            show (or clear) the accumulated raw trace
  field on|off|status                                      turn the reader carrier on/off, or report it
  help                                                     show this help
  exit                                                     leave the rfid app

read, write, list, collect, and emulate are handled on the host; search, sniff, raw, trace, and field dispatch to the device.

list

list prints the supported protocols as a band > tech > protocol tree, with the operations available for each protocol. Pass a band or sub-category name to filter (for example list lf). The three bands are LF, HF, and UHF.

rfid> list
LF
  125-500 kHz
    lf     generic                  read               available
    t5577  T5577                    read raw write     available
HF · 13.56 MHz
  NFC A · ISO14443-A
    nfca   generic                  read sniff raw     available
    mfc    MIFARE Classic           read sniff raw     available
    mfp    MIFARE Plus              sniff raw          available
    ul     Ultralight               read sniff raw     available
    ulc    Ultralight C             read sniff raw     available
    ulaes  Ultralight AES           sniff raw          available
    mfdes  DESFire                  sniff raw          available
  NFC B · ISO14443-B
    (none yet)
  NFC F · FeliCa
    (none yet)
  NFC V · ISO15693
    (none yet)
UHF
  860-960 MHz
    (none yet)

search [protocol] scans for a tag in the field and reports what it finds. With no argument it scans every band; pass a protocol to limit the scan.

read

read <protocol> [-b <block>] reads a tag. A bare read <protocol> reads all blocks; -b <n> reads a single block.

  • read t5577 reads an LF T5577 in full. It decodes the config block first to determine how many data blocks the tag holds, then reads them and prints an all-block dump.
  • read mfc reads a MIFARE Classic card end to end: it collects nonces, recovers the sector keys against a dictionary, then authenticates and dumps every block. The bundled key dictionary is in resources/nfc/mfc_dict.dic.

Add -s to save the result as a dump file (see Dump files).

write

write <protocol> -b <block> -d <hex> writes one block. For example, to write block 4 of a T5577:

rfid> write t5577 -b 4 -d 1A2B3C4D

raw

raw <protocol> [-c][-k][-s] <hex> sends a raw frame and prints the response - the way to reach a protocol that has no dedicated read/write support (see the raw column in list).

FlagEffect
-cAppend the protocol CRC to the frame
-kKeep the field on after the frame (for a multi-step exchange)
-sSelect the card before sending the frame

field

field on|off|status drives the reader carrier directly: turn the field on or off, or report its current state.

trace

trace prints the accumulated raw frame trace from the current session; trace clear empties it.

Sniffing

sniff <protocol> passively watches a live reader-to-card exchange with the device's own field off. Traffic prints as it happens; press any key or ^C (Control-C) to stop.

rfid> sniff mfc

The host annotates each captured frame against the protocol you named, labelling commands inline - for example SELECT, ANTICOLL, READ blk 4, AUTH-A blk 7, WRITE page 6. Frames with bad CRCs or parity errors are flagged in place. For MIFARE Classic, mfkey64 runs against the trace as it is captured, so a captured authentication yields the sector key without a separate cracking step.

Where the frontend can measure field strength, a capture opens with a coupling reading that grades the sniff quality as strong, fair, or weak (shown green, yellow, or red). On the Flipper this reading comes from the ST25R3916's External Field Detector and also drives an adaptive first-stage gain, which keeps a reader in range as its distance changes. A device that cannot measure field strength reports the coupling as unknown.

Emulation

emulate <dump.json> plays a saved card back to a reader. The supported card type is MIFARE Classic 1K, which is load-modulated through a full reader authentication and block reads. Emulation runs until you press a key or ^C.

rfid> emulate hf-mf-A1B2C3D4-dump.json

The dump is a JSON card image such as those written by read -s. Frame delay time (FDT) is close to that of a physical card, which is generally required for readers that reject slower emulators. For background on the timing, see the Chameleon Ultra technical whitepaper.

collect

collect <protocol> <card|reader|sniff> [-u UID][-k key] gathers key material - nonces from a card or reader, or keys recovered from a sniffed exchange - and writes it to a log the host can consume (for example when recovering MIFARE Classic keys).

Dump files

read -s writes a dump file when it reads a card. The format is close to the Proxmark3's own dump format, so files interchange for common card types. Emulation and re-writing read these dumps back.

How the app is structured

The RFID app itself contains little protocol code. Each feature - the HF reader, the LF reader, the sniffer, raw transceive, T5577 read/write, and the MIFARE Classic collect, read, and emulate stages - is a separate ELF module. When a command needs one, the module is fetched from the host over the protobuf link, run, and then deleted, so only one module is resident at a time. This keeps the subsystem within the flash and heap limits of the smallest target, the Proxmark3.

★ DREAM // HACK ★