Merge pull request #350 from oliv3r/master

Allow mfultralight and mfc tools to work also with specific UID's
This commit is contained in:
Romuald Conty 2016-05-15 11:48:39 +02:00
commit 403650a0fc
3 changed files with 162 additions and 52 deletions

View file

@ -5,6 +5,7 @@ nfc-mfclassic \- MIFARE Classic command line tool
.B nfc-mfclassic .B nfc-mfclassic
.RI \fR\fBf\fR|\fR\fBr\fR|\fR\fBR\fR|\fBw\fR\fR|\fBW\fR .RI \fR\fBf\fR|\fR\fBr\fR|\fR\fBR\fR|\fBw\fR\fR|\fBW\fR
.RI \fR\fBa\fR|\fR\fBA\fR|\fBb\fR\fR|\fBB\fR .RI \fR\fBa\fR|\fR\fBA\fR|\fBb\fR\fR|\fBB\fR
.RI \fR\fBu\fR\fR|\fBU\fR<\fBuid\fR>\fR
.IR DUMP .IR DUMP
.RI [ .RI [
.IR KEYS .IR KEYS
@ -56,6 +57,15 @@ or
.B B .B B
). ).
When using multiple tags infront of a reader, the
.B U
option can be used to supply the UID of tag to be read or written. Append the
hexadecimal UID to the U option. For example U01ab23cd for the 4 byte UID
0x01 0xab 0x23 0xcd. Using the
.B u
parameter instead will use whatever libnfc decides which generally is the lowest
UID.
*** Note that *** Note that
.B W .B W
and and
@ -90,6 +100,13 @@ Halt on errors (
B B
). ).
.TP .TP
.BR u " | " U
Use the default UID (
.B u
) or supply a valid 4 byte UID (
.B U<uid>
).
.TP
.IR DUMP .IR DUMP
MiFare Dump (MFD) used to write (card to MFD) or (MFD to card) MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)
.TP .TP

View file

