Unlocked read and format/wipe of special Mifare cards

This commit is contained in:
Adam Laurie 2011-09-06 21:17:38 +00:00
parent 1a07613ce2
commit 028f310576
4 changed files with 108 additions and 63 deletions

View file

@ -3,7 +3,7 @@
nfc-mfclassic \- MIFARE Classic command line tool
.SH SYNOPSIS
.B nfc-mfclassic
.RI \fR\fBr\fR|\fBw\fR\fR|\fBu\fR
.RI \fR\fBr\fR|\fR\fBR\fR|\fBw\fR\fR|\fBW\fR
.RI \fR\fBa\fR|\fBb\fR
.IR DUMP
.IR [KEYS]
@ -27,18 +27,25 @@ 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
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
The 'W' 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.
Similarly, the 'R' option allows an 'unlocked' read. This bypasses authentication and allows
reading of the Key A and Key B data regardless of ACLs.
*** Note that 'W' and 'R' options only work on special versions of Mifare 1K cards (Chinese clones).
.SH OPTIONS
.BR r " | " w " | " u
.BR r " | " R " | " w " | " W
Perform read from (
.B r
) or unlocked read from (
.B R
) or write to (
.B w
) or unlocked write to (
.B u
.B W
) card.
.TP
.BR a " | " b
@ -65,6 +72,7 @@ are covered by the GNU Lesser General Public License (LGPL), version 3.
Roel Verdult <roel@libnfc.org>
Romuald Conty <romuald@libnfc.org>
Romain Tartière <romain@blogreen.org>
Adam Laurie <adam@algroup.co.uk>
.PP
This manual page was written by Romuald Conty <romuald@libnfc.org>.
It is licensed under the terms of the GNU GPL (version 2 or later).

View file

