mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-22 14:23:50 -07:00
commit
4a26096006
7 changed files with 69 additions and 85 deletions
|
@ -3294,10 +3294,10 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
uint8_t cascade_levels = 0;
|
uint8_t cascade_levels = 0;
|
||||||
|
|
||||||
// static variables here, is re-used in the next call
|
// static variables here, is re-used in the next call
|
||||||
static uint32_t nt_attacked = 0;
|
|
||||||
static int32_t sync_cycles = 0;
|
static int32_t sync_cycles = 0;
|
||||||
static uint8_t par_low = 0;
|
static uint32_t nt_attacked = 0;
|
||||||
static uint8_t mf_nr_ar3 = 0;
|
static uint8_t mf_nr_ar3 = 0;
|
||||||
|
static uint8_t par_low = 0;
|
||||||
|
|
||||||
int return_status = PM3_SUCCESS;
|
int return_status = PM3_SUCCESS;
|
||||||
|
|
||||||
|
@ -3328,7 +3328,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
// Test if the action was cancelled
|
// Test if the action was cancelled
|
||||||
if (checkbtn_cnt == 1000) {
|
if (checkbtn_cnt == 1000) {
|
||||||
if (BUTTON_PRESS() || data_available()) {
|
if (BUTTON_PRESS() || data_available()) {
|
||||||
isOK = -1;
|
isOK = 5;
|
||||||
return_status = PM3_EOPABORTED;
|
return_status = PM3_EOPABORTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3382,7 +3382,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
|
ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
|
||||||
|
|
||||||
// Receive the (4 Byte) "random" TAG nonce
|
// Receive the (4 Byte) "random" TAG nonce
|
||||||
if (!ReaderReceive(receivedAnswer, receivedAnswerPar))
|
if (ReaderReceive(receivedAnswer, receivedAnswerPar) != 4)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
previous_nt = nt;
|
previous_nt = nt;
|
||||||
|
@ -3398,7 +3398,8 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
else if (resp_res == 4) {
|
else if (resp_res == 4) {
|
||||||
// did we get lucky and got our dummykey to be valid?
|
// did we get lucky and got our dummykey to be valid?
|
||||||
// however we don't feed key w uid it the prng..
|
// however we don't feed key w uid it the prng..
|
||||||
isOK = -6;
|
isOK = 6;
|
||||||
|
return_status = PM3_ESOFT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3416,7 +3417,8 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
if (nt_distance == -99999) { // invalid nonce received
|
if (nt_distance == -99999) { // invalid nonce received
|
||||||
unexpected_random++;
|
unexpected_random++;
|
||||||
if (unexpected_random > MAX_UNEXPECTED_RANDOM) {
|
if (unexpected_random > MAX_UNEXPECTED_RANDOM) {
|
||||||
isOK = -3; // Card has an unpredictable PRNG. Give up
|
isOK = 3; // Card has an unpredictable PRNG. Give up
|
||||||
|
return_status = PM3_ESOFT;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
continue; // continue trying...
|
continue; // continue trying...
|
||||||
|
@ -3424,14 +3426,15 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++sync_tries > MAX_SYNC_TRIES) {
|
if (++sync_tries > MAX_SYNC_TRIES) {
|
||||||
isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly
|
isOK = 4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly
|
||||||
|
return_status = PM3_ESOFT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_cycles = (sync_cycles - nt_distance) / elapsed_prng_sequences;
|
sync_cycles = (sync_cycles - nt_distance) / elapsed_prng_sequences;
|
||||||
|
|
||||||
// no negative sync_cycles
|
// no negative sync_cycles, and too small sync_cycles will result in continuous misses
|
||||||
if (sync_cycles <= 0) sync_cycles += PRNG_SEQUENCE_LENGTH;
|
if (sync_cycles <= 10) sync_cycles += PRNG_SEQUENCE_LENGTH;
|
||||||
|
|
||||||
// reset sync_cycles
|
// reset sync_cycles
|
||||||
if (sync_cycles > PRNG_SEQUENCE_LENGTH * 2) {
|
if (sync_cycles > PRNG_SEQUENCE_LENGTH * 2) {
|
||||||
|
@ -3442,11 +3445,9 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
if (g_dbglevel >= DBG_EXTENDED)
|
if (g_dbglevel >= DBG_EXTENDED)
|
||||||
Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n", i, nt_distance, elapsed_prng_sequences, sync_cycles);
|
Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n", i, nt_distance, elapsed_prng_sequences, sync_cycles);
|
||||||
|
|
||||||
LED_B_OFF();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LED_B_OFF();
|
|
||||||
|
|
||||||
if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again...
|
if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again...
|
||||||
|
|
||||||
|
@ -3495,6 +3496,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
// Test if the information is complete
|
// Test if the information is complete
|
||||||
if (nt_diff == 0x07) {
|
if (nt_diff == 0x07) {
|
||||||
isOK = 1;
|
isOK = 1;
|
||||||
|
return_status = PM3_SUCCESS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3507,7 +3509,8 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||||
if (nt_diff == 0 && first_try) {
|
if (nt_diff == 0 && first_try) {
|
||||||
par[0]++;
|
par[0]++;
|
||||||
if (par[0] == 0) { // tried all 256 possible parities without success. Card doesn't send NACK.
|
if (par[0] == 0) { // tried all 256 possible parities without success. Card doesn't send NACK.
|
||||||
isOK = -2;
|
isOK = 2;
|
||||||
|
return_status = PM3_ESOFT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -186,14 +186,7 @@ local function main(args)
|
||||||
-- Crack it
|
-- Crack it
|
||||||
local cnt
|
local cnt
|
||||||
err, res = core.mfDarkside()
|
err, res = core.mfDarkside()
|
||||||
if err == -1 then return oops('Button pressed. Aborted.')
|
if err ~= 0 then return oops('Darkside attack failed.') end
|
||||||
elseif err == -2 then return oops([[Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).]])
|
|
||||||
elseif err == -3 then return oops([[Card is not vulnerable to Darkside attack (its random number generator is not predictable).]])
|
|
||||||
elseif err == -4 then return oops([[
|
|
||||||
Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown
|
|
||||||
generating polynomial with 16 effective bits only, but shows unexpected behaviour.]])
|
|
||||||
elseif err == -5 then return oops('aborted via keyboard.')
|
|
||||||
end
|
|
||||||
-- The key is actually 8 bytes, so a
|
-- The key is actually 8 bytes, so a
|
||||||
-- 6-byte key is sent as 00XXXXXX
|
-- 6-byte key is sent as 00XXXXXX
|
||||||
-- This means we unpack it as first
|
-- This means we unpack it as first
|
||||||
|
|
|
@ -915,27 +915,12 @@ static int CmdHF14AMfDarkside(const char *Cmd) {
|
||||||
|
|
||||||
uint64_t key = 0;
|
uint64_t key = 0;
|
||||||
uint64_t t1 = msclock();
|
uint64_t t1 = msclock();
|
||||||
int isOK = mfDarkside(blockno, key_type, &key);
|
int ret = mfDarkside(blockno, key_type, &key);
|
||||||
t1 = msclock() - t1;
|
t1 = msclock() - t1;
|
||||||
|
|
||||||
switch (isOK) {
|
if (ret != PM3_SUCCESS) return ret;
|
||||||
case PM3_EOPABORTED:
|
|
||||||
PrintAndLogEx(WARNING, "button pressed or aborted via keyboard. aborted");
|
PrintAndLogEx(SUCCESS, "found valid key: " _GREEN_("%012" PRIx64), key);
|
||||||
return PM3_EOPABORTED;
|
|
||||||
case -2 :
|
|
||||||
PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests)");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
case -3 :
|
|
||||||
PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (its random number generator is not predictable)");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
case -4 :
|
|
||||||
PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");
|
|
||||||
PrintAndLogEx(FAILED, "generating polynomial with 16 effective bits only, but shows unexpected behaviour");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
default :
|
|
||||||
PrintAndLogEx(SUCCESS, "found valid key: "_GREEN_("%012" PRIx64), key);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(SUCCESS, "time in darkside " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
|
PrintAndLogEx(SUCCESS, "time in darkside " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2907,26 +2892,15 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
|
PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
isOK = mfDarkside(mfFirstBlockOfSector(sectorno), MIFARE_AUTH_KEYA + keytype, &key64);
|
isOK = mfDarkside(mfFirstBlockOfSector(sectorno), MIFARE_AUTH_KEYA + keytype, &key64);
|
||||||
|
|
||||||
switch (isOK) {
|
if (isOK != PM3_SUCCESS)
|
||||||
case PM3_EOPABORTED :
|
|
||||||
PrintAndLogEx(WARNING, "\nButton pressed or aborted via keyboard");
|
|
||||||
goto noValidKeyFound;
|
goto noValidKeyFound;
|
||||||
case -2 :
|
|
||||||
PrintAndLogEx(FAILED, "\nCard is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).");
|
PrintAndLogEx(SUCCESS, "Found valid key [ " _GREEN_("%012" PRIx64) " ]\n", key64);
|
||||||
goto noValidKeyFound;
|
|
||||||
case -3 :
|
|
||||||
PrintAndLogEx(FAILED, "\nCard is not vulnerable to Darkside attack (its random number generator is not predictable).");
|
|
||||||
goto noValidKeyFound;
|
|
||||||
case -4 :
|
|
||||||
PrintAndLogEx(FAILED, "\nCard is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");
|
|
||||||
PrintAndLogEx(FAILED, "generating polynomial with 16 effective bits only, but shows unexpected behaviour.");
|
|
||||||
goto noValidKeyFound;
|
|
||||||
default :
|
|
||||||
PrintAndLogEx(SUCCESS, "\nFound valid key [ " _GREEN_("%012" PRIx64) " ]\n", key64);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the keys
|
// Store the keys
|
||||||
num_to_bytes(key64, MIFARE_KEY_SIZE, key);
|
num_to_bytes(key64, MIFARE_KEY_SIZE, key);
|
||||||
|
|
|
@ -283,7 +283,7 @@ static int CmdQuit(const char *Cmd) {
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_SQUIT;
|
return PM3_EFATAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdRev(const char *Cmd) {
|
static int CmdRev(const char *Cmd) {
|
||||||
|
|
|
@ -57,6 +57,15 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
|
|
||||||
|
//TODO: Not really stopping the command in time.
|
||||||
|
//flush queue
|
||||||
|
while (kbd_enter_pressed()) {
|
||||||
|
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||||
|
PrintAndLogEx(WARNING, "Aborted via keyboard");
|
||||||
|
return PM3_EOPABORTED;
|
||||||
|
}
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t first_run;
|
uint8_t first_run;
|
||||||
uint8_t blockno;
|
uint8_t blockno;
|
||||||
|
@ -67,12 +76,6 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
||||||
payload.key_type = key_type;
|
payload.key_type = key_type;
|
||||||
SendCommandNG(CMD_HF_MIFARE_READER, (uint8_t *)&payload, sizeof(payload));
|
SendCommandNG(CMD_HF_MIFARE_READER, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
|
||||||
//flush queue
|
|
||||||
while (kbd_enter_pressed()) {
|
|
||||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
|
||||||
return PM3_EOPABORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "Running darkside " NOLF);
|
PrintAndLogEx(INFO, "Running darkside " NOLF);
|
||||||
|
|
||||||
|
@ -80,16 +83,17 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
||||||
while (true) {
|
while (true) {
|
||||||
PrintAndLogEx(NORMAL, "." NOLF);
|
PrintAndLogEx(NORMAL, "." NOLF);
|
||||||
|
|
||||||
|
if (IsCommunicationThreadDead()) return PM3_EIO;
|
||||||
|
|
||||||
|
//TODO: Not really stopping the command in time.
|
||||||
if (kbd_enter_pressed()) {
|
if (kbd_enter_pressed()) {
|
||||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||||
|
PrintAndLogEx(WARNING, "\nAborted via keyboard");
|
||||||
return PM3_EOPABORTED;
|
return PM3_EOPABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_READER, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_HF_MIFARE_READER, &resp, 2000)) {
|
||||||
if (resp.status == PM3_EOPABORTED) {
|
|
||||||
return resp.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct p {
|
struct p {
|
||||||
int32_t isOK;
|
int32_t isOK;
|
||||||
|
@ -101,16 +105,35 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
||||||
uint8_t ar[4];
|
uint8_t ar[4];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
struct p *package = (struct p *) resp.data.asBytes;
|
struct p *package = (struct p *)resp.data.asBytes;
|
||||||
|
|
||||||
if (package->isOK == -6) {
|
if (resp.status != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
|
switch (package->isOK) {
|
||||||
|
case 2:
|
||||||
|
PrintAndLogEx(FAILED, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
PrintAndLogEx(FAILED, "Card is not vulnerable to Darkside attack (its random number generator is not predictable).");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
PrintAndLogEx(FAILED, "Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");
|
||||||
|
PrintAndLogEx(FAILED, "generating polynomial with 16 effective bits only, but shows unexpected behaviour.");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
PrintAndLogEx(WARNING, "Button pressed. aborted");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
*key = 0101;
|
*key = 0101;
|
||||||
return 1;
|
return PM3_SUCCESS;
|
||||||
|
default:
|
||||||
|
PrintAndLogEx(FAILED, "Unknown error. Darkside attack failed.");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (package->isOK < 0)
|
return resp.status;
|
||||||
return package->isOK;
|
}
|
||||||
|
|
||||||
|
|
||||||
uid = (uint32_t)bytes_to_num(package->cuid, sizeof(package->cuid));
|
uid = (uint32_t)bytes_to_num(package->cuid, sizeof(package->cuid));
|
||||||
nt = (uint32_t)bytes_to_num(package->nt, sizeof(package->nr));
|
nt = (uint32_t)bytes_to_num(package->nt, sizeof(package->nr));
|
||||||
|
|
|
@ -574,11 +574,6 @@ check_script:
|
||||||
// exit or quit
|
// exit or quit
|
||||||
if (mainret == PM3_EFATAL)
|
if (mainret == PM3_EFATAL)
|
||||||
break;
|
break;
|
||||||
if (mainret == PM3_SQUIT) {
|
|
||||||
// Normal quit, map to 0
|
|
||||||
mainret = PM3_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(cmd);
|
free(cmd);
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
|
|
|
@ -794,11 +794,7 @@ typedef struct {
|
||||||
#define FLAG_ANSI 0x08
|
#define FLAG_ANSI 0x08
|
||||||
|
|
||||||
// Error codes Usages:
|
// Error codes Usages:
|
||||||
|
// NOTE: Positive values should be reserved for commands in case they need to return multiple statuses and error codes simultaneously.
|
||||||
// Success, regular quit
|
|
||||||
#define PM3_SQUIT 2
|
|
||||||
// Success, transfer nonces pm3: Sending nonces back to client
|
|
||||||
#define PM3_SNONCES 1
|
|
||||||
// Success (no error)
|
// Success (no error)
|
||||||
#define PM3_SUCCESS 0
|
#define PM3_SUCCESS 0
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue