mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
draft for a Mifare classic NACK bug detection.
the idea is to have a statistically solid conclusion if tag does or does not have the NACK bug. -in short, ref https://github.com/iceman1001/proxmark3/issues/141 NACK bug; when a tag responds with a NACK to a 8 byte nonce exchange during authentication when the bytes are wrong but the parity bits are correct. This is a strong oracle which is used in the darkside attack.
This commit is contained in:
parent
07bf77e155
commit
e02e145fae
6 changed files with 281 additions and 14 deletions
|
@ -881,21 +881,18 @@ void UsbPacketReceived(uint8_t *packet, int len) {
|
||||||
case CMD_MIFARE_CIDENT:
|
case CMD_MIFARE_CIDENT:
|
||||||
MifareCIdent();
|
MifareCIdent();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// mifare sniffer
|
// mifare sniffer
|
||||||
case CMD_MIFARE_SNIFFER:
|
case CMD_MIFARE_SNIFFER:
|
||||||
SniffMifare(c->arg[0]);
|
SniffMifare(c->arg[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_MIFARE_SETMOD:
|
case CMD_MIFARE_SETMOD:
|
||||||
MifareSetMod(c->arg[0], c->d.asBytes);
|
MifareSetMod(c->arg[0], c->d.asBytes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//mifare desfire
|
//mifare desfire
|
||||||
case CMD_MIFARE_DESFIRE_READBL:
|
case CMD_MIFARE_DESFIRE_READBL:
|
||||||
break;
|
break;
|
||||||
case CMD_MIFARE_DESFIRE_WRITEBL:
|
case CMD_MIFARE_DESFIRE_WRITEBL:
|
||||||
break;
|
break;
|
||||||
case CMD_MIFARE_DESFIRE_AUTH1:
|
case CMD_MIFARE_DESFIRE_AUTH1:
|
||||||
MifareDES_Auth1(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
|
MifareDES_Auth1(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
|
||||||
break;
|
break;
|
||||||
|
@ -913,6 +910,9 @@ void UsbPacketReceived(uint8_t *packet, int len) {
|
||||||
break;
|
break;
|
||||||
case CMD_MIFARE_COLLECT_NONCES:
|
case CMD_MIFARE_COLLECT_NONCES:
|
||||||
break;
|
break;
|
||||||
|
case CMD_MIFARE_NACK_DETECT:
|
||||||
|
DetectNACKbug();
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_ICLASS
|
#ifdef WITH_ICLASS
|
||||||
|
|
|
@ -2297,7 +2297,6 @@ int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
|
||||||
// Cloning MiFare Classic Rail and Building Passes, Anywhere, Anytime"
|
// Cloning MiFare Classic Rail and Building Passes, Anywhere, Anytime"
|
||||||
// (article by Nicolas T. Courtois, 2009)
|
// (article by Nicolas T. Courtois, 2009)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) {
|
void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) {
|
||||||
|
|
||||||
uint8_t mf_auth[] = { keytype, block, 0x00, 0x00 };
|
uint8_t mf_auth[] = { keytype, block, 0x00, 0x00 };
|
||||||
|
@ -2548,6 +2547,231 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) {
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mifare Classic NACK-bug detection
|
||||||
|
*/
|
||||||
|
void DetectNACKbug() {
|
||||||
|
|
||||||
|
uint8_t mf_auth[] = {0x60, 0, 0, 0};
|
||||||
|
uint8_t mf_nr_ar[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
uint8_t uid[10] = {0,0,0,0,0,0,0,0,0,0};
|
||||||
|
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||||
|
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
|
||||||
|
uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough
|
||||||
|
uint8_t nt_diff = 0;
|
||||||
|
uint32_t nt = 0;
|
||||||
|
uint32_t previous_nt = 0;
|
||||||
|
uint32_t cuid = 0;
|
||||||
|
|
||||||
|
int32_t catch_up_cycles = 0;
|
||||||
|
int32_t last_catch_up = 0;
|
||||||
|
int32_t isOK = 0;
|
||||||
|
int32_t nt_distance = 0;
|
||||||
|
|
||||||
|
uint16_t elapsed_prng_sequences = 1;
|
||||||
|
uint16_t consecutive_resyncs = 0;
|
||||||
|
uint16_t unexpected_random = 0;
|
||||||
|
uint16_t sync_tries = 0;
|
||||||
|
|
||||||
|
// static variables here, is re-used in the next call
|
||||||
|
static uint32_t nt_attacked = 0;
|
||||||
|
static uint32_t sync_time = 0;
|
||||||
|
static uint32_t sync_cycles = 0;
|
||||||
|
static uint8_t par_low = 0;
|
||||||
|
|
||||||
|
#define PRNG_SEQUENCE_LENGTH (1 << 16)
|
||||||
|
#define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up.
|
||||||
|
#define MAX_SYNC_TRIES 32
|
||||||
|
|
||||||
|
AppendCrc14443a(mf_auth, 2);
|
||||||
|
|
||||||
|
BigBuf_free(); BigBuf_Clear_ext(false);
|
||||||
|
clear_trace();
|
||||||
|
set_tracing(false);
|
||||||
|
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||||
|
|
||||||
|
sync_time = GetCountSspClk() & 0xfffffff8;
|
||||||
|
sync_cycles = PRNG_SEQUENCE_LENGTH; // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces).
|
||||||
|
nt_attacked = 0;
|
||||||
|
|
||||||
|
if (MF_DBGLEVEL >= 4) Dbprintf("Mifare::Sync %u", sync_time);
|
||||||
|
|
||||||
|
par_low = 0;
|
||||||
|
|
||||||
|
bool have_uid = false;
|
||||||
|
uint8_t cascade_levels = 0;
|
||||||
|
|
||||||
|
LED_C_ON();
|
||||||
|
uint16_t i;
|
||||||
|
for(i = 0; true; ++i) {
|
||||||
|
|
||||||
|
WDT_HIT();
|
||||||
|
|
||||||
|
// Test if the action was cancelled
|
||||||
|
if(BUTTON_PRESS()) {
|
||||||
|
isOK = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this part is from Piwi's faster nonce collecting part in Hardnested.
|
||||||
|
if (!have_uid) { // need a full select cycle to get the uid first
|
||||||
|
iso14a_card_select_t card_info;
|
||||||
|
if(!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||||
|
if (MF_DBGLEVEL >= 4) Dbprintf("Mifare: Can't select card (ALL)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (card_info.uidlen) {
|
||||||
|
case 4 : cascade_levels = 1; break;
|
||||||
|
case 7 : cascade_levels = 2; break;
|
||||||
|
case 10: cascade_levels = 3; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
have_uid = true;
|
||||||
|
} else { // no need for anticollision. We can directly select the card
|
||||||
|
if(!iso14443a_select_card(uid, NULL, &cuid, false, cascade_levels, true)) {
|
||||||
|
if (MF_DBGLEVEL >= 4) Dbprintf("Mifare: Can't select card (UID)");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sending timeslot of ISO14443a frame
|
||||||
|
sync_time = (sync_time & 0xfffffff8 ) + sync_cycles + catch_up_cycles;
|
||||||
|
catch_up_cycles = 0;
|
||||||
|
|
||||||
|
// if we missed the sync time already, advance to the next nonce repeat
|
||||||
|
while( GetCountSspClk() > sync_time) {
|
||||||
|
++elapsed_prng_sequences;
|
||||||
|
sync_time = (sync_time & 0xfffffff8 ) + sync_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked)
|
||||||
|
ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time);
|
||||||
|
|
||||||
|
// Receive the (4 Byte) "random" nonce from TAG
|
||||||
|
if (!ReaderReceive(receivedAnswer, receivedAnswerPar))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
previous_nt = nt;
|
||||||
|
nt = bytes_to_num(receivedAnswer, 4);
|
||||||
|
|
||||||
|
// Transmit reader nonce with fake par
|
||||||
|
ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL);
|
||||||
|
|
||||||
|
// we didn't calibrate our clock yet,
|
||||||
|
// iceman: has to be calibrated every time.
|
||||||
|
if (previous_nt && !nt_attacked) {
|
||||||
|
|
||||||
|
nt_distance = dist_nt(previous_nt, nt);
|
||||||
|
|
||||||
|
// if no distance between, then we are in sync.
|
||||||
|
if (nt_distance == 0) {
|
||||||
|
nt_attacked = nt;
|
||||||
|
} else {
|
||||||
|
if (nt_distance == -99999) { // invalid nonce received
|
||||||
|
unexpected_random++;
|
||||||
|
if (unexpected_random > MAX_UNEXPECTED_RANDOM) {
|
||||||
|
isOK = -3; // Card has an unpredictable PRNG. Give up
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (sync_cycles <= 0) sync_cycles += PRNG_SEQUENCE_LENGTH;
|
||||||
|
LED_B_OFF();
|
||||||
|
continue; // continue trying...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++sync_tries > MAX_SYNC_TRIES) {
|
||||||
|
isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_cycles = (sync_cycles - nt_distance)/elapsed_prng_sequences;
|
||||||
|
|
||||||
|
if (sync_cycles <= 0)
|
||||||
|
sync_cycles += PRNG_SEQUENCE_LENGTH;
|
||||||
|
|
||||||
|
if (MF_DBGLEVEL >= 4)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LED_B_OFF();
|
||||||
|
|
||||||
|
if ( (nt != nt_attacked) && nt_attacked) {
|
||||||
|
// we somehow lost sync. Try to catch up again...
|
||||||
|
catch_up_cycles = ABS(dist_nt(nt_attacked, nt));
|
||||||
|
|
||||||
|
if (catch_up_cycles == 99999) {
|
||||||
|
// invalid nonce received. Don't resync on that one.
|
||||||
|
catch_up_cycles = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// average?
|
||||||
|
catch_up_cycles /= elapsed_prng_sequences;
|
||||||
|
|
||||||
|
if (catch_up_cycles == last_catch_up) {
|
||||||
|
consecutive_resyncs++;
|
||||||
|
} else {
|
||||||
|
last_catch_up = catch_up_cycles;
|
||||||
|
consecutive_resyncs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consecutive_resyncs < 3) {
|
||||||
|
if (MF_DBGLEVEL >= 4)
|
||||||
|
Dbprintf("Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up...\n", i, catch_up_cycles, consecutive_resyncs);
|
||||||
|
} else {
|
||||||
|
sync_cycles += catch_up_cycles;
|
||||||
|
|
||||||
|
if (MF_DBGLEVEL >= 4)
|
||||||
|
Dbprintf("Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d.\n", i, catch_up_cycles, sync_cycles);
|
||||||
|
|
||||||
|
last_catch_up = 0;
|
||||||
|
catch_up_cycles = 0;
|
||||||
|
consecutive_resyncs = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding
|
||||||
|
if (ReaderReceive(receivedAnswer, receivedAnswerPar)) {
|
||||||
|
catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer
|
||||||
|
|
||||||
|
if (nt_diff == 0)
|
||||||
|
par_low = par[0] & 0xE0; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change
|
||||||
|
|
||||||
|
// Test if the information is complete
|
||||||
|
|
||||||
|
nt_diff = (nt_diff + 1) & 0x07;
|
||||||
|
mf_nr_ar[3] = (mf_nr_ar[3] & 0x1F) | (nt_diff << 5);
|
||||||
|
par[0] = par_low;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// No NACK.
|
||||||
|
if (nt_diff == 0) {
|
||||||
|
par[0]++;
|
||||||
|
if (par[0] == 0x00) { // tried all 256 possible parities without success. Card doesn't send NACK.
|
||||||
|
isOK = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Why this?
|
||||||
|
par[0] = ((par[0] & 0x1F) + 1) | par_low;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the resyncs since we got a complete transaction on right time.
|
||||||
|
consecutive_resyncs = 0;
|
||||||
|
} // end for loop
|
||||||
|
|
||||||
|
if (MF_DBGLEVEL >= 4) Dbprintf("Number of sent auth requestes: %u", i);
|
||||||
|
|
||||||
|
cmd_send(CMD_ACK, isOK, 0, 0, 0, 0 );
|
||||||
|
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
LEDsoff();
|
||||||
|
set_tracing(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*MIFARE 1K simulate.
|
*MIFARE 1K simulate.
|
||||||
|
@ -3155,7 +3379,6 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// MIFARE sniffer.
|
// MIFARE sniffer.
|
||||||
//
|
//
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "usb_cmd.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
#include "apps.h"
|
#include "apps.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -27,6 +28,7 @@ extern "C" {
|
||||||
#include "mifareutil.h"
|
#include "mifareutil.h"
|
||||||
#include "parity.h"
|
#include "parity.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
#include "mifare.h" // structs
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
enum {
|
enum {
|
||||||
|
@ -82,10 +84,13 @@ typedef struct {
|
||||||
uint8_t *parity;
|
uint8_t *parity;
|
||||||
} tUart;
|
} tUart;
|
||||||
|
|
||||||
|
|
||||||
extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
|
extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
|
||||||
extern void AppendCrc14443a(uint8_t *data, int len);
|
extern void AppendCrc14443a(uint8_t *data, int len);
|
||||||
|
|
||||||
|
// iso14443a.h
|
||||||
|
extern void RAMFUNC SniffIso14443a(uint8_t param);
|
||||||
|
extern void SimulateIso14443aTag(int tagType, int flags, uint8_t *data);
|
||||||
|
extern void ReaderIso14443a(UsbCommand *c);
|
||||||
extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing);
|
extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing);
|
||||||
extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing);
|
extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing);
|
||||||
extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing);
|
extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing);
|
||||||
|
@ -97,14 +102,20 @@ extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_da
|
||||||
extern int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
|
extern int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
|
||||||
extern void iso14a_set_trigger(bool enable);
|
extern void iso14a_set_trigger(bool enable);
|
||||||
|
|
||||||
int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen);
|
extern int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen);
|
||||||
int EmSend4bit(uint8_t resp);
|
extern int EmSend4bit(uint8_t resp);
|
||||||
extern int EmSendCmd(uint8_t *resp, uint16_t respLen);
|
extern int EmSendCmd(uint8_t *resp, uint16_t respLen);
|
||||||
extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity);
|
extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity);
|
||||||
int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
|
extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
|
||||||
|
extern int EmSendPrecompiledCmd(tag_response_info_t *response_info);
|
||||||
|
|
||||||
bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity,
|
bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity,
|
||||||
uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity);
|
uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity);
|
||||||
|
|
||||||
|
//extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size);
|
||||||
|
|
||||||
|
void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype );
|
||||||
|
void DetectNACKbug();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -2848,6 +2848,36 @@ int CmdHf14AMfSetMod(const char *Cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mifare NACK bug detection
|
||||||
|
int CmdHf14AMfNack(const char *Cmd) {
|
||||||
|
|
||||||
|
UsbCommand c = {CMD_MIFARE_NACK_DETECT, {0, 0, 0}};
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommand(&c);
|
||||||
|
UsbCommand resp;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
printf(".");
|
||||||
|
fflush(stdout);
|
||||||
|
if (ukbhit()) {
|
||||||
|
int gc = getchar(); (void)gc;
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
|
uint8_t ok = resp.arg[0] & 0xff;
|
||||||
|
PrintAndLog("isOk:%02x", ok);
|
||||||
|
if (!ok) {
|
||||||
|
PrintAndLog("Failed.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int CmdHF14AMfice(const char *Cmd) {
|
int CmdHF14AMfice(const char *Cmd) {
|
||||||
|
|
||||||
uint8_t blockNo = 0;
|
uint8_t blockNo = 0;
|
||||||
|
@ -2957,6 +2987,7 @@ static command_t CommandTable[] = {
|
||||||
{"decrypt", CmdHf14AMfDecryptBytes, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"},
|
{"decrypt", CmdHf14AMfDecryptBytes, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"},
|
||||||
{"setmod", CmdHf14AMfSetMod, 0, "Set MIFARE Classic EV1 load modulation strength"},
|
{"setmod", CmdHf14AMfSetMod, 0, "Set MIFARE Classic EV1 load modulation strength"},
|
||||||
{"ice", CmdHF14AMfice, 0, "collect Mifare Classic nonces to file"},
|
{"ice", CmdHF14AMfice, 0, "collect Mifare Classic nonces to file"},
|
||||||
|
{"nack", CmdHf14AMfNack, 0, "Test for Mifare NACK bug"},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ extern int CmdHF14AMfCLoad(const char* cmd);
|
||||||
extern int CmdHF14AMfCSave(const char* cmd);
|
extern int CmdHF14AMfCSave(const char* cmd);
|
||||||
extern int CmdHf14MfDecryptBytes(const char *Cmd);
|
extern int CmdHf14MfDecryptBytes(const char *Cmd);
|
||||||
extern int CmdHf14AMfSetMod(const char *Cmd);
|
extern int CmdHf14AMfSetMod(const char *Cmd);
|
||||||
|
extern int CmdHf14AMfNack(const char *Cmd);
|
||||||
|
|
||||||
void showSectorTable(void);
|
void showSectorTable(void);
|
||||||
void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose);
|
void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose);
|
||||||
|
|
|
@ -231,6 +231,7 @@ typedef struct{
|
||||||
#define CMD_MIFARE_DESFIRE 0x072e
|
#define CMD_MIFARE_DESFIRE 0x072e
|
||||||
|
|
||||||
#define CMD_MIFARE_COLLECT_NONCES 0x072f
|
#define CMD_MIFARE_COLLECT_NONCES 0x072f
|
||||||
|
#define CMD_MIFARE_NACK_DETECT 0x0730
|
||||||
|
|
||||||
#define CMD_HF_SNIFFER 0x0800
|
#define CMD_HF_SNIFFER 0x0800
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue