Skip to content

WelbourneSecurity/RFIDemon

Repository files navigation

RFIDemon

RFIDemon is a Raspberry Pi based RFID analysis and cloning workstation for MIFARE Classic cards. The Raspberry Pi owns the RC522 reader, the REST API, the reader loop, and the AutoPwn cracking pipeline. A laptop runs the operator dashboard proxy and an HTTPS receiver for captured card snapshots.

The current supported network model is intentionally simple:

  • The Raspberry Pi and laptop must be on the same infrastructure Wi-Fi network.
  • The Pi serves the API on port 5000.
  • The laptop dashboard proxy serves the browser UI on http://localhost:5001.
  • The laptop receiver accepts pushed captures on port 5002.
  • BLE and Pi-hosted hotspot fallback are not part of the active runtime.

RFIDemon is intended for authorised RFID security research, lab work, and defensive assessment. Only use it on cards and systems you own or have explicit permission to test.

Highlights

  • Raspberry Pi RC522/MFRC522 reader support over SPI.
  • Windows/non-Pi development support through MockMFRC522.
  • MIFARE Classic 1K, Mini, 4K, and Fudan-style card classification.
  • AutoPwn pipeline with dictionary, Darkside, and nested attack phases.
  • Thread-safe reader access through one shared reader_lock.
  • Encrypted Pi-side capture storage using core/Encryption.py.
  • Plaintext laptop inbox by design for easy review and export.
  • Authenticated dashboard login with JWT access and refresh tokens.
  • Save-only Pi database persistence: live cards stay in memory until the Database tab Save action writes encrypted profiles.
  • TLS certificate generation for the Pi API and laptop receiver.
  • Secure exfil using HTTPS, deployment-secret auth, HMAC request signatures, and Fernet-encrypted payloads.
  • CSV, TXT, PDF, and HTML report generation.
  • Active automated tests for transport, receiver, reports, and auth.

Architecture At A Glance

graph LR
    subgraph Pi["Raspberry Pi"]
        RC522["RC522 reader"]
        API["server/app.py\nFlask API :5000"]
    AutoPwn["AutoPwn\n1K + 4K crack threads"]
    Session["Live session memory"]
    Store["Encrypted SQLite\ncore/CardCapture.py"]
        Discovery["UDP discovery responder\n:52117"]
    end

    subgraph Laptop["Laptop"]
        Browser["Browser"]
        Proxy["dashboard_proxy.py\nHTTP :5001"]
        Receiver["laptop_receiver.py\nHTTPS :5002"]
        Inbox["Plaintext inbox\ndata/exfil_inbox"]
    end

    RC522 --> API
    API --> AutoPwn
    API --> Session
    AutoPwn --> Session
    API -->|"Database Save"| Store
    API <--> Discovery
    Browser --> Proxy
    Proxy <--> API
    API -->|"capture push"| Receiver
    Receiver --> Inbox
Loading

The Pi starts in config mode. The operator opens the laptop dashboard and switches to attack mode. Attack mode starts a scan loop and AutoPwn worker threads. When a card is detected, the scan loop routes it to the correct MIFARE Classic AutoPwn instance by SAK/card type. Cracked profiles are exposed to the dashboard as live session data and pushed to the configured laptop receiver when exfil is enabled. The Pi database is written only when the operator presses Save in the Database tab.

Runtime Components

Component Host Purpose
server/app.py Pi Flask API, reader loop, mode switching, AutoPwn orchestration, capture storage, exfil push
MFRC522.py Pi/dev RC522 SPI driver plus MockMFRC522 for non-Pi development
Config.py Pi/laptop Environment-backed runtime configuration
autopwn/ Pi MIFARE Classic card detection, key recovery, CRYPTO1 helpers, KeyStore
core/ Pi/laptop Card read/write/dump/fingerprint logic, encrypted storage, formatting, TLS cert helpers
network/transport_manager.py Pi UDP discovery responder and in-memory card snapshot buffer
network/discovery.py Laptop UDP discovery client and TLS fingerprint helper
windows/dashboard_proxy.py Laptop Browser-facing dashboard proxy and Pi API forwarder
windows/laptop_receiver.py Laptop HTTPS inbox for card pushes from the Pi
reports.py Pi/laptop CSV, TXT, PDF, and HTML exports
security/ Pi JWT token creation/verification and Flask auth decorators
web/ Laptop browser Single-page operator dashboard assets
setup/ Pi/laptop Setup, launch, systemd, and validation scripts
tests/ Dev Supported automated tests

Codebase Tree

