From e21e9c6410a8dc69e4019d5383098ca6238f1279 Mon Sep 17 00:00:00 2001 From: Hanno Heinrichs Date: Sun, 17 Sep 2017 18:57:22 +0200 Subject: [PATCH] Add CUID card support --- utils/nfc-mfclassic.1 | 42 ++++++++++++++++++++++++++++-------------- utils/nfc-mfclassic.c | 35 ++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/utils/nfc-mfclassic.1 b/utils/nfc-mfclassic.1 index 0be3871..59d0aff 100644 --- a/utils/nfc-mfclassic.1 +++ b/utils/nfc-mfclassic.1 @@ -37,15 +37,33 @@ option to format the card will reset all keys to FFFFFFFFFFFF, all data to 00 an The .B 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 +option performs a write operation on special MIFARE Classic cards, that can +be 'unlocked' to allow block 0 to be modified ('generation 1 Chinese magic +cards'). Similarly, the .B R option allows an 'unlocked' read. This bypasses authentication and allows reading of the Key A and Key B data regardless of ACLs. +The +.B C +option performs a write operation on special MIFARE Classic cards, that allow +block 0 to be modified by the regular write command ('generation 2 Chinese +magic cards'/'CUID direct-write cards'). This type of card does not reply to +the backdoor/unlock command of generation 1 cards and is therefore harder to +detect. + +*** Note that +.B W +, +.B R +and +.B C +options only work on Chinese magic cards (clones of MIFARE Classic cards, that +have a modifiable block 0). Rewriting block 0 allows for modification of +manufacturer data such as the UID. Writing bad manufacturer data into block 0 +(e.g. bad BCC) may permanantly brick a Chinese magic card. Currently, only +4-byte UIDs are supported. + R/W errors on some blocks can be either considered as critical or ignored. To halt on first error, specify keys with lowercase ( .B a @@ -66,25 +84,21 @@ hexadecimal UID to the U option. For example U01ab23cd for the 4 byte UID parameter instead will use whatever libnfc decides which generally is the lowest UID. -*** Note that -.B W -and -.B R -options only work on special versions of MIFARE 1K cards (Chinese clones). - .SH OPTIONS .TP -.BR f " | " r " | " R " | " w " | " W +.BR f " | " r " | " R " | " w " | " W " | " C Perform format ( .B f ) or read from ( .B r -) or unlocked read from ( +) or unlocked/gen1 read from ( .B R ) or write to ( .B w -) or unlocked write to ( +) or unlocked/gen1 write to ( .B W +) or direct/CUID/gen2 write to ( +C ) card. .TP .BR a " | " A " | " b " | " B diff --git a/utils/nfc-mfclassic.c b/utils/nfc-mfclassic.c index ceb54cd..86c9f55 100644 --- a/utils/nfc-mfclassic.c +++ b/utils/nfc-mfclassic.c @@ -70,6 +70,7 @@ static bool bForceKeyFile; static bool bTolerateFailures; static bool bFormatCard; static bool magic_type2a = false; +static bool magic_type2b = false; static bool unlocked = false; static uint8_t uiBlocks; static uint8_t keys[] = { @@ -315,7 +316,7 @@ read_card(int read_unlocked) if (read_unlocked) { //If the user is attempting an unlocked read, but has a direct-write type magic card, they don't //need to use the R mode. We'll trigger a warning and let them proceed. - if (magic_type2a) { + if (magic_type2a || magic_type2b) { printf("Note: This card does not require an unlocked read (R) \n"); read_unlocked = false; } else { @@ -395,7 +396,7 @@ write_card(bool write_unlocked) if (write_unlocked) { //If the user is attempting an unlocked write, but has a direct-write type magic card, they don't //need to use the W mode. We'll trigger a warning and let them proceed. - if (magic_type2a) { + if (magic_type2a || magic_type2b) { printf("Note: This card does not require an unlocked write (W) \n"); write_unlocked = false; } else { @@ -449,7 +450,7 @@ write_card(bool write_unlocked) } } else { // The first block 0x00 is read only, skip this - if (uiBlock == 0 && !write_unlocked && !magic_type2a) + if (uiBlock == 0 && !(write_unlocked || magic_type2a || magic_type2b)) continue; @@ -476,6 +477,21 @@ write_card(bool write_unlocked) print_success_or_failure(bFailure, &uiWriteBlocks); if ((!bTolerateFailures) && bFailure) return false; + if (uiBlock == 0 && magic_type2b) + { + // CUID card must be selected again after writing of block0 + if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { + printf("Error: tag disappeared after writing block 0\n"); + nfc_close(pnd); + nfc_exit(context); + exit(EXIT_FAILURE); + } + // Re-authenticate to sector 0 for writing of remaining blocks + if (!authenticate(uiBlock)) { + printf("!\nError: re-authentication failed for block %02x\n", uiBlock); + return false; + } + } } printf("|\n"); printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1); @@ -495,11 +511,10 @@ print_usage(const char *pcProgramName) { printf("Usage: "); 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(" f|r|R|w|W|C - Perform format (f) or read from (r) or unlocked/gen1 read from (R) or write to (w) or unlocked/gen1\n"); + printf(" write to (W) or direct/CUID/gen2 write to (C) card\n"); + printf(" *** Options (R), (W) and (C) only work on Chinese magic cards (read manpage to prevent bricking them!)\n"); + printf(" *** Format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\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"); @@ -547,10 +562,12 @@ main(int argc, const char *argv[]) bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); 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) { + } else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "C") == 0 || strcmp(command, "f") == 0) { atAction = ACTION_WRITE; if (strcmp(command, "W") == 0) unlock = true; + if (strcmp(command, "C") == 0) + magic_type2b = true; 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]));