@ -491,26 +491,29 @@ static void
print_usage(const char *pcProgramName) print_usage(const char *pcProgramName)
{ {
printf("Usage: "); printf("Usage: ");
printf("%s f|r|R|w|W a|b <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName); printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName);
printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n"); printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n");
printf(" *** format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\n"); printf(" *** format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\n");
printf(" *** unlocked read does not require authentication and will reveal A and B keys\n"); printf(" *** unlocked read does not require authentication and will reveal A and B keys\n");
printf(" *** note that unlocked write will attempt to overwrite block 0 including UID\n"); printf(" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
printf(" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n"); printf(" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n");
printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n"); printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n");
printf(" u|U - Use any (u) uid or supply a uid specifically as U01ab23cd.\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");
printf(" f - Force using the keyfile even if UID does not match (optional)\n"); printf(" f - Force using the keyfile even if UID does not match (optional)\n");
printf("Examples: \n\n"); printf("Examples: \n\n");
printf(" Read card to file, using key A:\n\n"); printf(" Read card to file, using key A:\n\n");
printf(" %s r a mycard.mfd\n\n", pcProgramName); printf(" %s r a u mycard.mfd\n\n", pcProgramName);
printf(" Write file to blank card, using key A:\n\n"); printf(" Write file to blank card, using key A:\n\n");
printf(" %s w a mycard.mfd\n\n", pcProgramName); printf(" %s w a u mycard.mfd\n\n", pcProgramName);
printf(" Write new data and/or keys to previously written card, using key A:\n\n"); printf(" Write new data and/or keys to previously written card, using key A:\n\n");
printf(" %s w a newdata.mfd mycard.mfd\n\n", pcProgramName); printf(" %s w a u newdata.mfd mycard.mfd\n\n", pcProgramName);
printf(" Format/wipe card (note two passes required to ensure writes for all ACL cases):\n\n"); printf(" Format/wipe card (note two passes required to ensure writes for all ACL cases):\n\n");
printf(" %s f A dummy.mfd keyfile.mfd f\n", pcProgramName); printf(" %s f A u dummy.mfd keyfile.mfd f\n", pcProgramName);
printf(" %s f B dummy.mfd keyfile.mfd f\n\n", pcProgramName); printf(" %s f B u dummy.mfd keyfile.mfd f\n\n", pcProgramName);
printf(" Read card to file, using key A and uid 0x01 0xab 0x23 0xcd:\n\n");
printf(" %s r a U01ab23cd mycard.mfd\n\n", pcProgramName);
} }
int int
@ -518,6 +521,9 @@ main(int argc, const char *argv[])
{ {
action_t atAction = ACTION_USAGE; action_t atAction = ACTION_USAGE;
uint8_t *pbtUID; uint8_t *pbtUID;
uint8_t _tag_uid[4];
uint8_t *tag_uid = _tag_uid;
int unlock = 0; int unlock = 0;
if (argc < 2) { if (argc < 2) {
@ -526,31 +532,45 @@ main(int argc, const char *argv[])
} }
const char *command = argv[1]; const char *command = argv[1];
if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) { if (argc < 5) {
if (argc < 4) {
print_usage(argv[0]); print_usage(argv[0]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) {
atAction = ACTION_READ; atAction = ACTION_READ;
if (strcmp(command, "R") == 0) if (strcmp(command, "R") == 0)
unlock = 1; unlock = 1;
bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
bUseKeyFile = (argc > 4); bUseKeyFile = (argc > 5);
bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0)); bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
} else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) { } else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) {
if (argc < 4) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
atAction = ACTION_WRITE; atAction = ACTION_WRITE;
if (strcmp(command, "W") == 0) if (strcmp(command, "W") == 0)
unlock = 1; unlock = 1;
bFormatCard = (strcmp(command, "f") == 0); bFormatCard = (strcmp(command, "f") == 0);
bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
bUseKeyFile = (argc > 4); bUseKeyFile = (argc > 5);
bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0)); bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
}
if (argv[3][0] == 'U') {
unsigned long int _uid;
if (strlen(argv[3]) != 9) {
printf("Error, illegal tag specification, use U01ab23cd for example.\n");
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
_uid = strtoul(argv[3] + 1, NULL, 16);
tag_uid[0] = (_uid & 0xff000000UL) >> 24;
tag_uid[1] = (_uid & 0x00ff0000UL) >> 16;
tag_uid[2] = (_uid & 0x0000ff00UL) >> 8;
tag_uid[3] = (_uid & 0x000000ffUL);
printf("Attempting to use specific UID: 0x%2x 0x%2x 0x%2x 0x%2x\n",
tag_uid[0], tag_uid[1], tag_uid[2], tag_uid[3]);
} else {
tag_uid = NULL;
} }
if (atAction == ACTION_USAGE) { if (atAction == ACTION_USAGE) {
@ -559,13 +579,13 @@ main(int argc, const char *argv[])
} }
// We don't know yet the card size so let's read only the UID from the keyfile for the moment // We don't know yet the card size so let's read only the UID from the keyfile for the moment
if (bUseKeyFile) { if (bUseKeyFile) {
FILE *pfKeys = fopen(argv[4], "rb"); FILE *pfKeys = fopen(argv[5], "rb");
if (pfKeys == NULL) { if (pfKeys == NULL) {
printf("Could not open keys file: %s\n", argv[4]); printf("Could not open keys file: %s\n", argv[5]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (fread(&mtKeys, 1, 4, pfKeys) != 4) { if (fread(&mtKeys, 1, 4, pfKeys) != 4) {
printf("Could not read UID from key file: %s\n", argv[4]); printf("Could not read UID from key file: %s\n", argv[5]);
fclose(pfKeys); fclose(pfKeys);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -610,7 +630,10 @@ main(int argc, const char *argv[])
printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));
// Try to find a MIFARE Classic tag // Try to find a MIFARE Classic tag
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { int tags;
tags = nfc_initiator_select_passive_target(pnd, nmMifare, tag_uid, tag_uid == NULL ? 0 : 4, &nt);
if (tags <= 0) {
printf("Error: no tag was found\n"); printf("Error: no tag was found\n");
nfc_close(pnd); nfc_close(pnd);
nfc_exit(context); nfc_exit(context);
@ -672,13 +695,13 @@ main(int argc, const char *argv[])
printf("Guessing size: seems to be a %i-byte card\n", (uiBlocks + 1) * 16); printf("Guessing size: seems to be a %i-byte card\n", (uiBlocks + 1) * 16);
if (bUseKeyFile) { if (bUseKeyFile) {
FILE *pfKeys = fopen(argv[4], "rb"); FILE *pfKeys = fopen(argv[5], "rb");
if (pfKeys == NULL) { if (pfKeys == NULL) {
printf("Could not open keys file: %s\n", argv[4]); printf("Could not open keys file: %s\n", argv[5]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (fread(&mtKeys, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfKeys) != (uiBlocks + 1) * sizeof(mifare_classic_block)) { if (fread(&mtKeys, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfKeys) != (uiBlocks + 1) * sizeof(mifare_classic_block)) {
printf("Could not read keys file: %s\n", argv[4]); printf("Could not read keys file: %s\n", argv[5]);
fclose(pfKeys); fclose(pfKeys);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -688,16 +711,16 @@ main(int argc, const char *argv[])
if (atAction == ACTION_READ) { if (atAction == ACTION_READ) {
memset(&mtDump, 0x00, sizeof(mtDump)); memset(&mtDump, 0x00, sizeof(mtDump));
} else { } else {
FILE *pfDump = fopen(argv[3], "rb"); FILE *pfDump = fopen(argv[4], "rb");
if (pfDump == NULL) { if (pfDump == NULL) {
printf("Could not open dump file: %s\n", argv[3]); printf("Could not open dump file: %s\n", argv[4]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (fread(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != (uiBlocks + 1) * sizeof(mifare_classic_block)) { if (fread(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != (uiBlocks + 1) * sizeof(mifare_classic_block)) {
printf("Could not read dump file: %s\n", argv[3]); printf("Could not read dump file: %s\n", argv[4]);
fclose(pfDump); fclose(pfDump);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -707,17 +730,17 @@ main(int argc, const char *argv[])
if (atAction == ACTION_READ) { if (atAction == ACTION_READ) {
if (read_card(unlock)) { if (read_card(unlock)) {
printf("Writing data to file: %s ...", argv[3]); printf("Writing data to file: %s ...", argv[4]);
fflush(stdout); fflush(stdout);
FILE *pfDump = fopen(argv[3], "wb"); FILE *pfDump = fopen(argv[4], "wb");
if (pfDump == NULL) { if (pfDump == NULL) {
printf("Could not open dump file: %s\n", argv[3]); printf("Could not open dump file: %s\n", argv[4]);
nfc_close(pnd); nfc_close(pnd);
nfc_exit(context); nfc_exit(context);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (fwrite(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != ((uiBlocks + 1) * sizeof(mifare_classic_block))) { if (fwrite(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != ((uiBlocks + 1) * sizeof(mifare_classic_block))) {
printf("\nCould not write to file: %s\n", argv[3]); printf("\nCould not write to file: %s\n", argv[4]);
fclose(pfDump); fclose(pfDump);
nfc_close(pnd); nfc_close(pnd);
nfc_exit(context); nfc_exit(context);

View file

@ -58,11 +58,15 @@
#include "nfc-utils.h" #include "nfc-utils.h"
#include "mifare.h" #include "mifare.h"
#define MAX_TARGET_COUNT 16
#define MAX_UID_LEN 10
#define BLOCK_COUNT 0xf
static nfc_device *pnd; static nfc_device *pnd;
static nfc_target nt; static nfc_target nt;
static mifare_param mp; static mifare_param mp;
static mifareul_tag mtDump; static mifareul_tag mtDump;
static uint32_t uiBlocks = 0xF; static const uint32_t uiBlocks = BLOCK_COUNT;
// special unlock command // special unlock command
uint8_t abtUnlock1[1] = { 0x40 }; uint8_t abtUnlock1[1] = { 0x40 };
@ -267,12 +271,12 @@ write_card(bool write_otp, bool write_lock, bool write_uid)
} else { } else {
if (!check_magic()) { if (!check_magic()) {
printf("\nUnable to unlock card - are you sure the card is magic?\n"); printf("\nUnable to unlock card - are you sure the card is magic?\n");
return false;
bFailure = false; bFailure = false;
return false;
} }
} }
for (int page = uiSkippedPages; page <= 0xF; page++) { for (uint32_t page = uiSkippedPages; page <= ((uiBlocks / 4) * 4); page++) {
if ((page == 0x2) && (!write_lock)) { if ((page == 0x2) && (!write_lock)) {
printf("s"); printf("s");
uiSkippedPages++; uiSkippedPages++;
@ -310,6 +314,57 @@ write_card(bool write_otp, bool write_lock, bool write_uid)
return true; return true;
} }
static int list_passive_targets(nfc_device *_pnd)
{
int res = 0;
nfc_target ant[MAX_TARGET_COUNT];
if (nfc_initiator_init(_pnd) < 0) {
return -EXIT_FAILURE;
}
if ((res = nfc_initiator_list_passive_targets(_pnd, nmMifare, ant, MAX_TARGET_COUNT)) >= 0) {
int i;
if (res > 0)
printf("%d ISO14443A passive target(s) found:\n", res);
for (i = 0; i < res; i++) {
size_t szPos;
printf("\t");
for (szPos = 0; szPos < ant[i].nti.nai.szUidLen; szPos++) {
printf("%02x", ant[i].nti.nai.abtUid[szPos]);
}
printf("\n");
}
}
return 0;
}
static size_t str_to_uid(const char *str, uint8_t *uid)
{
uint8_t i;
memset(uid, 0x0, MAX_UID_LEN);
i = 0;
while ((*str != '\0') && ((i >> 1) < MAX_UID_LEN) ) {
char nibble[2] = { 0x00, '\n' }; /* for strtol */
nibble[0] = *str++;
if (isxdigit(nibble[0])) {
if (isupper(nibble[0]))
nibble[0] = tolower(nibble[0]);
uid[i >> 1] |= strtol(nibble, NULL, 16) << ((i % 2) ? 0 : 4) & ((i % 2) ? 0x0f : 0xf0);
i++;
}
}
return i >> 1;
}
static void static void
print_usage(const char *argv[]) print_usage(const char *argv[])
{ {
@ -321,18 +376,21 @@ print_usage(const char *argv[])
printf("\t--lock\t\t - Don't prompt for Lockbit writing (Assume yes)\n"); printf("\t--lock\t\t - Don't prompt for Lockbit writing (Assume yes)\n");
printf("\t--uid\t\t - Don't prompt for UID writing (Assume yes)\n"); printf("\t--uid\t\t - Don't prompt for UID writing (Assume yes)\n");
printf("\t--full\t\t - Assume full card write (UID + OTP + Lockbit)\n"); printf("\t--full\t\t - Assume full card write (UID + OTP + Lockbit)\n");
printf("\t--with-uid <UID>\t\t - Specify UID to read/write from\n");
} }
int int
main(int argc, const char *argv[]) main(int argc, const char *argv[])
{ {
int iAction = 0; int iAction = 0;
uint8_t iUID[MAX_UID_LEN] = { 0x0 };
size_t szUID = 0;
bool bOTP = false; bool bOTP = false;
bool bLock = false; bool bLock = false;
bool bUID = false; bool bUID = false;
FILE *pfDump; FILE *pfDump;
if (argc == 0) { if (argc < 2) {
print_usage(argv); print_usage(argv);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -345,6 +403,12 @@ main(int argc, const char *argv[])
iAction = 1; iAction = 1;
} else if (0 == strcmp(argv[arg], "w")) { } else if (0 == strcmp(argv[arg], "w")) {
iAction = 2; iAction = 2;
} else if (0 == strcmp(argv[arg], "--with-uid")) {
if (argc < 5) {
ERR("Please supply a UID of 4, 7 or 10 bytes long. Ex: a1:b2:c3:d4");
exit(EXIT_FAILURE);
}
szUID = str_to_uid(argv[4], iUID);
} else if (0 == strcmp(argv[arg], "--full")) { } else if (0 == strcmp(argv[arg], "--full")) {
bOTP = true; bOTP = true;
bLock = true; bLock = true;
@ -359,7 +423,7 @@ main(int argc, const char *argv[])
iAction = 3; iAction = 3;
} else { } else {
//Skip validation of the filename //Skip validation of the filename
if (arg != 2) { if ((arg != 2) && (arg != 4)) {
ERR("%s is not supported option.", argv[arg]); ERR("%s is not supported option.", argv[arg]);
print_usage(argv); print_usage(argv);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -405,6 +469,14 @@ main(int argc, const char *argv[])
nfc_exit(context); nfc_exit(context);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("NFC device: %s opened\n", nfc_device_get_name(pnd));
if (list_passive_targets(pnd)) {
nfc_perror(pnd, "nfc_device_set_property_bool");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
if (nfc_initiator_init(pnd) < 0) { if (nfc_initiator_init(pnd) < 0) {
nfc_perror(pnd, "nfc_initiator_init"); nfc_perror(pnd, "nfc_initiator_init");
@ -421,10 +493,8 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("NFC device: %s opened\n", nfc_device_get_name(pnd));
// Try to find a MIFARE Ultralight tag // Try to find a MIFARE Ultralight tag
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { if (nfc_initiator_select_passive_target(pnd, nmMifare, (szUID) ? iUID : NULL, szUID, &nt) <= 0) {
ERR("no tag was found\n"); ERR("no tag was found\n");
nfc_close(pnd); nfc_close(pnd);
nfc_exit(context); nfc_exit(context);
@ -439,7 +509,7 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Get the info from the current tag // Get the info from the current tag
printf("Found MIFARE Ultralight card with UID: "); printf("Using MIFARE Ultralight card with UID: ");
size_t szPos; size_t szPos;
for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) { for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) {
printf("%02x", nt.nti.nai.abtUid[szPos]); printf("%02x", nt.nti.nai.abtUid[szPos]);