RFIDemon/
|-- server/ Pi Flask API, mode switching, scan loop, AutoPwn orchestration
|-- autopwn/ Dictionary, Darkside, nested auth, CRYPTO1 helpers
|-- core/ RFID operations, encrypted storage, cloning, formatting, TLS helpers
|-- network/ UDP discovery and transport support
|-- security/ JWT auth and Flask route protection
|-- shared/ HMAC, deployment secret, Fernet payload security
|-- windows/ Laptop dashboard proxy, receiver, launcher
|-- web/ Browser dashboard assets
|-- setup/ Pi/laptop setup scripts and service files
|-- tests/ Pytest regression and integration tests
|-- reports.py CSV, TXT, PDF, and HTML report generation
|-- Config.py Runtime configuration
|-- MFRC522.py RC522 hardware driver and mock reader
|-- README.md Main documentation

data/ is repo-local runtime state. It is intentionally ignored except for data/.gitkeep; generated certs, keys, databases, logs, laptop inbox files, and caches should not be committed.

Quick Start: Raspberry Pi

Use Raspberry Pi OS Lite with SSH, SPI-capable hardware, and Wi-Fi configured in Raspberry Pi Imager. RFIDemon no longer manages access-point mode itself.

Clone or copy the project onto the Pi, then run:

cd /opt/RFIDemon
bash setup/ServerSetup.sh

The setup script:

  1. Checks Python 3.9+ and Raspberry Pi suitability.
  2. Installs Python, venv, development headers, iproute2, and iw.
  3. Creates the rfidemon service user.
  4. Creates .venv and installs requirements.txt.
  5. Creates data/rfidemon.env from setup/rfidemon.env.example.
  6. Enables SPI.
  7. Installs and starts rfidemon.service.

Edit the Pi environment file:

nano data/rfidemon.env

Set at least:

RFIDEMON_API_PASSWORD=<choose-a-strong-password>
RFIDEMON_DEPLOYMENT_SECRET=<same-secret-as-laptop>

TLS is enabled by default. On first start, the Pi generates:

  • data/rfidemon.crt
  • data/rfidemon.key
  • data/encryption.key
  • data/jwt_secret.key

Restart and watch logs:

sudo systemctl restart rfidemon
sudo journalctl -u rfidemon -f

If SPI was first enabled during setup, reboot once:

sudo reboot

Validate the Pi:

.venv/bin/python setup/validate_deployment.py

Quick Start: Windows Laptop

Run:

setup\ClientSetup.bat

The client setup creates .venv, installs requirements.txt, creates data/, and copies setup/rfidemon.env.example to data/rfidemon.env if the env file is missing. It preserves an existing env file.

Start both laptop services:

.\.venv\Scripts\activate
python .\windows\launch_laptop.py

Open:

http://localhost:5001

The launcher starts:

  • windows/laptop_receiver.py on HTTPS port 5002
  • windows/dashboard_proxy.py on HTTP port 5001

Before starting, the launcher validates critical Python imports, checks that data/rfidemon.env exists, warns when RFIDEMON_DEPLOYMENT_SECRET is unset, checks the receiver/dashboard ports are free, and prints log paths on failure.

Allow Python through Windows Firewall on private networks. The Pi must be able to reach the laptop receiver on port 5002.

Security Model Summary

Use the same RFIDEMON_DEPLOYMENT_SECRET in data/rfidemon.env on the Pi and Windows laptop. That static deployment secret replaces the old interactive pairing ceremony.

On the Pi, first start creates:

  • data/rfidemon.crt and data/rfidemon.key for the Pi HTTPS API
  • data/encryption.key for encrypted Pi storage
  • data/jwt_secret.key for persistent JWT signing

On the laptop, first receiver start creates:

  • data/laptop.crt and data/laptop.key for the laptop HTTPS receiver

Card pushes to the laptop receiver use:

  • HTTPS to the learned receiver IP/port.
  • Authorization: Bearer <RFIDEMON_DEPLOYMENT_SECRET>.
  • X-RFIDemon-Signature: sha256=<hmac>.
  • Fernet payload encryption with a key derived from RFIDEMON_DEPLOYMENT_SECRET.

TLS trust uses SHA-256 certificate fingerprints, so normal DHCP IP changes on the shared Wi-Fi can reconnect without hostname errors. The laptop keeps the last Pi target and learned fingerprint in data/pi_config.json; after a new launcher session, log in again and the proxy can rediscover or reuse that saved target. Saved database profiles remain on the Pi. Unsaved live session cards do not survive a Pi process restart.

To force a clean run-through on the laptop:

