mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-23 06:25:28 -07:00
Merge b596441c5c
into 8cf533fd98
This commit is contained in:
commit
d015bd7b61
6 changed files with 329 additions and 158 deletions
|
@ -1214,13 +1214,14 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
|
||||||
if (workFlags & 0x01) {
|
if (workFlags & 0x01) {
|
||||||
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
|
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
|
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||||
break;
|
// Continue, if we set wrong UID or wrong UID checksum or some ATQA or SAK we will can't select card. But we need to write block 0 to make card work.
|
||||||
|
//break;
|
||||||
};
|
};
|
||||||
|
|
||||||
if(mifare_classic_halt(NULL, cuid)) {
|
if(mifare_classic_halt(NULL, cuid)) {
|
||||||
if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
|
if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
|
||||||
// Continue, some magic tags misbehavies and send an answer to it.
|
// Continue, some magic tags misbehavies and send an answer to it.
|
||||||
// break;
|
// break;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
293
client/cmdhfmf.c
293
client/cmdhfmf.c
|
@ -516,6 +516,7 @@ typedef struct {
|
||||||
} sector_t;
|
} sector_t;
|
||||||
|
|
||||||
|
|
||||||
|
# define NESTED_KEY_COUNT 15
|
||||||
int CmdHF14AMfNested(const char *Cmd)
|
int CmdHF14AMfNested(const char *Cmd)
|
||||||
{
|
{
|
||||||
int i, j, res, iterations;
|
int i, j, res, iterations;
|
||||||
|
@ -526,10 +527,12 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
uint8_t trgKeyType = 0;
|
uint8_t trgKeyType = 0;
|
||||||
uint8_t SectorsCnt = 0;
|
uint8_t SectorsCnt = 0;
|
||||||
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
|
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
|
||||||
uint8_t keyBlock[14*6];
|
uint8_t keyBlock[NESTED_KEY_COUNT * 6];
|
||||||
uint64_t key64 = 0;
|
uint64_t key64 = 0;
|
||||||
bool transferToEml = false;
|
|
||||||
|
|
||||||
|
bool autosearchKey = false;
|
||||||
|
|
||||||
|
bool transferToEml = false;
|
||||||
bool createDumpFile = false;
|
bool createDumpFile = false;
|
||||||
FILE *fkeys;
|
FILE *fkeys;
|
||||||
uint8_t standart[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
uint8_t standart[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
@ -542,63 +545,82 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
PrintAndLog(" all sectors: hf mf nested <card memory> <block number> <key A/B> <key (12 hex symbols)> [t,d]");
|
PrintAndLog(" all sectors: hf mf nested <card memory> <block number> <key A/B> <key (12 hex symbols)> [t,d]");
|
||||||
PrintAndLog(" one sector: hf mf nested o <block number> <key A/B> <key (12 hex symbols)>");
|
PrintAndLog(" one sector: hf mf nested o <block number> <key A/B> <key (12 hex symbols)>");
|
||||||
PrintAndLog(" <target block number> <target key A/B> [t]");
|
PrintAndLog(" <target block number> <target key A/B> [t]");
|
||||||
|
PrintAndLog(" all sectors autosearch key: hf mf nested <card memory> * [t,d]");
|
||||||
|
PrintAndLog(" ");
|
||||||
PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");
|
PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");
|
||||||
PrintAndLog("t - transfer keys into emulator memory");
|
PrintAndLog("t - transfer keys to emulator memory");
|
||||||
PrintAndLog("d - write keys to binary file");
|
PrintAndLog("d - write keys to binary file dumpkeys.bin");
|
||||||
PrintAndLog(" ");
|
PrintAndLog(" ");
|
||||||
PrintAndLog(" sample1: hf mf nested 1 0 A FFFFFFFFFFFF ");
|
PrintAndLog(" sample1: hf mf nested 1 0 A FFFFFFFFFFFF ");
|
||||||
PrintAndLog(" sample2: hf mf nested 1 0 A FFFFFFFFFFFF t ");
|
PrintAndLog(" sample2: hf mf nested 1 0 A FFFFFFFFFFFF t ");
|
||||||
PrintAndLog(" sample3: hf mf nested 1 0 A FFFFFFFFFFFF d ");
|
PrintAndLog(" sample3: hf mf nested 1 0 A FFFFFFFFFFFF d ");
|
||||||
PrintAndLog(" sample4: hf mf nested o 0 A FFFFFFFFFFFF 4 A");
|
PrintAndLog(" sample4: hf mf nested o 0 A FFFFFFFFFFFF 4 A");
|
||||||
|
PrintAndLog(" sample5: hf mf nested 1 * t");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdp = param_getchar(Cmd, 0);
|
cmdp = param_getchar(Cmd, 0);
|
||||||
blockNo = param_get8(Cmd, 1);
|
switch (cmdp) {
|
||||||
ctmp = param_getchar(Cmd, 2);
|
case 'o':
|
||||||
|
case 'O':
|
||||||
|
cmdp = 'o';
|
||||||
|
trgBlockNo = param_get8(Cmd, 4);
|
||||||
|
|
||||||
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
|
ctmp = param_getchar(Cmd, 5);
|
||||||
PrintAndLog("Key type must be A or B");
|
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
|
||||||
return 1;
|
PrintAndLog("Target key type must be A or B");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (ctmp != 'A' && ctmp != 'a')
|
||||||
|
trgKeyType = 1;
|
||||||
|
break;
|
||||||
|
case '0': SectorsCnt = 05; break;
|
||||||
|
case '1': SectorsCnt = 16; break;
|
||||||
|
case '2': SectorsCnt = 32; break;
|
||||||
|
case '4': SectorsCnt = 40; break;
|
||||||
|
default: SectorsCnt = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctmp != 'A' && ctmp != 'a')
|
if (param_getchar(Cmd, 1) == '*') {
|
||||||
keyType = 1;
|
autosearchKey = true;
|
||||||
|
|
||||||
if (param_gethex(Cmd, 3, key, 12)) {
|
ctmp = param_getchar(Cmd, 2);
|
||||||
PrintAndLog("Key must include 12 HEX symbols");
|
transferToEml |= (ctmp == 't' || ctmp == 'T');
|
||||||
return 1;
|
createDumpFile |= (ctmp == 'd' || ctmp == 'D');
|
||||||
}
|
} else {
|
||||||
|
blockNo = param_get8(Cmd, 1);
|
||||||
|
|
||||||
if (cmdp == 'o' || cmdp == 'O') {
|
ctmp = param_getchar(Cmd, 2);
|
||||||
cmdp = 'o';
|
|
||||||
trgBlockNo = param_get8(Cmd, 4);
|
|
||||||
ctmp = param_getchar(Cmd, 5);
|
|
||||||
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
|
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
|
||||||
PrintAndLog("Target key type must be A or B");
|
PrintAndLog("Key type must be A or B");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (ctmp != 'A' && ctmp != 'a')
|
|
||||||
trgKeyType = 1;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
switch (cmdp) {
|
if (ctmp != 'A' && ctmp != 'a')
|
||||||
case '0': SectorsCnt = 05; break;
|
keyType = 1;
|
||||||
case '1': SectorsCnt = 16; break;
|
|
||||||
case '2': SectorsCnt = 32; break;
|
if (param_gethex(Cmd, 3, key, 12)) {
|
||||||
case '4': SectorsCnt = 40; break;
|
PrintAndLog("Key must include 12 HEX symbols");
|
||||||
default: SectorsCnt = 16;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctmp = param_getchar(Cmd, 4);
|
||||||
|
transferToEml |= (ctmp == 't' || ctmp == 'T');
|
||||||
|
createDumpFile |= (ctmp == 'd' || ctmp == 'D');
|
||||||
|
|
||||||
|
ctmp = param_getchar(Cmd, 6);
|
||||||
|
transferToEml |= (ctmp == 't' || ctmp == 'T');
|
||||||
|
createDumpFile |= (ctmp == 'd' || ctmp == 'D');
|
||||||
|
|
||||||
|
// check if we can authenticate to sector
|
||||||
|
res = mfCheckKeys(blockNo, keyType, true, 1, key, &key64);
|
||||||
|
if (res) {
|
||||||
|
PrintAndLog("Can't authenticate to block:%3d key type:%c key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6));
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctmp = param_getchar(Cmd, 4);
|
// one-sector nested
|
||||||
if (ctmp == 't' || ctmp == 'T') transferToEml = true;
|
|
||||||
else if (ctmp == 'd' || ctmp == 'D') createDumpFile = true;
|
|
||||||
|
|
||||||
ctmp = param_getchar(Cmd, 6);
|
|
||||||
transferToEml |= (ctmp == 't' || ctmp == 'T');
|
|
||||||
transferToEml |= (ctmp == 'd' || ctmp == 'D');
|
|
||||||
|
|
||||||
if (cmdp == 'o') {
|
if (cmdp == 'o') {
|
||||||
PrintAndLog("--target block no:%3d, target key type:%c ", trgBlockNo, trgKeyType?'B':'A');
|
PrintAndLog("--target block no:%3d, target key type:%c ", trgBlockNo, trgKeyType?'B':'A');
|
||||||
int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true);
|
int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true);
|
||||||
|
@ -630,6 +652,7 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
else
|
else
|
||||||
num_to_bytes(key64, 6, &keyBlock[10]);
|
num_to_bytes(key64, 6, &keyBlock[10]);
|
||||||
mfEmlSetMem(keyBlock, sectortrailer, 1);
|
mfEmlSetMem(keyBlock, sectortrailer, 1);
|
||||||
|
PrintAndLog("Key transferred to emulator memory.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLog("No valid key found");
|
PrintAndLog("No valid key found");
|
||||||
|
@ -657,13 +680,14 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
num_to_bytes(0xa0478cc39091, 6, (uint8_t*)(keyBlock + 11 * 6));
|
num_to_bytes(0xa0478cc39091, 6, (uint8_t*)(keyBlock + 11 * 6));
|
||||||
num_to_bytes(0x533cb6c723f6, 6, (uint8_t*)(keyBlock + 12 * 6));
|
num_to_bytes(0x533cb6c723f6, 6, (uint8_t*)(keyBlock + 12 * 6));
|
||||||
num_to_bytes(0x8fd0a4f256e9, 6, (uint8_t*)(keyBlock + 13 * 6));
|
num_to_bytes(0x8fd0a4f256e9, 6, (uint8_t*)(keyBlock + 13 * 6));
|
||||||
|
num_to_bytes(0x1a2b3c4d5e6f, 6, (uint8_t*)(keyBlock + 14 * 6));
|
||||||
|
|
||||||
PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt);
|
PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt);
|
||||||
for (i = 0; i < SectorsCnt; i++) {
|
for (i = 0; i < SectorsCnt; i++) {
|
||||||
for (j = 0; j < 2; j++) {
|
for (j = 0; j < 2; j++) {
|
||||||
if (e_sector[i].foundKey[j]) continue;
|
if (e_sector[i].foundKey[j]) continue;
|
||||||
|
|
||||||
res = mfCheckKeys(FirstBlockOfSector(i), j, true, 6, keyBlock, &key64);
|
res = mfCheckKeys(FirstBlockOfSector(i), j, true, NESTED_KEY_COUNT, keyBlock, &key64);
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
e_sector[i].Key[j] = key64;
|
e_sector[i].Key[j] = key64;
|
||||||
|
@ -672,6 +696,32 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get known key from array
|
||||||
|
bool keyFound = false;
|
||||||
|
if (autosearchKey) {
|
||||||
|
for (i = 0; i < SectorsCnt; i++) {
|
||||||
|
for (j = 0; j < 2; j++) {
|
||||||
|
if (e_sector[i].foundKey[j]) {
|
||||||
|
// get known key
|
||||||
|
blockNo = i * 4;
|
||||||
|
keyType = j;
|
||||||
|
num_to_bytes(e_sector[i].Key[j], 6, key);
|
||||||
|
|
||||||
|
keyFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keyFound) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't found a key....
|
||||||
|
if (!keyFound) {
|
||||||
|
PrintAndLog("Can't found any of the known keys.");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
PrintAndLog("--auto key. block no:%3d, key type:%c key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6));
|
||||||
|
}
|
||||||
|
|
||||||
// nested sectors
|
// nested sectors
|
||||||
iterations = 0;
|
iterations = 0;
|
||||||
PrintAndLog("nested...");
|
PrintAndLog("nested...");
|
||||||
|
@ -707,10 +757,71 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Time in nested: %1.3f (%1.3f sec per key)\n\n", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0);
|
// print nested statistic
|
||||||
|
PrintAndLog("\n\n-----------------------------------------------\nNested statistic:\nIterations count: %d", iterations);
|
||||||
|
PrintAndLog("Time in nested: %1.3f (%1.3f sec per key)", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0);
|
||||||
|
|
||||||
PrintAndLog("-----------------------------------------------\nIterations count: %d\n\n", iterations);
|
// check if we have unrecognized keys
|
||||||
//print them
|
bool notFoundKeys = false;
|
||||||
|
for (i = 0; i < SectorsCnt; i++) {
|
||||||
|
for (j = 0; j < 2; j++) {
|
||||||
|
if (!e_sector[i].foundKey[j]) {
|
||||||
|
notFoundKeys = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notFoundKeys) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notFoundKeys) {
|
||||||
|
PrintAndLog("-----------------------------------------------\n");
|
||||||
|
PrintAndLog("We have unrecognized keys. Trying to check if we have this keys on key buffer...");
|
||||||
|
|
||||||
|
// fill keyBlock with known keys
|
||||||
|
int cnt = 0;
|
||||||
|
for (i = 0; i < SectorsCnt; i++) {
|
||||||
|
for (j = 0; j < 2; j++) {
|
||||||
|
if (e_sector[i].foundKey[j]) {
|
||||||
|
// try to insert key to keyBlock
|
||||||
|
if (cnt < NESTED_KEY_COUNT) {
|
||||||
|
|
||||||
|
// search for dublicates
|
||||||
|
bool dubl = false;
|
||||||
|
for (int v = 0; v < NESTED_KEY_COUNT; v++) {
|
||||||
|
if (e_sector[i].Key[j] == bytes_to_num((uint8_t*)(keyBlock + v * 6), 6)) {
|
||||||
|
dubl = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert
|
||||||
|
if (!dubl) {
|
||||||
|
num_to_bytes(e_sector[i].Key[j], 6, (uint8_t*)(keyBlock + cnt * 6));
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to auth with known keys to not recognized sectors keys
|
||||||
|
PrintAndLog("Testing keys. Sector count=%d known keys count:%d", SectorsCnt, cnt);
|
||||||
|
for (i = 0; i < SectorsCnt; i++) {
|
||||||
|
for (j = 0; j < 2; j++) {
|
||||||
|
if (e_sector[i].foundKey[j]) continue;
|
||||||
|
|
||||||
|
res = mfCheckKeys(FirstBlockOfSector(i), j, true, cnt, keyBlock, &key64);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
e_sector[i].Key[j] = key64;
|
||||||
|
e_sector[i].foundKey[j] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // if (notFoundKeys)
|
||||||
|
|
||||||
|
// print result
|
||||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||||
PrintAndLog("|sec|key A |res|key B |res|");
|
PrintAndLog("|sec|key A |res|key B |res|");
|
||||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||||
|
@ -720,7 +831,7 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
}
|
}
|
||||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||||
|
|
||||||
// transfer them to the emulator
|
// transfer keys to the emulator memory
|
||||||
if (transferToEml) {
|
if (transferToEml) {
|
||||||
for (i = 0; i < SectorsCnt; i++) {
|
for (i = 0; i < SectorsCnt; i++) {
|
||||||
mfEmlGetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
|
mfEmlGetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
|
||||||
|
@ -730,6 +841,7 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]);
|
num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]);
|
||||||
mfEmlSetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
|
mfEmlSetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
|
||||||
}
|
}
|
||||||
|
PrintAndLog("Keys transferred to emulator memory.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create dump file
|
// Create dump file
|
||||||
|
@ -1784,64 +1896,81 @@ int CmdHF14AMfEKeyPrn(const char *Cmd)
|
||||||
int CmdHF14AMfCSetUID(const char *Cmd)
|
int CmdHF14AMfCSetUID(const char *Cmd)
|
||||||
{
|
{
|
||||||
uint8_t wipeCard = 0;
|
uint8_t wipeCard = 0;
|
||||||
|
uint8_t fillCard = 0;
|
||||||
uint8_t uid[8] = {0x00};
|
uint8_t uid[8] = {0x00};
|
||||||
uint8_t oldUid[8] = {0x00};
|
uint8_t oldUid[8] = {0x00};
|
||||||
uint8_t atqa[2] = {0x00};
|
uint8_t atqa[2] = {0x00};
|
||||||
uint8_t sak[1] = {0x00};
|
uint8_t sak[1] = {0x00};
|
||||||
uint8_t atqaPresent = 1;
|
uint8_t atqaPresent = 0;
|
||||||
int res;
|
int res;
|
||||||
char ctmp;
|
|
||||||
int argi=0;
|
|
||||||
|
|
||||||
if (strlen(Cmd) < 1 || param_getchar(Cmd, argi) == 'h') {
|
uint8_t needHelp = 0;
|
||||||
PrintAndLog("Usage: hf mf csetuid <UID 8 hex symbols> [ATQA 4 hex symbols SAK 2 hex symbols] [w]");
|
char cmdp = 1;
|
||||||
PrintAndLog("sample: hf mf csetuid 01020304");
|
|
||||||
PrintAndLog("sample: hf mf csetuid 01020304 0004 08 w");
|
|
||||||
PrintAndLog("Set UID, ATQA, and SAK for magic Chinese card (only works with such cards)");
|
|
||||||
PrintAndLog("If you also want to wipe the card then add 'w' at the end of the command line.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_getchar(Cmd, argi) && param_gethex(Cmd, argi, uid, 8)) {
|
if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 8)) {
|
||||||
PrintAndLog("UID must include 8 HEX symbols");
|
PrintAndLog("UID must include 8 HEX symbols");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
argi++;
|
|
||||||
|
|
||||||
ctmp = param_getchar(Cmd, argi);
|
if (param_getlength(Cmd, 1) > 1 && param_getlength(Cmd, 2) > 1) {
|
||||||
if (ctmp == 'w' || ctmp == 'W') {
|
atqaPresent = 1;
|
||||||
wipeCard = 1;
|
cmdp = 3;
|
||||||
atqaPresent = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atqaPresent) {
|
if (param_gethex(Cmd, 1, atqa, 4)) {
|
||||||
if (param_getchar(Cmd, argi)) {
|
PrintAndLog("ATQA must include 4 HEX symbols");
|
||||||
if (param_gethex(Cmd, argi, atqa, 4)) {
|
return 1;
|
||||||
PrintAndLog("ATQA must include 4 HEX symbols");
|
}
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
argi++;
|
|
||||||
if (!param_getchar(Cmd, argi) || param_gethex(Cmd, argi, sak, 2)) {
|
|
||||||
PrintAndLog("SAK must include 2 HEX symbols");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
argi++;
|
|
||||||
} else
|
|
||||||
atqaPresent = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!wipeCard) {
|
if (param_gethex(Cmd, 2, sak, 2)) {
|
||||||
ctmp = param_getchar(Cmd, argi);
|
PrintAndLog("SAK must include 2 HEX symbols");
|
||||||
if (ctmp == 'w' || ctmp == 'W') {
|
return 1;
|
||||||
wipeCard = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLog("--wipe card:%s uid:%s", (wipeCard)?"YES":"NO", sprint_hex(uid, 4));
|
while(param_getchar(Cmd, cmdp) != 0x00)
|
||||||
|
{
|
||||||
|
switch(param_getchar(Cmd, cmdp))
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
case 'H':
|
||||||
|
needHelp = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
case 'W':
|
||||||
|
wipeCard = 1;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
case 'K':
|
||||||
|
fillCard = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PrintAndLog("ERROR: Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||||
|
needHelp = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cmdp++;
|
||||||
|
}
|
||||||
|
|
||||||
res = mfCSetUID(uid, (atqaPresent)?atqa:NULL, (atqaPresent)?sak:NULL, oldUid, wipeCard);
|
if (strlen(Cmd) < 1 || needHelp) {
|
||||||
|
PrintAndLog("");
|
||||||
|
PrintAndLog("Usage: hf mf csetuid <UID 8 hex symbols> [ATQA 4 hex symbols SAK 2 hex symbols] [w] [k]");
|
||||||
|
PrintAndLog("sample: hf mf csetuid 01020304");
|
||||||
|
PrintAndLog("sample: hf mf csetuid 01020304 0004 08 w");
|
||||||
|
PrintAndLog("sample: hf mf csetuid 01020304 0004 08 f");
|
||||||
|
PrintAndLog("Set UID, ATQA, and SAK for magic Chinese card (only works with such cards)");
|
||||||
|
PrintAndLog("'w' - wipe the card. Works only for cards with this function");
|
||||||
|
PrintAndLog("'k' - fill data blocks with 0x00 and keys with 0xFFFFFFFFFFFF");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("--wipe card:%s fill card:%s uid:%s", (wipeCard)?"YES":"NO", (fillCard)?"YES":"NO", sprint_hex(uid, 4));
|
||||||
|
if (atqaPresent) {
|
||||||
|
PrintAndLog("--atqa:%s sak:%02x", sprint_hex(atqa, 2), sak[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = mfCSetUID(uid, (atqaPresent)?atqa:NULL, (atqaPresent)?sak:NULL, oldUid, wipeCard, fillCard);
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLog("Can't set UID. error=%d", res);
|
PrintAndLog("Can't set UID. Error=%d", res);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -437,8 +437,8 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uin
|
||||||
memcpy(c.d.asBytes, data, 16);
|
memcpy(c.d.asBytes, data, 16);
|
||||||
SendCommand(&c);
|
SendCommand(&c);
|
||||||
|
|
||||||
UsbCommand resp;
|
UsbCommand resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
isOK = resp.arg[0] & 0xff;
|
isOK = resp.arg[0] & 0xff;
|
||||||
if (uid != NULL)
|
if (uid != NULL)
|
||||||
memcpy(uid, resp.d.asBytes, 4);
|
memcpy(uid, resp.d.asBytes, 4);
|
||||||
|
@ -448,25 +448,29 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uin
|
||||||
PrintAndLog("Command execute timeout");
|
PrintAndLog("Command execute timeout");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, bool wantWipe) {
|
int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, bool wantWipe, bool wantFill) {
|
||||||
uint8_t oldblock0[16] = {0x00};
|
uint8_t oldblock0[16] = {0x00};
|
||||||
uint8_t block0[16] = {0x00};
|
uint8_t block0[16] = {0x00};
|
||||||
int old, gen = 0;
|
uint8_t block1[16] = {0x00};
|
||||||
|
uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
int gen = 0, res;
|
||||||
|
|
||||||
gen = mfCIdentify();
|
gen = mfCIdentify();
|
||||||
|
|
||||||
|
/* generation 1a magic card by default */
|
||||||
|
uint8_t cmdParams = CSETBLOCK_SINGLE_OPER;
|
||||||
if (gen == 2) {
|
if (gen == 2) {
|
||||||
/* generation 1b magic card */
|
/* generation 1b magic card */
|
||||||
old = mfCGetBlock(0, oldblock0, CSETBLOCK_SINGLE_OPER | CSETBLOCK_MAGIC_1B);
|
cmdParams = CSETBLOCK_SINGLE_OPER | CSETBLOCK_MAGIC_1B;
|
||||||
} else {
|
|
||||||
/* generation 1a magic card by default */
|
|
||||||
old = mfCGetBlock(0, oldblock0, CSETBLOCK_SINGLE_OPER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old == 0) {
|
res = mfCGetBlock(0, oldblock0, cmdParams);
|
||||||
|
|
||||||
|
if (res == 0) {
|
||||||
memcpy(block0, oldblock0, 16);
|
memcpy(block0, oldblock0, 16);
|
||||||
PrintAndLog("old block 0: %s", sprint_hex(block0,16));
|
PrintAndLog("old block 0: %s", sprint_hex(block0,16));
|
||||||
} else {
|
} else {
|
||||||
|
@ -477,25 +481,96 @@ int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, bool w
|
||||||
// UID
|
// UID
|
||||||
memcpy(block0, uid, 4);
|
memcpy(block0, uid, 4);
|
||||||
// Mifare UID BCC
|
// Mifare UID BCC
|
||||||
block0[4] = block0[0]^block0[1]^block0[2]^block0[3];
|
block0[4] = block0[0] ^ block0[1] ^ block0[2] ^ block0[3];
|
||||||
// mifare classic SAK(byte 5) and ATQA(byte 6 and 7, reversed)
|
// mifare classic SAK(byte 5) and ATQA(byte 6 and 7, reversed)
|
||||||
if (sak!=NULL)
|
if (sak != NULL)
|
||||||
block0[5]=sak[0];
|
block0[5] = sak[0];
|
||||||
if (atqa!=NULL) {
|
if (atqa != NULL) {
|
||||||
block0[6]=atqa[1];
|
block0[6] = atqa[1];
|
||||||
block0[7]=atqa[0];
|
block0[7] = atqa[0];
|
||||||
}
|
}
|
||||||
PrintAndLog("new block 0: %s", sprint_hex(block0,16));
|
PrintAndLog("new block 0: %s", sprint_hex(block0, 16));
|
||||||
|
|
||||||
if (gen == 2) {
|
res = mfCSetBlock(0, block0, oldUID, wantWipe, cmdParams);
|
||||||
/* generation 1b magic card */
|
if (res) {
|
||||||
return mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER | CSETBLOCK_MAGIC_1B);
|
PrintAndLog("Can't set block 0. Error: %d", res);
|
||||||
} else {
|
return res;
|
||||||
/* generation 1a magic card by default */
|
|
||||||
return mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wantFill) {
|
||||||
|
int blockNo = 1;
|
||||||
|
|
||||||
|
printf("write blocks ");
|
||||||
|
while (blockNo < 64) {
|
||||||
|
if ((blockNo + 1) % 4) {
|
||||||
|
res = mfCSetBlock(blockNo, block1, NULL, false, cmdParams);
|
||||||
|
} else {
|
||||||
|
res = mfCSetBlock(blockNo, blockK, NULL, false, cmdParams);
|
||||||
|
printf(".");
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
printf("\n");
|
||||||
|
PrintAndLog("Can't set block %d. Error: %d", blockNo, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockNo++;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
PrintAndLog("64 blocks writed successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mfCIdentify()
|
||||||
|
{
|
||||||
|
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
|
||||||
|
SendCommand(&c);
|
||||||
|
|
||||||
|
UsbCommand resp;
|
||||||
|
WaitForResponse(CMD_ACK,&resp);
|
||||||
|
|
||||||
|
iso14a_card_select_t card;
|
||||||
|
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
|
||||||
|
|
||||||
|
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||||
|
|
||||||
|
if(select_status != 0) {
|
||||||
|
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
|
||||||
|
c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT;
|
||||||
|
c.arg[1] = 2;
|
||||||
|
c.arg[2] = 0;
|
||||||
|
memcpy(c.d.asBytes, rats, 2);
|
||||||
|
SendCommand(&c);
|
||||||
|
WaitForResponse(CMD_ACK,&resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
c.cmd = CMD_MIFARE_CIDENT;
|
||||||
|
c.arg[0] = 0;
|
||||||
|
c.arg[1] = 0;
|
||||||
|
c.arg[2] = 0;
|
||||||
|
SendCommand(&c);
|
||||||
|
WaitForResponse(CMD_ACK,&resp);
|
||||||
|
|
||||||
|
uint8_t isGeneration = resp.arg[0] & 0xff;
|
||||||
|
switch( isGeneration ){
|
||||||
|
case 1: PrintAndLog("Chinese magic backdoor commands (GEN 1a) detected"); break;
|
||||||
|
case 2: PrintAndLog("Chinese magic backdoor command (GEN 1b) detected"); break;
|
||||||
|
default: PrintAndLog("No chinese magic backdoor command detected"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disconnect
|
||||||
|
c.cmd = CMD_READER_ISO_14443a;
|
||||||
|
c.arg[0] = 0;
|
||||||
|
c.arg[1] = 0;
|
||||||
|
c.arg[2] = 0;
|
||||||
|
SendCommand(&c);
|
||||||
|
|
||||||
|
return (int) isGeneration;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// SNIFFER
|
// SNIFFER
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
|
@ -820,6 +895,8 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DECODING
|
||||||
|
|
||||||
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len){
|
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len){
|
||||||
/*
|
/*
|
||||||
uint32_t nt; // tag challenge
|
uint32_t nt; // tag challenge
|
||||||
|
@ -840,49 +917,3 @@ int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mfCIdentify()
|
|
||||||
{
|
|
||||||
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
|
|
||||||
SendCommand(&c);
|
|
||||||
|
|
||||||
UsbCommand resp;
|
|
||||||
WaitForResponse(CMD_ACK,&resp);
|
|
||||||
|
|
||||||
iso14a_card_select_t card;
|
|
||||||
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
|
|
||||||
|
|
||||||
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
|
||||||
|
|
||||||
if(select_status != 0) {
|
|
||||||
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
|
|
||||||
c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT;
|
|
||||||
c.arg[1] = 2;
|
|
||||||
c.arg[2] = 0;
|
|
||||||
memcpy(c.d.asBytes, rats, 2);
|
|
||||||
SendCommand(&c);
|
|
||||||
WaitForResponse(CMD_ACK,&resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cmd = CMD_MIFARE_CIDENT;
|
|
||||||
c.arg[0] = 0;
|
|
||||||
c.arg[1] = 0;
|
|
||||||
c.arg[2] = 0;
|
|
||||||
SendCommand(&c);
|
|
||||||
WaitForResponse(CMD_ACK,&resp);
|
|
||||||
|
|
||||||
uint8_t isGeneration = resp.arg[0] & 0xff;
|
|
||||||
switch( isGeneration ){
|
|
||||||
case 1: PrintAndLog("Chinese magic backdoor commands (GEN 1a) detected"); break;
|
|
||||||
case 2: PrintAndLog("Chinese magic backdoor command (GEN 1b) detected"); break;
|
|
||||||
default: PrintAndLog("No chinese magic backdoor command detected"); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// disconnect
|
|
||||||
c.cmd = CMD_READER_ISO_14443a;
|
|
||||||
c.arg[0] = 0;
|
|
||||||
c.arg[1] = 0;
|
|
||||||
c.arg[2] = 0;
|
|
||||||
SendCommand(&c);
|
|
||||||
|
|
||||||
return (int) isGeneration;
|
|
||||||
}
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint
|
||||||
extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||||
extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||||
|
|
||||||
extern int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, bool wantWipe);
|
extern int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, bool wantWipe, bool wantFill);
|
||||||
extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params);
|
extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params);
|
||||||
extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
||||||
|
|
||||||
|
|
|
@ -322,7 +322,7 @@ char * printBits(size_t const size, void const * const ptr)
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// line - param line
|
// line - param line
|
||||||
// bg, en - symbol numbers in param line of beginning an ending parameter
|
// bg, en - symbol numbers in param line of beginning and ending parameter
|
||||||
// paramnum - param number (from 0)
|
// paramnum - param number (from 0)
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
int param_getptr(const char *line, int *bg, int *en, int paramnum)
|
int param_getptr(const char *line, int *bg, int *en, int paramnum)
|
||||||
|
@ -355,6 +355,15 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int param_getlength(const char *line, int paramnum)
|
||||||
|
{
|
||||||
|
int bg, en;
|
||||||
|
|
||||||
|
if (param_getptr(line, &bg, &en, paramnum)) return 0;
|
||||||
|
|
||||||
|
return en - bg + 1;
|
||||||
|
}
|
||||||
|
|
||||||
char param_getchar(const char *line, int paramnum)
|
char param_getchar(const char *line, int paramnum)
|
||||||
{
|
{
|
||||||
int bg, en;
|
int bg, en;
|
||||||
|
|
|
@ -51,6 +51,7 @@ extern uint32_t SwapBits(uint32_t value, int nrbits);
|
||||||
extern uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
|
extern uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
|
||||||
extern void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest);
|
extern void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest);
|
||||||
|
|
||||||
|
extern int param_getlength(const char *line, int paramnum);
|
||||||
extern char param_getchar(const char *line, int paramnum);
|
extern char param_getchar(const char *line, int paramnum);
|
||||||
extern int param_getptr(const char *line, int *bg, int *en, int paramnum);
|
extern int param_getptr(const char *line, int *bg, int *en, int paramnum);
|
||||||
extern uint8_t param_get8(const char *line, int paramnum);
|
extern uint8_t param_get8(const char *line, int paramnum);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue