Dumper de carte portatif
Auteur : Xylitol
Zine : Rafale #21
Salut à tous,
Dans rafale 20 (yescard cafe) j'utilisais un PN532 de chez Adafruit connecté en
UART sur un Raspberry Pi pour casser/forger des badges Mifare Classic de
distributeur.
Dans cet article qui est plus ou moins en continuité on va voir comment
interfacer le PN532 sur un Arduino.
L'idée finale est de réaliser un dumper de carte portatif.
Arduino n'étant pas un mini PC comme le Raspbery Pi mais un mini automate, on
aura besoin d'une chose supplémentaire : un module carte SD pour sauvegarder les
dumps (les chinois vendent ça 1€ sur eBay).
Nativement Arduino possède la librairie 'SD'
(https://www.arduino.cc/en/Reference/SD) qui permet de jouer avec ce genre de
module. Pour utiliser le PN532 d'Adafruit sur un Arduino j'ai trouvé une
librairie "NDEF" sur GitHub : https://github.com/don/NDEF
Viens ensuite le temps de la réflexion sur comment interfacer les deux, j'ai
choisi de reprendre les codes d'exemples des deux librairie et d'assembler le
tout, le module SD fonctionnera en SPI et le PN532 en i2c. N'oubliez pas de
basculer le module en i2c, jumpers SEL0: ON, SEL1: OFF.
Voici un câblage visuel de l'installation :
J'utilise un Arduino Mega car cela ne fonctionnerait pas sur un Arduino UNO (il
a peu de mémoire en comparaison, la bibliothèque NDEF est relativement lourde à
implanter).
ns plus attendre, voilà le code :
// RAFALE ZINES
// Project PN532 Tag --> SD card Dump
// Version 1.0
//------------LIB INCLUDE---------------
#include <Wire.h>
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
#include <SPI.h>
#include <SD.h>
//---------DEBUG PORT CONFIG-------------
#define DEBUG_PORT Serial
#define DEBUG_PORT_BAUD 9600
//--------------PIN DEFS-----------------
#define PIN_SD_MOSI 50
#define PIN_SD_MISO 51
#define PIN_SD_CLK 52
#define PIN_SD_CS 53
//--------FIRMWARE STATE TYPEDEF---------
typedef enum {
FIRMWARE_STATE_IDLE = 0,
FIRMWARE_STATE_CARD_SCANNED
} FirmwareState_t;
FirmwareState_t _state;
//-------------GLOBAL VARS---------------
char UID[13];
String content = "";
char buffer[33];
//----------NFC READER PARAMS------------
byte uid[] = {0, 0, 0, 0};
uint8_t uidLength;
uint8_t currentblock;
bool authenticated = false;
uint8_t data[16];
uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
bool flag = false;
//--------------OBJ DEFS-----------------
PN532_I2C pn532i2c(Wire);
PN532 nfc(pn532i2c);
File myFile;
void setup()
{
initDebug();
initNFCReader();
initSD();
}
void loop()
{
switch (_state)
{
case FIRMWARE_STATE_IDLE:
idle();
break;
case FIRMWARE_STATE_CARD_SCANNED:
dumpUID();
break;
}
}
void initDebug()
{
DEBUG_PORT.begin(9600);
DEBUG_PORT.println("Debugger Initialized..");
}
void initNFCReader()
{
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata)
{
DEBUG_PORT.print("Didn't find PN53x board");
while (1);
}
DEBUG_PORT.print("Found chip PN5"); DEBUG_PORT.println((versiondata >> 24) & 0xFF, HEX);
DEBUG_PORT.print("Firmware ver. "); DEBUG_PORT.print((versiondata >> 16) & 0xFF, DEC);
DEBUG_PORT.print('.'); DEBUG_PORT.println((versiondata >> 8) & 0xFF, DEC);
nfc.SAMConfig();
DEBUG_PORT.println("NFC Reader Initialized..");
}
void initSD()
{
if (!SD.begin(PIN_SD_CS))
{
DEBUG_PORT.println("SD Initialization Failed!");
return;
}
DEBUG_PORT.println("SD Initialized..");
}
void idle()
{
DEBUG_PORT.println("Scan a NFC Tag..");
delay(1000);
flag = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
if (flag)
{
DEBUG_PORT.println("Found an ISO14443A card");
DEBUG_PORT.print(" UID Length: "); DEBUG_PORT.print(uidLength, DEC); DEBUG_PORT.println(" bytes");
DEBUG_PORT.print(" UID Value: ");
array_to_string(uid, 4, UID);
DEBUG_PORT.println(UID);
_state = FIRMWARE_STATE_CARD_SCANNED;
}
}
void dumpUID()
{
UID[8] = '.';
UID[9] = 't';
UID[10] = 'x';
UID[11] = 't';
UID[12] = '\0';
DEBUG_PORT.print("Dumping content in file ");
DEBUG_PORT.print(UID);
DEBUG_PORT.println(" in SD Card..");
myFile = SD.open(UID , FILE_WRITE);
if (myFile)
{
myFile.seek(0);
if (uidLength == 4)
{
DEBUG_PORT.println("Seems to be a Mifare Classic card (4 byte UID)");
for (currentblock = 0; currentblock < 64; currentblock++)
{
if (nfc.mifareclassic_IsFirstBlock(currentblock)) authenticated = false;
if (!authenticated)
{
myFile.print("------------------------Sector ");
myFile.print(currentblock / 4, DEC);
myFile.println("-------------------------");
DEBUG_PORT.print("------------------------Sector ");
DEBUG_PORT.print(currentblock / 4, DEC);
DEBUG_PORT.println("-------------------------");
if (currentblock == 0)
{
flag = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal);
}
else
{
flag = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal);
}
if (flag)
{
authenticated = true;
}
else
{
DEBUG_PORT.println("Authentication error");
}
}
if (!authenticated)
{
myFile.print("Block ");
myFile.print(currentblock, DEC);
myFile.println(" unable to authenticate");
DEBUG_PORT.print("Block ");
DEBUG_PORT.print(currentblock, DEC);
DEBUG_PORT.println(" unable to authenticate");
}
else
{
flag = nfc.mifareclassic_ReadDataBlock(currentblock, data);
if (flag)
{
myFile.print("Block ");
myFile.print(currentblock, DEC);
DEBUG_PORT.print("Block ");
DEBUG_PORT.print(currentblock, DEC);
if (currentblock < 10)
{
myFile.print(" ");
DEBUG_PORT.print(" ");
}
else
{
myFile.print(" ");
DEBUG_PORT.print(" ");
}
nfc.PrintHexChar(data, 16);
array_to_string(data, 16, buffer);
myFile.println(buffer);
}
else
{
myFile.print("Block ");
myFile.print(currentblock, DEC);
myFile.println(" unable to read this block");
DEBUG_PORT.print("Block ");
DEBUG_PORT.print(currentblock, DEC);
DEBUG_PORT.println(" unable to read this block");
}
}
}
}
else
{
DEBUG_PORT.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
}
myFile.close();
DEBUG_PORT.println("Dump successful..");
}
else {
DEBUG_PORT.println("Failed to Dump!");
DEBUG_PORT.println("Reason: File Open Failed!");
}
flag = false;
content = "";
_state = FIRMWARE_STATE_IDLE;
}
void array_to_string(byte array[], unsigned int len, char buffer[])
{
for (unsigned int i = 0; i < len; i++)
{
byte nib1 = (array[i] >> 4) & 0x0F;
byte nib2 = (array[i] >> 0) & 0x0F;
buffer[i * 2 + 0] = nib1 < 0xA ? '0' + nib1 : 'A' + nib1 - 0xA;
buffer[i * 2 + 1] = nib2 < 0xA ? '0' + nib2 : 'A' + nib2 - 0xA;
}
buffer[len * 2] = '\0';
}
Output dans la console (ici avec un badge VIGIK) :
Le programme boucle en attente d'un passage d'un badge, dès qu'un badge est
trouvé il le dump puis retourne en attente du prochain passage.
Bien entendu pas de mfoc ici, il faut que le badge ne soit pas protégé contre la
lecture. Pour obtenir un dump complet le temps de lecture prend environ 6.50
secondes (chronométré à la Casio f-91w !)
Les données sont stockées au format TXT avec comme nom de fichier : l'UID du
badge.
Voila, bon c'est qu'un exemple, si vous voulez quelques idées d'amélioration on
pourrait aussi bien mettre un module Bluetooth, ou GSM, pour communiquer les
données on the fly.
Remplacer l'Arduino par un Raspi (pour casser les badges), remplacer le PN532
par un truc qui a une meilleure portée, etc...
Enfin y'a pas mal de trucs rigolos à faire avec la nfc, c'est pour ça que
maintenant j'utilise un portefeuille qui fait cage de Faraday ;)
|