diff --git a/utils/nfc-mfclassic.1 b/utils/nfc-mfclassic.1 index 34083c6..0be3871 100644 --- a/utils/nfc-mfclassic.1 +++ b/utils/nfc-mfclassic.1 @@ -5,6 +5,7 @@ nfc-mfclassic \- MIFARE Classic command line tool .B nfc-mfclassic .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\fBu\fR\fR|\fBU\fR<\fBuid\fR>\fR .IR DUMP .RI [ .IR KEYS @@ -56,6 +57,15 @@ or .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 .B W and @@ -90,6 +100,13 @@ Halt on errors ( B ). .TP +.BR u " | " U +Use the default UID ( +.B u +) or supply a valid 4 byte UID ( +.B U +). +.TP .IR DUMP MiFare Dump (MFD) used to write (card to MFD) or (MFD to card) .TP diff --git a/utils/nfc-mfclassic.c b/utils/nfc-mfclassic.c index 333f710..56d5717 100644 --- a/utils/nfc-mfclassic.c +++ b/utils/nfc-mfclassic.c @@ -491,26 +491,29 @@ static void print_usage(const char *pcProgramName) { printf("Usage: "); - printf("%s f|r|R|w|W a|b [ [f]]\n", pcProgramName); + printf("%s f|r|R|w|W a|b u|U<01ab23cd> [ [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(" *** 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(" *** 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(" 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(" - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); printf(" - MiFare Dump (MFD) that contain the keys (optional)\n"); printf(" f - Force using the keyfile even if UID does not match (optional)\n"); printf("Examples: \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(" %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(" %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(" %s f A dummy.mfd keyfile.mfd f\n", pcProgramName); - printf(" %s f B dummy.mfd keyfile.mfd f\n\n", pcProgramName); + printf(" %s f A u dummy.mfd keyfile.mfd f\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 @@ -518,6 +521,9 @@ main(int argc, const char *argv[]) { action_t atAction = ACTION_USAGE; uint8_t *pbtUID; + uint8_t _tag_uid[4]; + uint8_t *tag_uid = _tag_uid; + int unlock = 0; if (argc < 2) { @@ -526,31 +532,45 @@ main(int argc, const char *argv[]) } const char *command = argv[1]; + if (argc < 5) { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } 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'; bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); - bUseKeyFile = (argc > 4); - bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0)); + bUseKeyFile = (argc > 5); + bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "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; if (strcmp(command, "W") == 0) unlock = 1; bFormatCard = (strcmp(command, "f") == 0); bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); - bUseKeyFile = (argc > 4); - bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0)); + bUseKeyFile = (argc > 5); + 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) { @@ -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 if (bUseKeyFile) { - FILE *pfKeys = fopen(argv[4], "rb"); + FILE *pfKeys = fopen(argv[5], "rb"); 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); } 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); exit(EXIT_FAILURE); } @@ -610,7 +630,10 @@ main(int argc, const char *argv[]) printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); // 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"); nfc_close(pnd); 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); if (bUseKeyFile) { - FILE *pfKeys = fopen(argv[4], "rb"); + FILE *pfKeys = fopen(argv[5], "rb"); 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); } 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); exit(EXIT_FAILURE); } @@ -688,16 +711,16 @@ main(int argc, const char *argv[]) if (atAction == ACTION_READ) { memset(&mtDump, 0x00, sizeof(mtDump)); } else { - FILE *pfDump = fopen(argv[3], "rb"); + FILE *pfDump = fopen(argv[4], "rb"); 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); } 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); exit(EXIT_FAILURE); } @@ -707,17 +730,17 @@ main(int argc, const char *argv[]) if (atAction == ACTION_READ) { if (read_card(unlock)) { - printf("Writing data to file: %s ...", argv[3]); + printf("Writing data to file: %s ...", argv[4]); fflush(stdout); - FILE *pfDump = fopen(argv[3], "wb"); + FILE *pfDump = fopen(argv[4], "wb"); 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_exit(context); exit(EXIT_FAILURE); } 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); nfc_close(pnd); nfc_exit(context); diff --git a/utils/nfc-mfultralight.c b/utils/nfc-mfultralight.c index 615833f..4b9f39d 100644 --- a/utils/nfc-mfultralight.c +++ b/utils/nfc-mfultralight.c @@ -58,11 +58,15 @@ #include "nfc-utils.h" #include "mifare.h" +#define MAX_TARGET_COUNT 16 +#define MAX_UID_LEN 10 +#define BLOCK_COUNT 0xf + static nfc_device *pnd; static nfc_target nt; static mifare_param mp; static mifareul_tag mtDump; -static uint32_t uiBlocks = 0xF; +static const uint32_t uiBlocks = BLOCK_COUNT; // special unlock command uint8_t abtUnlock1[1] = { 0x40 }; @@ -180,7 +184,7 @@ unlock_card(void) static bool check_magic() { bool bFailure = false; - int uid_data; + int uid_data; for (uint32_t page = 0; page <= 1; page++) { // Show if the readout went well @@ -194,27 +198,27 @@ static bool check_magic() { } uid_data = 0x00000000; - + memcpy(mp.mpd.abtData, &uid_data, sizeof uid_data); memset(mp.mpd.abtData + 4, 0, 12); - + //Force the write without checking for errors - otherwise the writes to the sector 0 seem to complain nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp); } - + //Check that the ID is now set to 0x000000000000 if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) { //printf("%u", mp.mpd.abtData); bool result = true; for(int i = 0; i <= 7; i++) { if (mp.mpd.abtData[i] != 0x00) result = false; - } + } - if (result) { + if (result) { return true; } - } + } //Initially check if we can unlock via the MF method if (unlock_card()) { @@ -235,7 +239,7 @@ write_card(bool write_otp, bool write_lock, bool write_uid) char buffer[BUFSIZ]; - if (!write_otp) { + if (!write_otp) { printf("Write OTP bytes ? [yN] "); if (!fgets(buffer, BUFSIZ, stdin)) { ERR("Unable to read standard input."); @@ -243,7 +247,7 @@ write_card(bool write_otp, bool write_lock, bool write_uid) write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y')); } - if (!write_lock) { + if (!write_lock) { printf("Write Lock bytes ? [yN] "); if (!fgets(buffer, BUFSIZ, stdin)) { ERR("Unable to read standard input."); @@ -251,7 +255,7 @@ write_card(bool write_otp, bool write_lock, bool write_uid) write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y')); } - if (!write_uid) { + if (!write_uid) { printf("Write UID bytes (only for special writeable UID cards) ? [yN] "); if (!fgets(buffer, BUFSIZ, stdin)) { ERR("Unable to read standard input."); @@ -267,12 +271,12 @@ write_card(bool write_otp, bool write_lock, bool write_uid) } else { if (!check_magic()) { printf("\nUnable to unlock card - are you sure the card is magic?\n"); - return 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)) { printf("s"); uiSkippedPages++; @@ -310,6 +314,57 @@ write_card(bool write_otp, bool write_lock, bool write_uid) 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 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--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--with-uid \t\t - Specify UID to read/write from\n"); } int main(int argc, const char *argv[]) { int iAction = 0; + uint8_t iUID[MAX_UID_LEN] = { 0x0 }; + size_t szUID = 0; bool bOTP = false; bool bLock = false; bool bUID = false; FILE *pfDump; - if (argc == 0) { + if (argc < 2) { print_usage(argv); exit(EXIT_FAILURE); } @@ -345,6 +403,12 @@ main(int argc, const char *argv[]) iAction = 1; } else if (0 == strcmp(argv[arg], "w")) { 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")) { bOTP = true; bLock = true; @@ -359,7 +423,7 @@ main(int argc, const char *argv[]) iAction = 3; } else { //Skip validation of the filename - if (arg != 2) { + if ((arg != 2) && (arg != 4)) { ERR("%s is not supported option.", argv[arg]); print_usage(argv); exit(EXIT_FAILURE); @@ -390,7 +454,7 @@ main(int argc, const char *argv[]) ERR("Unable to determine operating mode"); exit(EXIT_FAILURE); } - + nfc_context *context; nfc_init(&context); if (context == NULL) { @@ -405,6 +469,14 @@ main(int argc, const char *argv[]) nfc_exit(context); 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) { nfc_perror(pnd, "nfc_initiator_init"); @@ -421,10 +493,8 @@ main(int argc, const char *argv[]) exit(EXIT_FAILURE); } - printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); - // 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"); nfc_close(pnd); nfc_exit(context); @@ -439,7 +509,7 @@ main(int argc, const char *argv[]) exit(EXIT_FAILURE); } // Get the info from the current tag - printf("Found MIFARE Ultralight card with UID: "); + printf("Using MIFARE Ultralight card with UID: "); size_t szPos; for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) { printf("%02x", nt.nti.nai.abtUid[szPos]);