Write special Mifare 1K cards, including Block 0 / UID

This commit is contained in:
Adam Laurie 2011-09-05 14:40:56 +00:00
parent fa7084fa77
commit e401f4ec4e
4 changed files with 458 additions and 11 deletions

View file

@ -10,6 +10,7 @@ bin_PROGRAMS = \
nfc-emulate-uid \ nfc-emulate-uid \
nfc-list \ nfc-list \
nfc-mfclassic \ nfc-mfclassic \
nfc-mfsetuid \
nfc-mfultralight \ nfc-mfultralight \
nfc-poll \ nfc-poll \
nfc-relay \ nfc-relay \
@ -51,6 +52,10 @@ nfc_mfclassic_SOURCES = nfc-mfclassic.c mifare.c mifare.h
nfc_mfclassic_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_mfclassic_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la libnfcutils.la
nfc_mfsetuid_SOURCES = nfc-mfsetuid.c
nfc_mfsetuid_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la
nfc_relay_SOURCES = nfc-relay.c nfc_relay_SOURCES = nfc-relay.c
nfc_relay_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_relay_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la libnfcutils.la

View file

@ -3,7 +3,7 @@
nfc-mfclassic \- MIFARE Classic command line tool nfc-mfclassic \- MIFARE Classic command line tool
.SH SYNOPSIS .SH SYNOPSIS
.B nfc-mfclassic .B nfc-mfclassic
.RI \fR\fBr\fR|\fBw\fR .RI \fR\fBr\fR|\fBw\fR\fR|\fBu\fR
.RI \fR\fBa\fR|\fBb\fR .RI \fR\fBa\fR|\fBb\fR
.IR DUMP .IR DUMP
.IR [KEYS] .IR [KEYS]
@ -27,12 +27,18 @@ to store the keys and data for all sectors.
Be cautious that some parts of a Mifare Classic memory are used for r/w access Be cautious that some parts of a Mifare Classic memory are used for r/w access
of the rest of the memory, so please read the tag documentation before experimenting too much! of the rest of the memory, so please read the tag documentation before experimenting too much!
The 'u' option allows writing of special Mifare cards that can be 'unlocked' to allow block 0
to be overwritten. This includes UID and manufacturer data. Take care when amending UIDs to set
the correct BCC (UID checksum). Currently only 4 byte UIDs are supported.
.SH OPTIONS .SH OPTIONS
.BR r " | " w .BR r " | " w " | " u
Perform read from ( Perform read from (
.B r .B r
) or write to ( ) or write to (
.B w .B w
) or unlocked write to (
.B u
) card. ) card.
.TP .TP
.BR a " | " b .BR a " | " b

View file

