From c188b1b9b24b65a60c594364b474edba7c4ab8a2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 27 Nov 2015 16:24:00 +0100 Subject: [PATCH] ADD: @go_tus simple bruteforce for t55xx, refactored a bit. ADD: @pwpiwi 's implementation of Hardnested --- armsrc/appmain.c | 5 +- armsrc/apps.h | 1 + armsrc/epa.c | 2 +- armsrc/iso14443a.c | 32 ++++--- armsrc/iso14443a.h | 2 +- armsrc/mifarecmd.c | 162 +++++++++++++++++++++++++++++++---- armsrc/mifaredesfire.c | 4 +- client/Makefile | 1 + client/cmddata.c | 21 +++-- client/cmdhfmf.c | 100 +++++++++++++++++++++ client/cmdhfmf.h | 1 + client/cmdlft55xx.c | 77 ++++++++++++++--- client/cmdlft55xx.h | 2 + client/data.c | 10 +-- client/hid-flasher/usb_cmd.h | 2 + client/lualibs/commands.lua | 1 + common/lfdemod.h | 1 + include/usb_cmd.h | 1 + 18 files changed, 367 insertions(+), 58 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index b29a61010..4cbf5acdc 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -432,7 +432,7 @@ void StandAloneMode14a() SpinDelay(300); } } - if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid)) + if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid, true, 0)) continue; else { @@ -1131,6 +1131,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFAREU_WRITEBL: MifareUWriteBlock(c->arg[0], c->arg[1], c->d.asBytes); break; + case CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES: + MifareAcquireEncryptedNonces(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; case CMD_MIFARE_NESTED: MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 3baf11ae8..83cd94ec8 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -132,6 +132,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) //void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); diff --git a/armsrc/epa.c b/armsrc/epa.c index 737e633fc..b89d49565 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -529,7 +529,7 @@ int EPA_Setup() // power up the field iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); // select the card - return_code = iso14443a_select_card(uid, &card_select_info, NULL); + return_code = iso14443a_select_card(uid, &card_select_info, NULL, true, 0); if (return_code == 1) { // send the PPS request ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index e21378326..29d9728a0 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1896,10 +1896,12 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) return Demod.len; } -/* performs iso14443a anticollision procedure - * fills the uid pointer unless NULL - * fills resp_data unless NULL */ -int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr) { +// performs iso14443a anticollision (optional) and card select procedure +// fills the uid and cuid pointer unless NULL +// fills the card info record unless NULL +// if anticollision is false, then the UID must be provided in uid_ptr[] +// and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID) +int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades) { uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP uint8_t sel_all[] = { 0x93,0x20 }; uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; @@ -1914,7 +1916,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u int len; // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitBitsPar(wupa,7,0, NULL); + ReaderTransmitBitsPar(wupa, 7, NULL, NULL); // Receive the ATQA if(!ReaderReceive(resp, resp_par)) return 0; @@ -1925,10 +1927,12 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u memset(p_hi14a_card->uid,0,10); } + if (anticollision) { // clear uid if (uid_ptr) { memset(uid_ptr,0,10); } + } // check for proprietary anticollision: if ((resp[0] & 0x1F) == 0) { @@ -1942,6 +1946,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; + if (anticollision) { // SELECT_ALL ReaderTransmit(sel_all, sizeof(sel_all), NULL); if (!ReaderReceive(resp, resp_par)) return 0; @@ -1977,6 +1982,14 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u } else { // no collision, use the response to SELECT_ALL as current uid memcpy(uid_resp, resp, 4); } + } else { + if (cascade_level < num_cascades - 1) { + uid_resp[0] = 0x88; + memcpy(uid_resp+1, uid_ptr+cascade_level*3, 3); + } else { + memcpy(uid_resp, uid_ptr+cascade_level*3, 4); + } + } uid_resp_len = 4; // calculate crypto UID. Always use last 4 Bytes. @@ -1986,7 +1999,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u // Construct SELECT UID command sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) - memcpy(sel_uid+2, uid_resp, 4); // the UID + memcpy(sel_uid+2, uid_resp, 4); // the UID received during anticollision, or the provided UID sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC AppendCrc14443a(sel_uid, 7); // calculate and add CRC ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); @@ -2002,11 +2015,10 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u uid_resp[0] = uid_resp[1]; uid_resp[1] = uid_resp[2]; uid_resp[2] = uid_resp[3]; - uid_resp_len = 3; } - if(uid_ptr) { + if(uid_ptr && anticollision) { memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len); } @@ -2127,7 +2139,7 @@ void ReaderIso14443a(UsbCommand *c) iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); if(!(param & ISO14A_NO_SELECT)) { iso14a_card_select_t *card = (iso14a_card_select_t*)buf; - arg0 = iso14443a_select_card(NULL,card,NULL); + arg0 = iso14443a_select_card(NULL,card,NULL, true, 0); cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t)); } } @@ -2325,7 +2337,7 @@ void ReaderMifare(bool first_try) SpinDelay(100); } - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card"); continue; } diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 81871dc71..c9da0da7d 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -83,7 +83,7 @@ extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par); extern void iso14443a_setup(uint8_t fpga_minor_mode); extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data); -extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr); +extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades); extern void iso14a_set_trigger(bool enable); #endif /* __ISO14443A_H */ diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 1e42d5b45..be25273de 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -49,7 +49,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_C_OFF(); while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; @@ -96,7 +96,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ clear_trace(); - if(!iso14443a_select_card(NULL, NULL, NULL)) { + if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); OnError(0); return; @@ -131,7 +131,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) clear_trace(); - int len = iso14443a_select_card(NULL, NULL, NULL); + int len = iso14443a_select_card(NULL, NULL, NULL, true, 0); if(!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len); OnError(1); @@ -207,7 +207,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_C_OFF(); isOK = 1; - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { isOK = 0; if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); } @@ -271,7 +271,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) return; } - int len = iso14443a_select_card(NULL, NULL, NULL); + int len = iso14443a_select_card(NULL, NULL, NULL, true, 0); if (!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len); OnError(1); @@ -373,7 +373,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_C_OFF(); while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; @@ -427,7 +427,7 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) clear_trace(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - if(!iso14443a_select_card(uid, NULL, NULL)) { + if(!iso14443a_select_card(uid, NULL, NULL, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); OnError(0); return; @@ -473,7 +473,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) clear_trace(); - if(!iso14443a_select_card(NULL, NULL, NULL)) { + if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); OnError(0); return; @@ -532,7 +532,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ clear_trace(); - if(!iso14443a_select_card(NULL, NULL, NULL)) { + if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); OnError(0); return; @@ -597,6 +597,138 @@ int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) { } +//----------------------------------------------------------------------------- +// acquire encrypted nonces in order to perform the attack described in +// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened +// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on +// Computer and Communications Security, 2015 +//----------------------------------------------------------------------------- +void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain) +{ + uint64_t ui64Key = 0; + uint8_t uid[10]; + uint32_t cuid; + uint8_t cascade_levels = 0; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; + int16_t isOK = 0; + uint8_t par_enc[1]; + uint8_t nt_par_enc = 0; + uint8_t buf[USB_CMD_DATA_SIZE]; + uint32_t timeout; + + uint8_t blockNo = arg0 & 0xff; + uint8_t keyType = (arg0 >> 8) & 0xff; + uint8_t targetBlockNo = arg1 & 0xff; + uint8_t targetKeyType = (arg1 >> 8) & 0xff; + ui64Key = bytes_to_num(datain, 6); + bool initialize = flags & 0x0001; + bool slow = flags & 0x0002; + bool field_off = flags & 0x0004; + + #define AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) + #define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication + + LED_A_ON(); + LED_C_OFF(); + + if (initialize) { + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + } + + LED_C_ON(); + + uint16_t num_nonces = 0; + bool have_uid = false; + for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE - 9; ) { + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + isOK = 2; + field_off = true; + break; + } + + 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)) { + if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)"); + continue; + } + 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, NULL, false, cascade_levels)) { + if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); + continue; + } + } + + if (slow) { + timeout = GetCountSspClk() + PRE_AUTHENTICATION_LEADTIME; + while(GetCountSspClk() < timeout); + } + + uint32_t nt1; + if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) { + if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error"); + continue; + } + + // nested authentication + uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL); + if (len != 4) { + if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len); + continue; + } + + // send a dummy byte as reader response in order to trigger the cards authentication timeout + uint8_t dummy_answer = 0; + ReaderTransmit(&dummy_answer, 1, NULL); + timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT; + + num_nonces++; + if (num_nonces % 2) { + memcpy(buf+i, receivedAnswer, 4); + nt_par_enc = par_enc[0] & 0xf0; + } else { + nt_par_enc |= par_enc[0] >> 4; + memcpy(buf+i+4, receivedAnswer, 4); + memcpy(buf+i+8, &nt_par_enc, 1); + i += 9; + } + + // wait for the card to become ready again + while(GetCountSspClk() < timeout); + + } + + LED_C_OFF(); + + crypto1_destroy(pcs); + + LED_B_ON(); + cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); + LED_B_OFF(); + + if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); + + if (field_off) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + } +} + + //----------------------------------------------------------------------------- // MIFARE nested authentication. // @@ -668,7 +800,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat continue; } - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); rtr--; continue; @@ -741,7 +873,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat continue; } - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); continue; }; @@ -857,7 +989,7 @@ void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error"); } - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card"); break; }; @@ -952,7 +1084,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai bool isOK = true; - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { isOK = false; if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); } @@ -1051,7 +1183,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain){ // read UID and return to client if (workFlags & MAGIC_UID) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); OnErrorMagic(MAGIC_UID); }; @@ -1222,7 +1354,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); - int len = iso14443a_select_card(uid, NULL, &cuid); + int len = iso14443a_select_card(uid, NULL, &cuid, true, 0); if(!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); OnError(1); diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index cacd767f9..8336d7933 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -25,7 +25,7 @@ bool InitDesfireCard(){ byte_t cardbuf[USB_CMD_DATA_SIZE] = {0x00}; iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; - int len = iso14443a_select_card(NULL,card,NULL); + int len = iso14443a_select_card(NULL,card,NULL,true,0); if (!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) @@ -114,7 +114,7 @@ void MifareDesfireGetInformation(){ // card select - information iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; - byte_t isOK = iso14443a_select_card(NULL, card, NULL); + byte_t isOK = iso14443a_select_card(NULL, card, NULL, true, 0); if ( isOK == 0) { if (MF_DBGLEVEL >= MF_DBG_ERROR) { Dbprintf("Can't select card"); diff --git a/client/Makefile b/client/Makefile index bcd593971..27617a5dd 100644 --- a/client/Makefile +++ b/client/Makefile @@ -109,6 +109,7 @@ CMDSRCS = nonce2key/crapto1.c\ cmdhficlass.c \ cmdhfmf.c \ cmdhfmfu.c \ +cmdhfmfhard.c \ cmdhfmfdes.c \ cmdhftopaz.c \ cmdhw.c \ diff --git a/client/cmddata.c b/client/cmddata.c index aaff0302f..aeabd9856 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -1987,7 +1987,11 @@ int getSamples(const char *Cmd, bool silent) GetFromBigBuf(got,n,0); PrintAndLog("Data fetched"); UsbCommand response; - WaitForResponse(CMD_ACK, &response); + if ( !WaitForResponseTimeout(CMD_ACK, &response, 10000) ) { + PrintAndLog("timeout while waiting for reply."); + return 1; + } + uint8_t bits_per_sample = 8; //Old devices without this feature would send 0 at arg[0] @@ -2030,9 +2034,9 @@ int CmdTuneSamples(const char *Cmd) int timeout = 0; printf("\nMeasuring antenna characteristics, please wait..."); - UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING}; + UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING, {0,0,0}}; + clearCommandBuffer(); SendCommand(&c); - UsbCommand resp; while(!WaitForResponseTimeout(CMD_MEASURED_ANTENNA_TUNING,&resp,1000)) { timeout++; @@ -2080,7 +2084,6 @@ int CmdTuneSamples(const char *Cmd) ShowGraphWindow(); RepaintGraphWindow(); } - return 0; } @@ -2096,7 +2099,7 @@ int CmdLoad(const char *Cmd) FILE *f = fopen(filename, "r"); if (!f) { - PrintAndLog("couldn't open '%s'", filename); + PrintAndLog("couldn't open '%s'", filename); return 0; } @@ -2115,11 +2118,13 @@ int CmdLoad(const char *Cmd) int CmdLtrim(const char *Cmd) { int ds = atoi(Cmd); - if (GraphTraceLen<=0) return 0; + + if (GraphTraceLen <= 0) return 0; + for (int i = ds; i < GraphTraceLen; ++i) GraphBuffer[i-ds] = GraphBuffer[i]; - GraphTraceLen -= ds; + GraphTraceLen -= ds; RepaintGraphWindow(); return 0; } @@ -2128,9 +2133,7 @@ int CmdLtrim(const char *Cmd) int CmdRtrim(const char *Cmd) { int ds = atoi(Cmd); - GraphTraceLen = ds; - RepaintGraphWindow(); return 0; } diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 1d1dc2f43..ae380b3c3 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" +#include "cmdhfmfhard.h" #include "nonce2key/nonce2key.h" static int CmdHelp(const char *Cmd); @@ -791,6 +792,104 @@ int CmdHF14AMfNested(const char *Cmd) return 0; } + +int CmdHF14AMfNestedHard(const char *Cmd) +{ + uint8_t blockNo = 0; + uint8_t keyType = 0; + uint8_t trgBlockNo = 0; + uint8_t trgKeyType = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + + char ctmp; + ctmp = param_getchar(Cmd, 0); + if (ctmp != 'R' && ctmp != 'r' && strlen(Cmd) < 20) { + PrintAndLog("Usage:"); + PrintAndLog(" hf mf hardnested "); + PrintAndLog(" [w] [s]"); + PrintAndLog(" or hf mf hardnested r"); + PrintAndLog(" "); + PrintAndLog("Options: "); + PrintAndLog(" w: Acquire nonces and write them to binary file nonces.bin"); + PrintAndLog(" s: Slower acquisition (required by some non standard cards)"); + PrintAndLog(" r: Read nonces.bin and start attack"); + PrintAndLog(" "); + PrintAndLog(" sample1: hf mf hardnested 0 A FFFFFFFFFFFF 4 A"); + PrintAndLog(" sample2: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w"); + PrintAndLog(" sample3: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w s"); + PrintAndLog(" sample4: hf mf hardnested r"); + + return 0; + } + + bool nonce_file_read = false; + bool nonce_file_write = false; + bool slow = false; + + if (ctmp == 'R' || ctmp == 'r') { + + nonce_file_read = true; + + } else { + + blockNo = param_get8(Cmd, 0); + ctmp = param_getchar(Cmd, 1); + if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') { + keyType = 1; + } + + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } + + trgBlockNo = param_get8(Cmd, 3); + ctmp = param_getchar(Cmd, 4); + if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') { + PrintAndLog("Target key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') { + trgKeyType = 1; + } + + uint16_t i = 5; + while ((ctmp = param_getchar(Cmd, i))) { + if (ctmp == 's' || ctmp == 'S') { + slow = true; + } else if (ctmp == 'w' || ctmp == 'W') { + nonce_file_write = true; + } else { + PrintAndLog("Possible options are w and/or s"); + return 1; + } + i++; + } + } + + PrintAndLog("--target block no:%3d, target key type:%c, file action: %s, Slow: %s ", + trgBlockNo, + trgKeyType?'B':'A', + nonce_file_write?"write":nonce_file_read?"read":"none", + slow?"Yes":"No"); + int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, nonce_file_read, nonce_file_write, slow); + if (isOK) { + switch (isOK) { + case 1 : PrintAndLog("Error: No response from Proxmark.\n"); break; + case 2 : PrintAndLog("Button pressed. Aborted.\n"); break; + default : break; + } + return 2; + } + + return 0; +} + + int CmdHF14AMfChk(const char *Cmd) { if (strlen(Cmd)<3) { @@ -2017,6 +2116,7 @@ static command_t CommandTable[] = {"chk", CmdHF14AMfChk, 0, "Test block keys"}, {"mifare", CmdHF14AMifare, 0, "Read parity error messages."}, {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, + {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"}, {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 19adbe304..31c84dc47 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -38,6 +38,7 @@ int CmdHF14AMfUWrBl(const char* cmd); int CmdHF14AMfChk(const char* cmd); int CmdHF14AMifare(const char* cmd); int CmdHF14AMfNested(const char* cmd); +int CmdHF14AMfNestedHard(const char *Cmd); int CmdHF14AMfSniff(const char* cmd); int CmdHF14AMf1kSim(const char* cmd); int CmdHF14AMfEClear(const char* cmd); diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index d864c9ed0..2605784e8 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -134,7 +134,7 @@ int usage_t55xx_detect(){ PrintAndLog("Examples:"); PrintAndLog(" lf t55xx detect"); PrintAndLog(" lf t55xx detect 1"); - PrintAndLog(" lf t55xx detect 11223344"); + PrintAndLog(" lf t55xx detect p 11223344"); PrintAndLog(""); return 0; } @@ -149,6 +149,14 @@ int usage_t55xx_wakup(){ PrintAndLog(" lf t55xx wakeup p 11223344 - send wakeup password"); return 0; } +int usage_t55xx_bruteforce(){ + PrintAndLog("Usage: lf t55xx bruteforce "); + PrintAndLog(" password must be 4 bytes (8 hex symbols)"); + PrintAndLog("Examples:"); + PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); + PrintAndLog(""); + return 0; +} static int CmdHelp(const char *Cmd); @@ -1307,20 +1315,61 @@ int CmdT55xxWipe(const char *Cmd) { return 0; } +int CmdT55xxBruteForce(const char *Cmd) { + uint32_t start_password = 0x00000000; //start password + uint32_t end_password = 0xFFFFFFFF; //end password + + bool found = false; + char cmdp = param_getchar(Cmd, 0); + if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_bruteforce(); + + start_password = param_get32ex(Cmd, 0, 0, 16); + end_password = param_get32ex(Cmd, 1, 0, 16); + + if ( start_password == end_password ) return usage_t55xx_bruteforce(); + + PrintAndLog("Start Password %08x", start_password); + PrintAndLog(" End Password %08x", end_password); + + int i = start_password; + + while ((!found) && (i <= end_password)){ + + AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, TRUE, i); + found = tryDetectModulation(); + + if (found) + break; + + if ((i % 0x100) == 0) printf("[%08x], ",i); + + i++; + } + + PrintAndLog(""); + + if (found) + PrintAndLog("Found Password [%08x]", i); + else + PrintAndLog("NOT Found Last Password [%08x]", i); + return 0; +} + static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, - {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, - {"read", CmdT55xxReadBlock, 0, "b p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]"}, - {"resetread",CmdResetRead, 0, "Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)"}, - {"write", CmdT55xxWriteBlock,0, "b d p [password] [1] -- Write T55xx block data. Optional [p password], [page1]"}, - {"trace", CmdT55xxReadTrace, 1, "[1] Show T55x7 traceability data (page 1/ blk 0-1)"}, - {"info", CmdT55xxInfo, 1, "[1] Show T55x7 configuration data (page 0/ blk 0)"}, - {"dump", CmdT55xxDump, 0, "[password] [o] Dump T55xx card block 0-7. Optional [password], [override]"}, - {"special", special, 0, "Show block changes with 64 different offsets"}, - {"wakeup", CmdT55xxWakeUp, 0, "Send AOR wakeup command"}, - {"wipe", CmdT55xxWipe, 0, "Wipe a T55xx tag and set defaults (will destroy any data on tag)"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"bruceforce", CmdT55xxBruteForce,0, "Simple bruteforce attack to find password"}, + {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, + {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, + {"dump", CmdT55xxDump, 0, "[password] [o] Dump T55xx card block 0-7. Optional [password], [override]"}, + {"info", CmdT55xxInfo, 1, "[1] Show T55x7 configuration data (page 0/ blk 0)"}, + {"read", CmdT55xxReadBlock, 0, "b p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]"}, + {"resetread", CmdResetRead, 0, "Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)"}, + {"special", special, 0, "Show block changes with 64 different offsets"}, + {"trace", CmdT55xxReadTrace, 1, "[1] Show T55x7 traceability data (page 1/ blk 0-1)"}, + {"wakeup", CmdT55xxWakeUp, 0, "Send AOR wakeup command"}, + {"wipe", CmdT55xxWipe, 0, "Wipe a T55xx tag and set defaults (will destroy any data on tag)"}, + {"write", CmdT55xxWriteBlock,0, "b d p [password] [1] -- Write T55xx block data. Optional [p password], [page1]"}, + {NULL, NULL, 0, NULL} }; int CmdLFT55XX(const char *Cmd) { diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index a58fa44e7..77963fde3 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -75,6 +75,7 @@ int CmdT55xxInfo(const char *Cmd); int CmdT55xxDetect(const char *Cmd); int CmdResetRead(const char *Cmd); int CmdT55xxWipe(const char *Cmd); +int CmdT55xxBruteForce(const char *Cmd); char * GetBitRateStr(uint32_t id); char * GetSaferStr(uint32_t id); @@ -92,4 +93,5 @@ bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5) int special(const char *Cmd); int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ); +bool detectPassword(int password); #endif diff --git a/client/data.c b/client/data.c index 4d7d1e410..1725944eb 100644 --- a/client/data.c +++ b/client/data.c @@ -17,9 +17,9 @@ uint8_t* sample_buf; -void GetFromBigBuf(uint8_t *dest, int bytes, int start_index) -{ - sample_buf = dest; - UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}}; - SendCommand(&c); +void GetFromBigBuf(uint8_t *dest, int bytes, int start_index) { + sample_buf = dest; + UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}}; + clearCommandBuffer(); + SendCommand(&c); } diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h index 01b2d83b1..be0cf9ced 100644 --- a/client/hid-flasher/usb_cmd.h +++ b/client/hid-flasher/usb_cmd.h @@ -168,6 +168,8 @@ typedef struct{ #define CMD_READER_MIFARE 0x0611 #define CMD_MIFARE_NESTED 0x0612 +#define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613 + #define CMD_MIFARE_READBL 0x0620 #define CMD_MIFAREU_READBL 0x0720 diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index 957c99b46..92fc9bb0b 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -129,6 +129,7 @@ local _commands = { CMD_READER_MIFARE = 0x0611, CMD_MIFARE_NESTED = 0x0612, + CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES = 0x0613, CMD_MIFARE_READBL = 0x0620, CMD_MIFAREU_READBL = 0x0720, diff --git a/common/lfdemod.h b/common/lfdemod.h index 20eb67695..a1d99e113 100644 --- a/common/lfdemod.h +++ b/common/lfdemod.h @@ -16,6 +16,7 @@ #include //generic +uint8_t justNoise(uint8_t *BitStream, size_t size); size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType); int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType); int BiphaseRawDecode(uint8_t * BitStream, size_t *size, int offset, int invert); diff --git a/include/usb_cmd.h b/include/usb_cmd.h index ff20fde76..d2f746a7c 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -171,6 +171,7 @@ typedef struct{ #define CMD_READER_MIFARE 0x0611 #define CMD_MIFARE_NESTED 0x0612 +#define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613 #define CMD_MIFARE_READBL 0x0620 #define CMD_MIFAREU_READBL 0x0720