Lectura y clonado de tarjetas NFC
Cómo leer, guardar y emular tarjetas NFC MIFARE Classic con el Flipper Zero.
NFC Payment Security Analysis: Vulnerabilidad en Máquina Vending con MIFARE Classic 1K
Autor: Francisco Javier Marmolejo López
Fecha: 2026
Tipo: Security Research / PoC
Entorno: Controlado y autorizado por el propietario del sistema
Estado: Responsible Disclosure completado
Índice
- Resumen Ejecutivo
- Entorno de Pruebas
- Reconocimiento
- Extracción de Claves — Ataque MFKey32
- Análisis de Dumps
- Hallazgo Principal
- Comportamiento del Lector
- Impacto
- Mitigaciones Recomendadas
- Conclusión y Responsible Disclosure
Resumen Ejecutivo
Durante una sesión de security research autorizada se ha identificado que el sistema de pago NFC de una máquina expendedora almacena el saldo del usuario en texto plano dentro de la tarjeta MIFARE Classic 1K, sin ningún mecanismo de integridad criptográfica.
Esto permite a un atacante con acceso físico a la tarjeta:
- Leer el saldo almacenado
- Modificarlo arbitrariamente
- Restaurar dumps anteriores para anular transacciones (double spending)
El hallazgo es consistente en cuatro muestras distintas con diferentes saldos, confirmando el patrón de forma inequívoca.
Entorno de Pruebas
| Elemento | Detalle |
|---|---|
| Dispositivo de análisis | Flipper Zero |
| Firmware | Momentum (basado en firmware oficial, incluye MFKey mejorado) |
| Objetivo | Máquina expendedora con sistema de pago NFC |
| Tipo de tarjeta | MIFARE Classic 1K |
| Autorización | Explícita por parte del propietario del sistema |
| Entorno | Controlado, sin impacto en sistemas de terceros |
⚠️ Toda la investigación se realizó con permiso explícito del propietario. Este documento tiene únicamente fines educativos y de mejora de seguridad.
Reconocimiento
El primer paso fue identificar el tipo de chip utilizado por la tarjeta del sistema de pago. Usando el Flipper Zero en modo lectura (NFC → Read), el dispositivo identificó automáticamente:
Device type: Mifare Classic
Mifare Classic type: 1K
ATQA: 00 04
SAK: 08
UID: 2B AE 54 B8
MIFARE Classic 1K es un estándar ampliamente documentado con vulnerabilidades conocidas desde 2008, cuando el algoritmo de cifrado propietario Crypto-1 fue completamente roto por investigadores de la Universidad de Radboud (Países Bajos).
Estructura de memoria MIFARE Classic 1K
La tarjeta organiza 1KB de memoria en 16 sectores de 4 bloques cada uno:
Sector 0: Bloque 0 → Datos fabricante (UID, read-only)
Bloque 1 → Datos de usuario
Bloque 2 → Datos de usuario
Bloque 3 → Sector Trailer (Key A + Access Bits + Key B)
Sector N: Bloque N*4+0 → Datos
Bloque N*4+1 → Datos
Bloque N*4+2 → Datos
Bloque N*4+3 → Sector Trailer
En la lectura inicial, los sectores 0-10 se leyeron completamente gracias al diccionario de claves por defecto del Flipper. Los sectores 11-15 (bloques 44-63) devolvieron ??, indicando claves no estándar.
Extracción de Claves — Ataque MFKey32
¿Por qué es necesario?
Los sectores con ?? están protegidos con claves personalizadas que no figuran en el diccionario por defecto. Para leer su contenido es necesario recuperar esas claves.
El ataque
MIFARE Classic usa Crypto-1 para la autenticación entre lector y tarjeta. Este protocolo intercambia números aleatorios (nonces) durante la negociación. La vulnerabilidad reside en que el generador de nonces es predecible, permitiendo recuperar la clave a partir de pocos intercambios capturados.
Proceso:
1. Flipper Zero entra en modo emulación de la tarjeta parcialmente leída
NFC → Saved → [tarjeta] → Extract MF Keys
2. Se acerca el Flipper al lector de la máquina (2-3 veces)
El lector intenta autenticar → Flipper captura los intercambios criptográficos
3. Se ejecuta la app MFKey en el Flipper
La app procesa los nonces capturados y calcula las claves mediante el ataque MFKey32
4. Las claves recuperadas se añaden automáticamente al diccionario
5. Se relee la tarjeta física → todos los bloques aparecen completos, sin ??
💡 Nota sobre Momentum: La implementación de MFKey en Momentum incluye recuperación de claves por Static Encrypted Nested, significativamente más rápida que la versión original MFKey32 clásica.
Resultado
Tras el proceso, todos los sectores quedaron desbloqueados. Las claves recuperadas de los sectores 11-15 resultaron ser idénticas entre sí, confirmando una práctica común de usar la misma clave para todos los sectores protegidos.
Análisis de Dumps
Para identificar dónde se almacena el saldo, se obtuvieron cuatro dumps comparativos con importes conocidos:
| Dump | Saldo | Fecha |
|---|---|---|
nfc_050.nfc | 0.50 € | Muestra A |
nfc_200.nfc | 2.00 € | Muestra B |
nfc_250.nfc | 2.50 € | Muestra C |
nfc_350.nfc | 3.50 € | Muestra D |
Comparativa de bloques (diff)
Al comparar los cuatro dumps, únicamente el bloque 45 presenta diferencias. El resto de los 63 bloques es idéntico entre las cuatro muestras.
Bloque 45 — Muestra A (0.50 €):
Block 45: 01 01 02 08 08 08 EE EE 00 00 32 01 62 54 00 01
^^
0x32 = 50
Bloque 45 — Muestra B (2.00 €):
Block 45: 01 01 02 08 08 08 EE EE 00 00 C8 01 62 54 00 01
^^
0xC8 = 200
Bloque 45 — Muestra C (2.50 €):
Block 45: 01 01 02 08 08 08 EE EE 00 00 FA 01 62 54 00 01
^^
0xFA = 250
Bloque 45 — Muestra D (3.50 €):
Block 45: 01 01 02 08 08 08 EE EE 00 01 5E 01 62 54 00 01
^^ ^^
01 5E → 0x015E = 350
Hallazgo Principal
El saldo se almacena en texto plano en los bytes 9-10 del Bloque 45
El saldo está codificado como un entero de 16 bits en formato little-endian en los bytes 9 y 10 del bloque 45, expresado en céntimos de euro, sin cifrado, sin MAC de integridad y sin ningún mecanismo de verificación.
| Muestra | Byte 9 | Byte 10 | Valor (little-endian) | Decimal | Saldo real |
|---|---|---|---|---|---|
| A | 0x00 | 0x32 | 0x0032 | 50 | 0.50 € ✅ |
| B | 0x00 | 0xC8 | 0x00C8 | 200 | 2.00 € ✅ |
| C | 0x00 | 0xFA | 0x00FA | 250 | 2.50 € ✅ |
| D | 0x01 | 0x5E | 0x015E | 350 | 3.50 € ✅ |
La correlación es perfecta en las cuatro muestras.
Observación importante: decodificación en dos fases
Con saldos ≤ 2.55 € el byte 9 permanece en 0x00, lo que inicialmente sugería un entero de 8 bits. La muestra D (3.50 €) reveló que el byte 9 actúa como byte alto del entero, confirmando la codificación de 16 bits. Esta es una trampa común en el análisis de protocolos propietarios: no asumir el tamaño del campo hasta cubrir el rango completo.
Fórmula de decodificación
saldo_euros = ((byte_9 << 8) | byte_10) / 100
# Ejemplo: (0x01 << 8) | 0x5E = 0x015E = 350 → 3.50€
Rango máximo del sistema
0x0000 = 0 céntimos = 0.00 €
0xFFFF = 65535 céntimos = 655.35 €
Comportamiento del Lector
El lector escribe en la tarjeta
Durante las pruebas se observó un comportamiento relevante: la máquina modifica el dump almacenado en el Flipper cuando este emula la tarjeta. Tras realizar una compra con el Flipper en modo emulación, el bloque 45 se actualiza automáticamente con el nuevo saldo descontado.
Esto confirma que el lector tiene permisos de escritura sobre los bloques de datos. Analizando el trailer del sector 11 (bloque 47):
Block 47: A0 A1 A2 A3 A4 A5 1E 11 EE 5A 4E D4 01 14 10 C2
────────────────── ──────── ──────────────────
Key A (conocida) Access Bits Key B (diferente)
Los access bits 1E 11 EE configuran Key B con permisos de escritura sobre los bloques de datos. El lector utiliza Key B para descontar el saldo tras cada transacción.
Flujo completo de una transacción
┌─────────────┐ ┌──────────────┐
│ Tarjeta │ │ Lector │
└──────┬──────┘ └──────┬───────┘
│ │
│◄── Campo RF activo ──────────────│
│ │
│── Anticolisión + UID ───────────►│
│ │
│◄── Autenticación (Key A) ────────│ ← Lectura del saldo
│── Bloque 45 (saldo actual) ─────►│
│ │
│ [máquina sirve producto] │
│ │
│◄── Autenticación (Key B) ────────│ ← Escritura del nuevo saldo
│◄── Escribe Bloque 45 ────────────│
│ │
└──────┴──────┘ └──────┴───────┘
Impacto
1. Double Spending (alta criticidad)
Un atacante puede guardar un dump de la tarjeta antes de realizar una compra y restaurarlo después, recuperando el saldo gastado indefinidamente.
# Pseudocódigo del ataque
dump_antes = leer_tarjeta() # bloque 45 byte9=0x00, byte10=0xC8 → 2.00€
realizar_compra() # descuenta 0.50€, tarjeta queda en 1.50€
escribir_tarjeta(dump_antes) # restaura byte9=0x00, byte10=0xC8 → 2.00€
# repetible sin límite, sin rastro auditable
2. Modificación arbitraria del saldo (alta criticidad)
Editando directamente los bytes 9 y 10 del bloque 45 en el archivo .nfc y escribiendo la tarjeta modificada, es posible establecer cualquier saldo entre 0.00 € y 655.35 €.
# Para establecer un saldo de 5.00€ (500 céntimos = 0x01F4):
byte_9 = 0x01
byte_10 = 0xF4
3. Sin detección server-side (agravante)
El sistema no dispone de validación en servidor. El saldo es la única fuente de verdad y reside en un medio físico manipulable sin rastro auditable.
Mitigaciones Recomendadas
Solución a corto plazo
| Medida | Descripción |
|---|---|
| Cambiar a claves no predecibles | Usar claves aleatorias únicas por tarjeta en lugar de claves compartidas entre sectores |
| Activar access bits restrictivos | Configurar bloques de datos como solo-lectura desde la tarjeta, solo escritura desde el lector autenticado con Key B |
Solución a medio plazo
Implementar MAC sobre los datos: Añadir un Message Authentication Code sobre el bloque de saldo que el lector pueda verificar antes de aceptar el valor. Sin la clave del MAC, modificar el saldo produce un MAC inválido que el lector rechaza.
Solución a largo plazo (recomendada)
Migrar la arquitectura a saldo en servidor:
Arquitectura actual (insegura):
Tarjeta → almacena saldo → lector lee/escribe directamente
Arquitectura recomendada (segura):
Tarjeta → almacena solo UID → lector consulta servidor → servidor gestiona saldo
Con esta arquitectura, la tarjeta actúa únicamente como identificador. El saldo reside en un servidor con logs de transacciones, lo que elimina completamente el vector de ataque y añade trazabilidad.
Alternativas de hardware más seguras:
| Chip | Seguridad | Notas |
|---|---|---|
| MIFARE Classic | ❌ Baja | Crypto-1 roto desde 2008 |
| MIFARE Plus | ⚠️ Media | Compatible con Classic, añade AES |
| MIFARE DESFire EV2/EV3 | ✅ Alta | AES-128, autenticación mutua, diversificación de claves |
Conclusión y Responsible Disclosure
Esta investigación demuestra que sistemas de pago basados en MIFARE Classic con saldo almacenado en la tarjeta presentan vulnerabilidades críticas bien documentadas que no requieren equipamiento especializado para ser explotadas.
El vector de ataque es sencillo, reproducible y no deja rastro auditable en el sistema actual.
Los hallazgos y recomendaciones fueron comunicados al propietario del sistema al finalizar la investigación.
Herramientas utilizadas
- Flipper Zero con firmware Momentum
- App MFKey (incluida en Momentum)
- Editor de texto para análisis de archivos
.nfc
Referencias
- Nohl, K. et al. (2008). Reverse-Engineering a Cryptographic RFID Tag. USENIX Security Symposium.
- MIFARE Classic EV1 1K — NXP Datasheet
- Flipper Zero NFC Documentation
- MFKey32 — GitHub
Este documento se publica con fines educativos. El autor no se hace responsable del uso indebido de la información aquí contenida. Cualquier reproducción de estas técnicas debe realizarse exclusivamente en entornos autorizados.