Add CUID card support
This commit is contained in:
parent
b7dbacf5cf
commit
e21e9c6410
@ -37,15 +37,33 @@ option to format the card will reset all keys to FFFFFFFFFFFF, all data to 00 an
|
|||||||
|
|
||||||
The
|
The
|
||||||
.B W
|
.B W
|
||||||
option allows writing of special MIFARE cards that can be 'unlocked' to allow block 0
|
option performs a write operation on special MIFARE Classic cards, that can
|
||||||
to be overwritten. This includes UID and manufacturer data. Take care when amending UIDs to set
|
be 'unlocked' to allow block 0 to be modified ('generation 1 Chinese magic
|
||||||
the correct BCC (UID checksum). Currently only 4 byte UIDs are supported.
|
cards'). Similarly, the
|
||||||
|
|
||||||
Similarly, the
|
|
||||||
.B R
|
.B R
|
||||||
option allows an 'unlocked' read. This bypasses authentication and allows
|
option allows an 'unlocked' read. This bypasses authentication and allows
|
||||||
reading of the Key A and Key B data regardless of ACLs.
|
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.
|
R/W errors on some blocks can be either considered as critical or ignored.
|
||||||
To halt on first error, specify keys with lowercase (
|
To halt on first error, specify keys with lowercase (
|
||||||
.B a
|
.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
|
parameter instead will use whatever libnfc decides which generally is the lowest
|
||||||
UID.
|
UID.
|
||||||
|
|
||||||
*** Note that
|
|
||||||
.B W
|
|
||||||
and
|
|
||||||
.B R
|
|
||||||
options only work on special versions of MIFARE 1K cards (Chinese clones).
|
|
||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
.BR f " | " r " | " R " | " w " | " W
|
.BR f " | " r " | " R " | " w " | " W " | " C
|
||||||
Perform format (
|
Perform format (
|
||||||
.B f
|
.B f
|
||||||
) or read from (
|
) or read from (
|
||||||
.B r
|
.B r
|
||||||
) or unlocked read from (
|
) or unlocked/gen1 read from (
|
||||||
.B R
|
.B R
|
||||||
) or write to (
|
) or write to (
|
||||||
.B w
|
.B w
|
||||||
) or unlocked write to (
|
) or unlocked/gen1 write to (
|
||||||
.B W
|
.B W
|
||||||
|
) or direct/CUID/gen2 write to (
|
||||||
|
C
|
||||||
) card.
|
) card.
|
||||||
.TP
|
.TP
|
||||||
.BR a " | " A " | " b " | " B
|
.BR a " | " A " | " b " | " B
|
||||||
|
|||||||
@ -70,6 +70,7 @@ static bool bForceKeyFile;
|
|||||||
static bool bTolerateFailures;
|
static bool bTolerateFailures;
|
||||||
static bool bFormatCard;
|
static bool bFormatCard;
|
||||||
static bool magic_type2a = false;
|
static bool magic_type2a = false;
|
||||||
|
static bool magic_type2b = false;
|
||||||
static bool unlocked = false;
|
static bool unlocked = false;
|
||||||
static uint8_t uiBlocks;
|
static uint8_t uiBlocks;
|
||||||
static uint8_t keys[] = {
|
static uint8_t keys[] = {
|
||||||
@ -315,7 +316,7 @@ read_card(int read_unlocked)
|
|||||||
if (read_unlocked) {
|
if (read_unlocked) {
|
||||||
//If the user is attempting an unlocked read, but has a direct-write type magic card, they don't
|
//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.
|
//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");
|
printf("Note: This card does not require an unlocked read (R) \n");
|
||||||
read_unlocked = false;
|
read_unlocked = false;
|
||||||
} else {
|
} else {
|
||||||
@ -395,7 +396,7 @@ write_card(bool write_unlocked)
|
|||||||
if (write_unlocked) {
|
if (write_unlocked) {
|
||||||
//If the user is attempting an unlocked write, but has a direct-write type magic card, they don't
|
//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.
|
//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");
|
printf("Note: This card does not require an unlocked write (W) \n");
|
||||||
write_unlocked = false;
|
write_unlocked = false;
|
||||||
} else {
|
} else {
|
||||||
@ -449,7 +450,7 @@ write_card(bool write_unlocked)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The first block 0x00 is read only, skip this
|
// 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;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
@ -476,6 +477,21 @@ write_card(bool write_unlocked)
|
|||||||
print_success_or_failure(bFailure, &uiWriteBlocks);
|
print_success_or_failure(bFailure, &uiWriteBlocks);
|
||||||
if ((!bTolerateFailures) && bFailure)
|
if ((!bTolerateFailures) && bFailure)
|
||||||
return false;
|
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("|\n");
|
||||||
printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
|
printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
|
||||||
@ -495,11 +511,10 @@ print_usage(const char *pcProgramName)
|
|||||||
{
|
{
|
||||||
printf("Usage: ");
|
printf("Usage: ");
|
||||||
printf("%s f|r|R|w|W a|b u|U<01ab23cd> <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|C - Perform format (f) or read from (r) or unlocked/gen1 read from (R) or write to (w) or unlocked/gen1\n");
|
||||||
printf(" *** format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\n");
|
printf(" write to (W) or direct/CUID/gen2 write to (C) card\n");
|
||||||
printf(" *** unlocked read does not require authentication and will reveal A and B keys\n");
|
printf(" *** Options (R), (W) and (C) only work on Chinese magic cards (read manpage to prevent bricking them!)\n");
|
||||||
printf(" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
|
printf(" *** Format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\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(" 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");
|
||||||
@ -547,10 +562,12 @@ main(int argc, const char *argv[])
|
|||||||
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 > 5);
|
bUseKeyFile = (argc > 5);
|
||||||
bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "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, "C") == 0 || strcmp(command, "f") == 0) {
|
||||||
atAction = ACTION_WRITE;
|
atAction = ACTION_WRITE;
|
||||||
if (strcmp(command, "W") == 0)
|
if (strcmp(command, "W") == 0)
|
||||||
unlock = true;
|
unlock = true;
|
||||||
|
if (strcmp(command, "C") == 0)
|
||||||
|
magic_type2b = true;
|
||||||
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]));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user