@ -213,13 +213,60 @@ authenticate (uint32_t uiBlock)
return false;
}
static bool
unlock_card()
{
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);
}
return true;
}
static bool
read_card (void)
read_card (int read_unlocked)
{
int32_t iBlock;
bool bFailure = false;
uint32_t uiReadBlocks = 0;
if(read_unlocked)
if (!unlock_card())
return false;
printf ("Reading out %d blocks |", uiBlocks + 1);
// Read the card from end to begin
@ -243,7 +290,7 @@ read_card (void)
fflush (stdout);
// Try to authenticate for the current sector
if (!authenticate (iBlock)) {
if (!read_unlocked && !authenticate (iBlock)) {
printf ("!\nError: authentication failed for block 0x%02x\n", iBlock);
return false;
}
@ -286,46 +333,9 @@ write_card (int write_block_zero)
uint32_t uiWriteBlocks = 0;
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");
if(write_block_zero)
if (!unlock_card())
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;
@ -418,18 +428,18 @@ typedef enum {
ACTION_READ,
ACTION_WRITE,
ACTION_EXTRACT,
ACTION_USAGE,
ACTION_WRITE_UNLOCKED
ACTION_USAGE
} action_t;
static void
print_usage (const char *pcProgramName)
{
printf ("Usage: ");
printf ("%s r|w|u a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
printf (" r|w|u - Perform read from (r) or write to (w) or unlocked write to (u) card\n");
printf ("%s r|R|w|W a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
printf (" r|R|w|W - Perform read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n");
printf (" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
printf (" *** and only works with special Mifare 1K cards (Chinese clones)\n");
printf (" *** unlocked read does not require authentication and will reveal A and B keys\n");
printf (" *** unlocking only works with special Mifare 1K cards (Chinese clones)\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 (" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
@ -447,6 +457,7 @@ main (int argc, const char *argv[])
byte_t *pbtUID;
FILE *pfKeys = NULL;
FILE *pfDump = NULL;
int unlock= 0;
if (argc < 2) {
print_usage (argv[0]);
@ -454,22 +465,24 @@ main (int argc, const char *argv[])
}
const char *command = argv[1];
if (strcmp (command, "r") == 0) {
if (strcmp (command, "r") == 0 || strcmp (command, "R") == 0) {
if (argc < 4) {
print_usage (argv[0]);
exit (EXIT_FAILURE);
}
atAction = ACTION_READ;
if (strcmp (command, "R") == 0)
unlock= 1;
bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
bUseKeyFile = (argc > 4);
} else if (strcmp (command, "w") == 0 || strcmp (command, "u") == 0) {
} else if (strcmp (command, "w") == 0 || strcmp (command, "W") == 0) {
if (argc < 4) {
print_usage (argv[0]);
exit (EXIT_FAILURE);
}
atAction = ACTION_WRITE;
if (strcmp (command, "u") == 0)
atAction = ACTION_WRITE_UNLOCKED;
if (strcmp (command, "W") == 0)
unlock= 1;
bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
bUseKeyFile = (argc > 4);
} else if (strcmp (command, "x") == 0) {
@ -487,7 +500,6 @@ main (int argc, const char *argv[])
break;
case ACTION_READ:
case ACTION_WRITE:
case ACTION_WRITE_UNLOCKED:
if (bUseKeyFile) {
pfKeys = fopen (argv[4], "rb");
if (pfKeys == NULL) {
@ -580,7 +592,7 @@ main (int argc, const char *argv[])
printf ("Guessing size: seems to be a %i-byte card\n", (uiBlocks + 1) * 16);
if (atAction == ACTION_READ) {
if (read_card ()) {
if (read_card (unlock)) {
printf ("Writing data to file: %s ...", argv[3]);
fflush (stdout);
pfDump = fopen (argv[3], "wb");
@ -596,10 +608,7 @@ main (int argc, const char *argv[])
fclose (pfDump);
}
} else if (atAction == ACTION_WRITE) {
write_card (0);
}
else if (atAction == ACTION_WRITE_UNLOCKED) {
write_card (1);
write_card (unlock);
}
nfc_disconnect (pnd);

View file

@ -3,12 +3,20 @@
nfc-mfsetuid \- MIFARE 1K special card UID setting and recovery tool
.SH SYNOPSIS
.B nfc-mfsetuid
[UID]
.SH DESCRIPTION
.B nfc-mfsetuid
is a MIFARE tool that allows setting of UID on special versions (Chinese clones) of Mifare 1K cards. It will also recover
damaged cards that have had invalid data written to block 0 (e.g. wrong BCC). Currently only 4 Byte UID is supported.
Specify an eight hex character UID or leave blank for the default '01234567'.
.SH OPTIONS
.B -f
Format. Wipe all data (set to 0xFF) and reset ACLs to defaults.
.B -q
Quiet. Suppress output of commands and responses.
.SH BUGS
Please report any bugs on the
.B libnfc

View file

@ -81,8 +81,10 @@ byte_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 };
// special unlock command
byte_t abtUnlock1[1] = { 0x40 };
byte_t abtUnlock2[1] = { 0x43 };
byte_t abtWipe[1] = { 0x41 };
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 };
byte_t abtBlank[18] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x36, 0xCC };
static bool
@ -134,7 +136,8 @@ 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 ("\t-f\tFormat. Delete all data (set to 0xFF) and reset ACLs to default.\n");
printf ("\t-q\tQuiet mode. Suppress output of READER and CARD 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");
@ -144,15 +147,19 @@ print_usage (char *argv[])
int
main (int argc, char *argv[])
{
int arg, i;
int arg, i;
bool format= false;
unsigned int c;
char tmp[3]= { 0x00, 0x00, 0x00 };
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], "-f")) {
format= true;
} else if (0 == strcmp (argv[arg], "-q")) {
quiet_output = true;
} else if (strlen(argv[arg]) == 8) {
@ -322,9 +329,22 @@ main (int argc, char *argv[])
iso14443a_crc_append(abtHalt, 2);
transmit_bytes (abtHalt, 4);
transmit_bits (abtUnlock1,7);
if(format) {
transmit_bytes (abtWipe,1);
transmit_bytes (abtHalt, 4);
transmit_bits (abtUnlock1,7);
}
transmit_bytes (abtUnlock2,1);
transmit_bytes (abtWrite,4);
transmit_bytes (abtData,18);
if(format) {
for(i= 3 ; i < 64 ; i += 4) {
abtWrite[1]= (char) i;
iso14443a_crc_append (abtWrite, 2);
transmit_bytes (abtWrite,4);
transmit_bytes (abtBlank,18);
}
}
nfc_disconnect (pnd);