@ -3,6 +3,7 @@
* *
* Copyright (C) 2009, Roel Verdult * Copyright (C) 2009, Roel Verdult
* Copyright (C) 2010, Romuald Conty, Romain Tartière * Copyright (C) 2010, Romuald Conty, Romain Tartière
* Copyright (C) 2011, Adam Laurie
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -78,6 +79,53 @@ static const nfc_modulation_t nmMifare = {
static size_t num_keys = sizeof (keys) / 6; static size_t num_keys = sizeof (keys) / 6;
#define MAX_FRAME_LEN 264
static byte_t abtRx[MAX_FRAME_LEN];
static size_t szRxBits;
static size_t szRx = sizeof(abtRx);
byte_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 };
// special unlock command
byte_t abtUnlock1[1] = { 0x40 };
byte_t abtUnlock2[1] = { 0x43 };
static bool
transmit_bits (const byte_t * pbtTx, const size_t szTxBits)
{
// Show transmitted command
printf ("Sent bits: ");
print_hex_bits (pbtTx, szTxBits);
// Transmit the bit frame command, we don't use the arbitrary parity feature
if (!nfc_initiator_transceive_bits (pnd, pbtTx, szTxBits, NULL, abtRx, &szRxBits, NULL))
return false;
// Show received answer
printf ("Received bits: ");
print_hex_bits (abtRx, szRxBits);
// Succesful transfer
return true;
}
static bool
transmit_bytes (const byte_t * pbtTx, const size_t szTx)
{
// Show transmitted command
printf ("Sent bits: ");
print_hex (pbtTx, szTx);
// Transmit the command bytes
if (!nfc_initiator_transceive_bytes (pnd, pbtTx, szTx, abtRx, &szRx))
return false;
// Show received answer
printf ("Received bits: ");
print_hex (abtRx, szRx);
// Succesful transfer
return true;
}
static void static void
print_success_or_failure (bool bFailure, uint32_t * uiBlockCounter) print_success_or_failure (bool bFailure, uint32_t * uiBlockCounter)
{ {
@ -231,14 +279,55 @@ read_card (void)
} }
static bool static bool
write_card (void) write_card (int write_block_zero)
{ {
uint32_t uiBlock; uint32_t uiBlock;
bool bFailure = false; bool bFailure = false;
uint32_t uiWriteBlocks = 0; uint32_t uiWriteBlocks = 0;
printf ("Writing %d blocks |", uiBlocks + 1);
if(write_block_zero) {
printf ("Unlocking card\n");
// Configure the CRC
if (!nfc_configure (pnd, NDO_HANDLE_CRC, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
// Use raw send/receive methods
if (!nfc_configure (pnd, NDO_EASY_FRAMING, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
iso14443a_crc_append(abtHalt, 2);
transmit_bytes (abtHalt, 4);
// now send unlock
if (!transmit_bits (abtUnlock1, 7)) {
printf("unlock failure!\n");
return false;
}
if (!transmit_bytes (abtUnlock2, 1)) {
printf("unlock failure!\n");
return false;
}
// reset reader
// Configure the CRC
if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
// Switch off raw send/receive methods
if (!nfc_configure (pnd, NDO_EASY_FRAMING, true)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
}
printf ("Writing %d blocks |", uiBlocks + 1);
// Write the card from begin to end; // Write the card from begin to end;
for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) { for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) {
// Authenticate everytime we reach the first sector of a new block // Authenticate everytime we reach the first sector of a new block
@ -260,7 +349,7 @@ write_card (void)
fflush (stdout); fflush (stdout);
// Try to authenticate for the current sector // Try to authenticate for the current sector
if (!authenticate (uiBlock)) { if (!write_block_zero && !authenticate (uiBlock)) {
printf ("!\nError: authentication failed for block %02x\n", uiBlock); printf ("!\nError: authentication failed for block %02x\n", uiBlock);
return false; return false;
} }
@ -279,13 +368,21 @@ write_card (void)
} }
} else { } else {
// The first block 0x00 is read only, skip this // The first block 0x00 is read only, skip this
if (uiBlock == 0) if (uiBlock == 0 && ! write_block_zero)
continue; continue;
// Make sure a earlier write did not fail // Make sure a earlier write did not fail
if (!bFailure) { if (!bFailure) {
// Try to write the data block // Try to write the data block
memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, 16); memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, 16);
// do not write a block 0 with incorrect BCC - card will be made invalid!
if (uiBlock == 0) {
if((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00) {
printf ("!\nError: incorrect BCC in MFD file!\n");
return false;
}
}
if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp)) if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp))
bFailure = true; bFailure = true;
} }
@ -321,15 +418,17 @@ typedef enum {
ACTION_READ, ACTION_READ,
ACTION_WRITE, ACTION_WRITE,
ACTION_EXTRACT, ACTION_EXTRACT,
ACTION_USAGE ACTION_USAGE,
ACTION_WRITE_UNLOCKED
} action_t; } action_t;
static void static void
print_usage (const char *pcProgramName) print_usage (const char *pcProgramName)
{ {
printf ("Usage: "); printf ("Usage: ");
printf ("%s r|w a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName); printf ("%s r|w|u a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
printf (" r|w - Perform read from (r) or write to (w) card\n"); printf (" r|w|u - Perform read from (r) or write to (w) or unlocked write to (u) card\n");
printf (" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
printf (" a|b - Use A or B keys for action\n"); printf (" a|b - Use A or B keys for action\n");
printf (" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); printf (" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
printf (" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n"); printf (" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
@ -362,12 +461,14 @@ main (int argc, const char *argv[])
atAction = ACTION_READ; atAction = ACTION_READ;
bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a'; bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
bUseKeyFile = (argc > 4); bUseKeyFile = (argc > 4);
} else if (strcmp (command, "w") == 0) { } else if (strcmp (command, "w") == 0 || strcmp (command, "u") == 0) {
if (argc < 4) { if (argc < 4) {
print_usage (argv[0]); print_usage (argv[0]);
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
atAction = ACTION_WRITE; atAction = ACTION_WRITE;
if (strcmp (command, "u") == 0)
atAction = ACTION_WRITE_UNLOCKED;
bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a'; bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
bUseKeyFile = (argc > 4); bUseKeyFile = (argc > 4);
} else if (strcmp (command, "x") == 0) { } else if (strcmp (command, "x") == 0) {
@ -385,6 +486,7 @@ main (int argc, const char *argv[])
break; break;
case ACTION_READ: case ACTION_READ:
case ACTION_WRITE: case ACTION_WRITE:
case ACTION_WRITE_UNLOCKED:
if (bUseKeyFile) { if (bUseKeyFile) {
pfKeys = fopen (argv[4], "rb"); pfKeys = fopen (argv[4], "rb");
if (pfKeys == NULL) { if (pfKeys == NULL) {
@ -493,7 +595,10 @@ main (int argc, const char *argv[])
fclose (pfDump); fclose (pfDump);
} }
} else if (atAction == ACTION_WRITE) { } else if (atAction == ACTION_WRITE) {
write_card (); write_card (0);
}
else if (atAction == ACTION_WRITE_UNLOCKED) {
write_card (1);
} }
nfc_disconnect (pnd); nfc_disconnect (pnd);

331
examples/nfc-mfsetuid.c Normal file
View file

@ -0,0 +1,331 @@
/*-
* Public platform independent Near Field Communication (NFC) library examples
*
* Copyright (C) 2009, Roel Verdult
* Copyright (C) 2011, Adam Laurie
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @file nfc-mfsetuid.c
* @brief Set UID of special Mifare cards
*/
/**
* based on nfc-anticol.c
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <nfc/nfc.h>
#include "nfc-utils.h"
#define SAK_FLAG_ATS_SUPPORTED 0x20
#define MAX_FRAME_LEN 264
static byte_t abtRx[MAX_FRAME_LEN];
static size_t szRxBits;
static size_t szRx = sizeof(abtRx);
static byte_t abtRawUid[12];
static byte_t abtAtqa[2];
static byte_t abtSak;
static byte_t abtAts[MAX_FRAME_LEN];
static byte_t szAts = 0;
static size_t szCL = 1;//Always start with Cascade Level 1 (CL1)
static nfc_device_t *pnd;
bool quiet_output = false;
bool iso_ats_supported = false;
// ISO14443A Anti-Collision Commands
byte_t abtReqa[1] = { 0x26 };
byte_t abtSelectAll[2] = { 0x93, 0x20 };
byte_t abtSelectTag[9] = { 0x93, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte_t abtRats[4] = { 0xe0, 0x50, 0x00, 0x00 };
byte_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 };
#define CASCADE_BIT 0x04
// special unlock command
byte_t abtUnlock1[1] = { 0x40 };
byte_t abtUnlock2[1] = { 0x43 };
byte_t abtWrite[4] = { 0xa0, 0x00, 0x5f, 0xb1 };
byte_t abtData[18] = { 0x01, 0x23, 0x45, 0x67, 0x00, 0x08, 0x04, 0x00, 0x46, 0x59, 0x25, 0x58, 0x49, 0x10, 0x23, 0x02, 0x23, 0xeb };
static bool
transmit_bits (const byte_t * pbtTx, const size_t szTxBits)
{
// Show transmitted command
if (!quiet_output) {
printf ("Sent bits: ");
print_hex_bits (pbtTx, szTxBits);
}
// Transmit the bit frame command, we don't use the arbitrary parity feature
if (!nfc_initiator_transceive_bits (pnd, pbtTx, szTxBits, NULL, abtRx, &szRxBits, NULL))
return false;
// Show received answer
if (!quiet_output) {
printf ("Received bits: ");
print_hex_bits (abtRx, szRxBits);
}
// Succesful transfer
return true;
}
static bool
transmit_bytes (const byte_t * pbtTx, const size_t szTx)
{
// Show transmitted command
if (!quiet_output) {
printf ("Sent bits: ");
print_hex (pbtTx, szTx);
}
// Transmit the command bytes
if (!nfc_initiator_transceive_bytes (pnd, pbtTx, szTx, abtRx, &szRx))
return false;
// Show received answer
if (!quiet_output) {
printf ("Received bits: ");
print_hex (abtRx, szRx);
}
// Succesful transfer
return true;
}
static void
print_usage (char *argv[])
{
printf ("Usage: %s [OPTIONS] [UID]\n", argv[0]);
printf ("Options:\n");
printf ("\t-h\tHelp. Print this message.\n");
printf ("\t-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n");
printf ("\n\tSpecify UID (4 HEX bytes) to set UID, or leave blank for default '01234567'.\n");
printf ("\tThis utility can be used to recover cards that have been damaged by writing bad\n");
printf ("\tdata (e.g. wrong BCC), thus making them non-selectable by most tools/readers.\n\n");
}
int
main (int argc, char *argv[])
{
int arg, i;
unsigned int c;
char tmp[3]= { 0x00, 0x00, 0x00 };
// Get commandline options
for (arg = 1; arg < argc; arg++) {
if (0 == strcmp (argv[arg], "-h")) {
print_usage (argv);
exit(EXIT_SUCCESS);
} else if (0 == strcmp (argv[arg], "-q")) {
quiet_output = true;
} else if (strlen(argv[arg]) == 8) {
for(i= 0 ; i < 4 ; ++i) {
memcpy(tmp, argv[arg]+i*2, 2);
sscanf(tmp, "%02x", &c);
abtData[i]= (char) c;
}
abtData[4]= abtData[0] ^ abtData[1] ^ abtData[2] ^ abtData[3];
iso14443a_crc_append (abtData, 16);
} else {
ERR ("%s is not supported option.", argv[arg]);
print_usage (argv);
exit(EXIT_FAILURE);
}
}
// Try to open the NFC reader
pnd = nfc_connect (NULL);
if (!pnd) {
printf ("Error connecting NFC reader\n");
exit(EXIT_FAILURE);
}
// Initialise NFC device as "initiator"
nfc_initiator_init (pnd);
// Configure the CRC
if (!nfc_configure (pnd, NDO_HANDLE_CRC, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
// Use raw send/receive methods
if (!nfc_configure (pnd, NDO_EASY_FRAMING, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
// Disable 14443-4 autoswitching
if (!nfc_configure (pnd, NDO_AUTO_ISO14443_4, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
printf ("Connected to NFC reader: %s\n\n", pnd->acName);
// Send the 7 bits request command specified in ISO 14443A (0x26)
if (!transmit_bits (abtReqa, 7)) {
printf ("Error: No tag available\n");
nfc_disconnect (pnd);
return 1;
}
memcpy (abtAtqa, abtRx, 2);
// Anti-collision
transmit_bytes (abtSelectAll, 2);
// Check answer
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
printf("WARNING: BCC check failed!\n");
}
// Save the UID CL1
memcpy (abtRawUid, abtRx, 4);
//Prepare and send CL1 Select-Command
memcpy (abtSelectTag + 2, abtRx, 5);
iso14443a_crc_append (abtSelectTag, 7);
transmit_bytes (abtSelectTag, 9);
abtSak = abtRx[0];
// Test if we are dealing with a CL2
if (abtSak & CASCADE_BIT) {
szCL = 2;//or more
// Check answer
if (abtRawUid[0] != 0x88) {
printf("WARNING: Cascade bit set but CT != 0x88!\n");
}
}
if(szCL == 2) {
// We have to do the anti-collision for cascade level 2
// Prepare CL2 commands
abtSelectAll[0] = 0x95;
// Anti-collision
transmit_bytes (abtSelectAll, 2);
// Check answer
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
printf("WARNING: BCC check failed!\n");
}
// Save UID CL2
memcpy (abtRawUid + 4, abtRx, 4);
// Selection
abtSelectTag[0] = 0x95;
memcpy (abtSelectTag + 2, abtRx, 5);
iso14443a_crc_append (abtSelectTag, 7);
transmit_bytes (abtSelectTag, 9);
abtSak = abtRx[0];
// Test if we are dealing with a CL3
if (abtSak & CASCADE_BIT) {
szCL = 3;
// Check answer
if (abtRawUid[0] != 0x88) {
printf("WARNING: Cascade bit set but CT != 0x88!\n");
}
}
if ( szCL == 3) {
// We have to do the anti-collision for cascade level 3
// Prepare and send CL3 AC-Command
abtSelectAll[0] = 0x97;
transmit_bytes (abtSelectAll, 2);
// Check answer
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
printf("WARNING: BCC check failed!\n");
}
// Save UID CL3
memcpy (abtRawUid + 8, abtRx, 4);
// Prepare and send final Select-Command
abtSelectTag[0] = 0x97;
memcpy (abtSelectTag + 2, abtRx, 5);
iso14443a_crc_append (abtSelectTag, 7);
transmit_bytes (abtSelectTag, 9);
abtSak = abtRx[0];
}
}
// Request ATS, this only applies to tags that support ISO 14443A-4
if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) {
iso_ats_supported = true;
}
printf ("\nFound tag with\n UID: ");
switch (szCL) {
case 1:
printf ("%02x%02x%02x%02x", abtRawUid[0], abtRawUid[1], abtRawUid[2], abtRawUid[3]);
break;
case 2:
printf ("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]);
printf ("%02x%02x%02x%02x", abtRawUid[4], abtRawUid[5], abtRawUid[6], abtRawUid[7]);
break;
case 3:
printf ("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]);
printf ("%02x%02x%02x", abtRawUid[5], abtRawUid[6], abtRawUid[7]);
printf ("%02x%02x%02x%02x", abtRawUid[8], abtRawUid[9], abtRawUid[10], abtRawUid[11]);
break;
}
printf("\n");
printf("ATQA: %02x%02x\n SAK: %02x\n", abtAtqa[1], abtAtqa[0], abtSak);
if (szAts > 1) { // if = 1, it's not actual ATS but error code
printf(" ATS: ");
print_hex (abtAts, szAts);
}
printf("\n");
// now reset UID
iso14443a_crc_append(abtHalt, 2);
transmit_bytes (abtHalt, 4);
transmit_bits (abtUnlock1,7);
transmit_bytes (abtUnlock2,1);
transmit_bytes (abtWrite,4);
transmit_bytes (abtData,18);
nfc_disconnect (pnd);
return 0;
}