NFC 01 de marzo de 2026

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

  1. Resumen Ejecutivo
  2. Entorno de Pruebas
  3. Reconocimiento
  4. Extracción de Claves — Ataque MFKey32
  5. Análisis de Dumps
  6. Hallazgo Principal
  7. Comportamiento del Lector
  8. Impacto
  9. Mitigaciones Recomendadas
  10. 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

ElementoDetalle
Dispositivo de análisisFlipper Zero
FirmwareMomentum (basado en firmware oficial, incluye MFKey mejorado)
ObjetivoMáquina expendedora con sistema de pago NFC
Tipo de tarjetaMIFARE Classic 1K
AutorizaciónExplícita por parte del propietario del sistema
EntornoControlado, 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:

DumpSaldoFecha
nfc_050.nfc0.50 €Muestra A
nfc_200.nfc2.00 €Muestra B
nfc_250.nfc2.50 €Muestra C
nfc_350.nfc3.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.

MuestraByte 9Byte 10Valor (little-endian)DecimalSaldo real
A0x000x320x0032500.50 €
B0x000xC80x00C82002.00 €
C0x000xFA0x00FA2502.50 €
D0x010x5E0x015E3503.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

MedidaDescripción
Cambiar a claves no predeciblesUsar claves aleatorias únicas por tarjeta en lugar de claves compartidas entre sectores
Activar access bits restrictivosConfigurar 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:

ChipSeguridadNotas
MIFARE Classic❌ BajaCrypto-1 roto desde 2008
MIFARE Plus⚠️ MediaCompatible con Classic, añade AES
MIFARE DESFire EV2/EV3✅ AltaAES-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


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.