Remove-Item .\data\laptop.crt, .\data\laptop.key, .\data\pi_config.json `
  -ErrorAction SilentlyContinue

Then restart python .\windows\launch_laptop.py and log in again.

Storage Model

Pi-side card data is encrypted before disk writes. The capture database is SQLite, but the card payload column is a Fernet-encrypted JSON blob. The Pi database is intended to survive process restarts without leaving raw card dumps on disk.

Live read/dump/exfil snapshots stay in server memory during the current Pi process. They appear in the Cards/session views immediately, but they are not inserted into data/captured_cards.db until the operator presses Save in the Database tab. /api/db/cards returns persisted database rows only and marks a saved UID with in_session when that UID is also live.

After a Pi restart, the live session is empty. Previously saved encrypted profiles still appear in the Database tab because they are loaded from the Pi database.

Laptop receiver output is intentionally plaintext and written under:

data/exfil_inbox/

That design makes the laptop inbox easy to inspect, submit, export, or archive after a test. Do not add laptop-side encryption unless the project requirements change.

data/recovered_keys.json stores recovered sector keys only. It should never store raw card dumps.

Runtime secrets, captures, logs, virtual environments, editor folders, and caches are ignored by .gitignore and .sftpignore.

Security Boundaries

Area Current design
Dashboard login Password login through /api/auth/login; JWT access and refresh tokens
Browser to proxy Localhost HTTP at http://localhost:5001
Proxy to Pi HTTPS when Pi TLS is enabled; SHA-256 fingerprint pinning
Pi to laptop receiver HTTPS receiver, deployment-secret auth, HMAC signatures, encrypted payload
Pi capture storage Encrypted at rest through core/Encryption.py
Laptop inbox Plaintext by design
Rate limiting Flask-Limiter global default plus stricter write/clone/security/test limits
Hardware access All RC522 access must go through reader_lock

Authentication is enforced by @require_auth only when RFIDEMON_API_PASSWORD is set. Do not deploy without setting that password.

Normal Operator Flow

  1. Start the Pi service.
  2. Start the laptop receiver and dashboard proxy with windows/launch_laptop.py.
  3. Open http://localhost:5001.
  4. Log in with the Pi RFIDEMON_API_PASSWORD.
  5. Let the dashboard discover the Pi, or set the Pi IP manually.
  6. Switch to attack mode.
  7. Present a MIFARE Classic card to the RC522 reader.
  8. Review live card status, recovered keys, cloneability, exports, and reports.
  9. Press Save in the Database tab for any session cards that must persist into a later Pi session.

Development And Tests

The supported non-Pi development path uses MockMFRC522, so most code can be tested on Windows, macOS, or Linux without RFID hardware.

Install dependencies:

python -m venv .venv
.venv/bin/python -m pip install -r requirements.txt

On Windows PowerShell:

python -m venv .venv
.\.venv\Scripts\python -m pip install -r requirements.txt

Run the active automated baseline:

python -m pytest tests -q

Run the full suite:

python -m pytest -q

Viva / Code Defence Path

Use this order when explaining the codebase:

  1. Config.py shows the active Wi-Fi, TLS, capture, auth, and rate-limit settings.
  2. server/app.py shows startup, reader initialisation, mode switching, the scan loop, and route boundaries.
  3. autopwn/MifareAutoPwnBase.py shows the dictionary -> Darkside -> nested -> final profile pipeline.
  4. core/CardCapture.py and core/Encryption.py show save-only encrypted Pi storage.
  5. shared/security.py, security/token_manager.py, and security/auth_middleware.py show HMAC/Fernet deployment security and JWT route protection.
  6. windows/dashboard_proxy.py and windows/laptop_receiver.py show laptop discovery, proxying, secure ingest, and the plaintext inbox.
  7. web/app.js shows dashboard auth token handling, polling, mode switching, database save, diagnostics, and report export flow.
  8. tests/ shows regression coverage for auth, AutoPwn, receiver security, robustness, Wi-Fi transport, and mock reader behaviour.

Limitations And Future Work

  • MIFARE Classic support is the focus; DESFire, Plus SL3, and Java Card devices are detected but not attacked.
  • Pi and laptop must share the same infrastructure Wi-Fi network.
  • Laptop inbox files are plaintext by design; protect the laptop workspace after an engagement.
  • Self-signed TLS uses certificate fingerprint pinning rather than public CA trust.
  • AutoPwn success depends on card family, keys, PRNG behaviour, reader positioning, and legal authorisation.
  • Future work could add stronger operator roles, richer report templates, hardware status telemetry, and broader non-Classic card analysis.

Supplementary Docs

README.md is the primary documentation entry point. The files under docs/ are intentionally slim pointers back here to avoid duplicate deployment and code-map guidance drifting out of date.

About

RFIDemon is a Raspberry Pi based RFID analysis and cloning workstation for authorised MIFARE Classic testing. The Pi owns the RC522 reader, REST API, scan loop, encrypted capture storage, and AutoPwn cracking pipeline. A laptop runs the browser dashboard proxy and HTTPS receiver for captured card snapshots.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors