mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
Add 'hf mf staticnonce' - a nested find all key solution command for tags that has a static nonce. \n See https://github.com/RfidResearchGroup/proxmark3/issues/133 \n See https://github.com/Proxmark/proxmark3/issues/899 \n This solution is based upon the ideas and solutions of @uzlonewolf and @xtigmh . Thanks!
This commit is contained in:
parent
7c913265c5
commit
b37a4c14eb
9 changed files with 478 additions and 19 deletions
233
client/cmdhfmf.c
233
client/cmdhfmf.c
|
@ -132,6 +132,21 @@ static int usage_hf14_nested(void) {
|
|||
PrintAndLogEx(NORMAL, " hf mf nested o 0 A FFFFFFFFFFFF 4 A -- one sector key recovery. Use block 0 Key A to find block 4 Key A");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_staticnested(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage:");
|
||||
PrintAndLogEx(NORMAL, " all sectors: hf mf staticnested <card memory> <block> <key A/B> <key (12 hex symbols)> [t,d]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");
|
||||
PrintAndLogEx(NORMAL, " t transfer keys into emulator memory");
|
||||
PrintAndLogEx(NORMAL, " d write keys to binary file `hf-mf-<UID>-key.bin`");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf mf staticnested 1 0 A FFFFFFFFFFFF -- key recovery against 1K, block 0, Key A using key FFFFFFFFFFFF");
|
||||
PrintAndLogEx(NORMAL, " hf mf staticnested 1 0 A FFFFFFFFFFFF t -- and transfer keys into emulator memory");
|
||||
PrintAndLogEx(NORMAL, " hf mf staticnested 1 0 A FFFFFFFFFFFF d -- or write keys to binary file ");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_hardnested(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage:");
|
||||
PrintAndLogEx(NORMAL, " hf mf hardnested <block number> <key A|B> <key (12 hex symbols)>");
|
||||
|
@ -1263,9 +1278,10 @@ static int CmdHF14AMfNested(const char *Cmd) {
|
|||
j++;
|
||||
}
|
||||
|
||||
// check if tag doesn't have static/fixed nonce
|
||||
// check if tag doesn't have static nonce
|
||||
if (detect_classic_static_nonce() != 0) {
|
||||
PrintAndLogEx(WARNING, "Static/fixed nonce detected. Quitting...");
|
||||
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
|
||||
PrintAndLogEx(INFO, "\t Try use `" _YELLOW_("hf mf staticnested") "`");
|
||||
return PM3_EOPABORTED;
|
||||
}
|
||||
|
||||
|
@ -1279,7 +1295,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
|
|||
int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true);
|
||||
switch (isOK) {
|
||||
case -1 :
|
||||
PrintAndLogEx(ERR, "Error: No response from Proxmark3.\n");
|
||||
PrintAndLogEx(ERR, "Command execute timeout\n");
|
||||
break;
|
||||
case -2 :
|
||||
PrintAndLogEx(WARNING, "Button pressed. Aborted.\n");
|
||||
|
@ -1314,7 +1330,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
|
|||
}
|
||||
return PM3_SUCCESS;
|
||||
default :
|
||||
PrintAndLogEx(ERR, "Unknown Error.\n");
|
||||
PrintAndLogEx(ERR, "Unknown error.\n");
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
} else { // ------------------------------------ multiple sectors working
|
||||
|
@ -1360,7 +1376,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
|
|||
int16_t isOK = mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate);
|
||||
switch (isOK) {
|
||||
case -1 :
|
||||
PrintAndLogEx(ERR, "error: No response from Proxmark3.\n");
|
||||
PrintAndLogEx(ERR, "Command execute timeout\n");
|
||||
break;
|
||||
case -2 :
|
||||
PrintAndLogEx(WARNING, "button pressed. Aborted.\n");
|
||||
|
@ -1382,7 +1398,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
|
|||
continue;
|
||||
|
||||
default :
|
||||
PrintAndLogEx(ERR, "unknown Error.\n");
|
||||
PrintAndLogEx(ERR, "Unknown error.\n");
|
||||
}
|
||||
free(e_sector);
|
||||
return PM3_ESOFT;
|
||||
|
@ -1472,6 +1488,204 @@ jumptoend:
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14AMfNestedStatic(const char *Cmd) {
|
||||
sector_t *e_sector = NULL;
|
||||
uint8_t keyType = 0;
|
||||
uint8_t trgKeyType = 0;
|
||||
uint8_t SectorsCnt = 0;
|
||||
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
|
||||
uint8_t keyBlock[(ARRAYLEN(g_mifare_default_keys) + 1) * 6];
|
||||
uint64_t key64 = 0;
|
||||
bool transferToEml = false;
|
||||
bool createDumpFile = false;
|
||||
|
||||
if (strlen(Cmd) < 3) return usage_hf14_staticnested();
|
||||
|
||||
char cmdp, ctmp;
|
||||
cmdp = tolower(param_getchar(Cmd, 0));
|
||||
uint8_t blockNo = param_get8(Cmd, 1);
|
||||
ctmp = tolower(param_getchar(Cmd, 2));
|
||||
|
||||
if (ctmp != 'a' && ctmp != 'b') {
|
||||
PrintAndLogEx(WARNING, "key type must be A or B");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (ctmp != 'a')
|
||||
keyType = 1;
|
||||
|
||||
if (param_gethex(Cmd, 3, key, 12)) {
|
||||
PrintAndLogEx(WARNING, "key must include 12 HEX symbols");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
SectorsCnt = NumOfSectors(cmdp);
|
||||
if (SectorsCnt == 0) return usage_hf14_staticnested();
|
||||
|
||||
uint8_t j = 4;
|
||||
while (ctmp != 0x00) {
|
||||
|
||||
ctmp = tolower(param_getchar(Cmd, j));
|
||||
transferToEml |= (ctmp == 't');
|
||||
createDumpFile |= (ctmp == 'd');
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
// check if tag have static nonce
|
||||
if (detect_classic_static_nonce() == 0) {
|
||||
PrintAndLogEx(WARNING, "Normal nonce detected. Quitting...");
|
||||
return PM3_EOPABORTED;
|
||||
}
|
||||
|
||||
// check if we can authenticate to sector
|
||||
if (mfCheckKeys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block:%3d key type:%c", blockNo, keyType ? 'B' : 'A');
|
||||
return PM3_EOPABORTED;
|
||||
}
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
e_sector = calloc(SectorsCnt, sizeof(sector_t));
|
||||
if (e_sector == NULL) return PM3_EMALLOC;
|
||||
|
||||
// add our known key
|
||||
e_sector[GetSectorFromBlockNo(blockNo)].foundKey[keyType] = 1;
|
||||
e_sector[GetSectorFromBlockNo(blockNo)].Key[keyType] = key64;
|
||||
|
||||
//test current key and additional standard keys first
|
||||
// add parameter key
|
||||
memcpy(keyBlock + (ARRAYLEN(g_mifare_default_keys) * 6), key, 6);
|
||||
|
||||
for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) {
|
||||
num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6));
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Testing known keys. Sector count=%d", SectorsCnt);
|
||||
int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false);
|
||||
if (res == PM3_SUCCESS) {
|
||||
// all keys found
|
||||
PrintAndLogEx(SUCCESS, "Fast check found all keys");
|
||||
goto jumptoend;
|
||||
}
|
||||
|
||||
uint64_t t2 = msclock() - t1;
|
||||
PrintAndLogEx(SUCCESS, "Time to check %zu known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0);
|
||||
PrintAndLogEx(SUCCESS, "enter static nested attack");
|
||||
|
||||
// nested sectors
|
||||
for (trgKeyType = 0; trgKeyType < 2; ++trgKeyType) {
|
||||
for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; ++sectorNo) {
|
||||
|
||||
for (int i = 0; i < 1; i++) {
|
||||
|
||||
if (e_sector[sectorNo].foundKey[trgKeyType]) continue;
|
||||
|
||||
int16_t isOK = mfStaticNested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock);
|
||||
switch (isOK) {
|
||||
case PM3_ETIMEOUT :
|
||||
PrintAndLogEx(ERR, "Command execute timeout");
|
||||
break;
|
||||
case PM3_ESOFT :
|
||||
continue;
|
||||
case PM3_SUCCESS :
|
||||
e_sector[sectorNo].foundKey[trgKeyType] = 1;
|
||||
e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
|
||||
|
||||
mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false);
|
||||
continue;
|
||||
default :
|
||||
PrintAndLogEx(ERR, "unknown error.\n");
|
||||
}
|
||||
free(e_sector);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t1 = msclock() - t1;
|
||||
PrintAndLogEx(SUCCESS, "time in static nested: %.0f seconds\n", (float)t1 / 1000.0);
|
||||
|
||||
|
||||
// 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
|
||||
PrintAndLogEx(INFO, "trying to read key B...");
|
||||
for (int i = 0; i < SectorsCnt; i++) {
|
||||
// KEY A but not KEY B
|
||||
if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) {
|
||||
|
||||
uint8_t sectrail = (FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "reading block %d", sectrail);
|
||||
|
||||
mf_readblock_t payload;
|
||||
payload.blockno = sectrail;
|
||||
payload.keytype = 0;
|
||||
|
||||
num_to_bytes(e_sector[i].Key[0], 6, payload.key); // KEY A
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue;
|
||||
|
||||
if (resp.status != PM3_SUCCESS) continue;
|
||||
|
||||
uint8_t *data = resp.data.asBytes;
|
||||
key64 = bytes_to_num(data + 10, 6);
|
||||
if (key64) {
|
||||
PrintAndLogEx(SUCCESS, "data: %s", sprint_hex(data + 10, 6));
|
||||
e_sector[i].foundKey[1] = true;
|
||||
e_sector[i].Key[1] = key64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jumptoend:
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "found keys:");
|
||||
|
||||
//print them
|
||||
printKeyTable(SectorsCnt, e_sector);
|
||||
|
||||
// transfer them to the emulator
|
||||
if (transferToEml) {
|
||||
// fast push mode
|
||||
conn.block_after_ACK = true;
|
||||
for (int i = 0; i < SectorsCnt; i++) {
|
||||
mfEmlGetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
|
||||
|
||||
if (e_sector[i].foundKey[0])
|
||||
num_to_bytes(e_sector[i].Key[0], 6, keyBlock);
|
||||
|
||||
if (e_sector[i].foundKey[1])
|
||||
num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]);
|
||||
|
||||
if (i == SectorsCnt - 1) {
|
||||
// Disable fast mode on last packet
|
||||
conn.block_after_ACK = false;
|
||||
}
|
||||
mfEmlSetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "keys transferred to emulator memory.");
|
||||
}
|
||||
|
||||
// Create dump file
|
||||
if (createDumpFile) {
|
||||
char *fptr = GenerateFilename("hf-mf-", "-key.bin");
|
||||
if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to save keys to file");
|
||||
free(e_sector);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
free(e_sector);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int CmdHF14AMfNestedHard(const char *Cmd) {
|
||||
uint8_t blockNo = 0;
|
||||
uint8_t keyType = 0;
|
||||
|
@ -1617,9 +1831,10 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
|
|||
|
||||
if (!know_target_key && nonce_file_read == false) {
|
||||
|
||||
// check if tag doesn't have static/fixed nonce
|
||||
// check if tag doesn't have static nonce
|
||||
if (detect_classic_static_nonce() != 0) {
|
||||
PrintAndLogEx(WARNING, "Static/fixed nonce detected. Quitting...");
|
||||
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
|
||||
PrintAndLogEx(INFO, "\t Try use `" _YELLOW_("hf mf staticnested") "`");
|
||||
return PM3_EOPABORTED;
|
||||
}
|
||||
|
||||
|
@ -4587,7 +4802,7 @@ static command_t CommandTable[] = {
|
|||
{"darkside", CmdHF14AMfDarkside, IfPm3Iso14443a, "Darkside attack"},
|
||||
{"nested", CmdHF14AMfNested, IfPm3Iso14443a, "Nested attack"},
|
||||
{"hardnested", CmdHF14AMfNestedHard, AlwaysAvailable, "Nested attack for hardened MIFARE Classic cards"},
|
||||
// {"fixednested", CmdHF14AMfNestedFixed, IfPm3Iso14443a, "Nested attack against static/fixed nonce Mifare Classic cards"},
|
||||
{"staticnested", CmdHF14AMfNestedStatic, IfPm3Iso14443a, "Nested attack against static nonce Mifare Classic cards"},
|
||||
{"autopwn", CmdHF14AMfAutoPWN, IfPm3Iso14443a, "Automatic key recovery tool for MIFARE Classic"},
|
||||
// {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"},
|
||||
{"nack", CmdHf14AMfNack, IfPm3Iso14443a, "Test for MIFARE NACK bug"},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue