Unlocked read and format/wipe of special Mifare cards
This commit is contained in:
parent
1a07613ce2
commit
028f310576
4 changed files with 108 additions and 63 deletions
|
@ -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).
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue