From f215ebef80c5875d4d5f1fcbe6c569bf9bb8294d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 11 Jan 2019 14:46:27 +0100 Subject: [PATCH] Refactored 'lf t55xx brute', split it up into two commands. - lf t55xx brute (tries bruteforcing a range of pwds - lf t55xx chk (uses dictionary file or RDV4 flashmem) FIX: adjust lf sim (@marshmellow42) see https://github.com/marshmellow42/proxmark3/commit/7008cf9c15a135a066227635e64f59285eb73a80 "attempt to speed up the loops waiting for carrier signal to go high or low by only checking for a halt (button press or usbpol) every 256th loop iteration. some users were experiencing modulating reactions to be too slow. ADD: 'lf t55xx chk' It uses @marshmellows42 idea behind commit (https://github.com/marshmellow42/proxmark3/commit/6178b085a0374e656cce3849e481fa5800403c2b) With calculating a baseline (read block0 32times and average the signal-ish) and sampling only 1024 signal data. The algo then proceeds to calc the average and keep track of the candidate which is given the most difference in signal data average value. I do some squaring and shifting for this. The candidate is then send back to client to be tested properly with trymodulation like before. This seems to work good on t55xx card which has a ASK configuration. WORK-IN-PROGRESS --- armsrc/appmain.c | 3 + armsrc/apps.h | 2 + armsrc/lfops.c | 153 +++++++++++++++++++++++++++++++++++++++----- client/cmdlft55xx.c | 153 ++++++++++++++++++++++++++++++++------------ client/cmdlft55xx.h | 1 + include/usb_cmd.h | 2 + 6 files changed, 255 insertions(+), 59 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 8759f93c4..0bf9ccb9d 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -724,6 +724,9 @@ void UsbPacketReceived(uint8_t *packet, int len) { case CMD_T55XX_RESET_READ: T55xxResetRead(); break; + case CMD_T55XX_CHKPWDS: + T55xx_ChkPwds(); + break; case CMD_PCF7931_READ: ReadPCF7931(); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 7e45d5e50..d17d9ef4b 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -103,6 +103,8 @@ void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode void T55xxWriteBlockExt(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode); void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd); void T55xxWakeUp(uint32_t Pwd); +void T55xx_ChkPwds(void); + void TurnReadLFOn(uint32_t delay); void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd); void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index e690714df..47f0cb324 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -598,9 +598,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; + + uint8_t check = 1; for(;;) { - + if ( numcycles > -1 ) { if ( x != numcycles ) { ++x; @@ -616,9 +618,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle // used as a simple detection of a reader field? while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { WDT_HIT(); - if ( usb_poll_validate_length() || BUTTON_PRESS() ) - goto OUT; - } + if ( !check ) { + if ( usb_poll_validate_length() || BUTTON_PRESS() ) + goto OUT; + } + ++check; } if (buf[i]) OPEN_COIL(); @@ -628,9 +632,11 @@ void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycle //wait until SSC_CLK goes LOW while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); - //if ( usb_poll_validate_length() || BUTTON_PRESS() ) - if ( BUTTON_PRESS() ) - goto OUT; + if ( !check ) { + if ( usb_poll_validate_length() || BUTTON_PRESS() ) + goto OUT; + } + ++check; } i++; @@ -1489,11 +1495,22 @@ void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg) { // Read one card block in page [page] void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode + bool PwdMode = arg0 & 0x1; + uint8_t Page = ( arg0 & 0x2 ) >> 1; + bool brute_mem = arg0 & 0x4; + uint32_t i = 0; + + // regular read mode + bool RegReadMode = (Block == 0xFF); + + uint8_t start_wait = 4; + size_t samples = 12000; + if ( brute_mem ) { + start_wait = 0; + samples = 1024; + } + //clear buffer now so it does not interfere with timing later BigBuf_Clear_keep_EM(); @@ -1505,7 +1522,8 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Set up FPGA, 125kHz to power up the tag LFSetupFPGAForADC(95, true); // make sure tag is fully powered up... - WaitMS(4); + WaitMS(start_wait); + // Trigger T55x7 Direct Access Mode with start gap FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(t_config.start_gap); @@ -1529,17 +1547,118 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Turn field on to read the response // 137*8 seems to get to the start of data pretty well... - // but we want to go past the start and let the repeating data settle in... + // but we want to go past the start and let the repeating data settle in... TurnReadLFOn(210*8); // Acquisition // Now do the acquisition - DoPartialAcquisition(0, true, 12000, 0); + DoPartialAcquisition(0, true, samples, 0); // Turn the field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); + if ( !brute_mem ) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); + } +} + +void T55xx_ChkPwds() { + + DbpString("[+] T55XX Check pwds using flashmemory starting"); + + uint8_t ret = 0; + // First get baseline and setup LF mode. + // tends to mess up BigBuf + uint8_t *buf = BigBuf_get_addr(); + + uint32_t b1, baseline = 0; + + // collect baseline for failed attempt + uint8_t x = 32; + while (x--) { + b1 = 0; + T55xxReadBlock(4, 1, 0); + for (uint16_t j=0; j < 1024; ++j) + b1 += buf[j]; + + b1 *= b1; + b1 >>= 8; + baseline += b1; + } + + baseline >>= 5; + Dbprintf("[=] Baseline determined [%u]", baseline); + + + uint8_t *pwds = BigBuf_get_EM_addr(); + bool use_flashmem = true; + uint16_t pwdCount = 0; + uint32_t candidate = 0; + +#ifdef WITH_FLASH + if ( use_flashmem ) { + BigBuf_Clear_EM(); + uint16_t isok = 0; + uint8_t counter[2] = {0x00, 0x00}; + isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET, counter, sizeof(counter) ); + if ( isok != sizeof(counter) ) + goto OUT; + + pwdCount = counter[1] << 8 | counter[0]; + + if ( pwdCount == 0 && pwdCount == 0xFFFF) + goto OUT; + + isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET+2, pwds, pwdCount * 4); + if ( isok != pwdCount * 4 ) + goto OUT; + + Dbprintf("[=] Password dictionary count %d ", pwdCount); + } +#endif + + uint32_t pwd = 0, curr = 0, prev = 0; + for (uint16_t i =0; i< pwdCount; ++i) { + + if (BUTTON_PRESS() && !usb_poll_validate_length()) { + goto OUT; + } + + pwd = bytes_to_num(pwds + i * 4, 4); + + + T55xxReadBlock(5, 0, pwd); + + // calc mean of BigBuf 1024 samples. + uint32_t sum = 0; + for (uint16_t j=0; j<1024; ++j) { + sum += buf[j]; + } + + sum *= sum; + sum >>= 8; + + int32_t tmp = (sum - baseline); + curr = ABS(tmp); + + Dbprintf("[=] Pwd %08X | ABS %u", pwd, curr ); + + if ( curr > prev ) { + + + Dbprintf("[=] --> ABS %u Candidate %08X <--", curr, pwd ); + candidate = pwd; + prev = curr; + } + } + + if ( candidate ) + ret = 1; + +OUT: + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + cmd_send(CMD_ACK,ret,candidate,0,0,0); + LEDsoff(); } void T55xxWakeUp(uint32_t Pwd){ diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index ed8c0464e..29487e026 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -141,21 +141,33 @@ int usage_t55xx_wakup(){ PrintAndLogEx(NORMAL, " lf t55xx wakeup p 11223344 - send wakeup password"); return 0; } -int usage_t55xx_bruteforce(){ - PrintAndLogEx(NORMAL, "This command uses A) bruteforce to scan a number range"); - PrintAndLogEx(NORMAL, " B) a dictionary attack"); +int usage_t55xx_chk(){ + PrintAndLogEx(NORMAL, "This command uses a dictionary attack"); PrintAndLogEx(NORMAL, "press 'enter' to cancel the command"); - PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] [i <*.dic>]"); + PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] [i <*.dic>]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " m - use dictionary from flashmemory\n"); + PrintAndLogEx(NORMAL, " i <*.dic> - loads a default keys dictionary file <*.dic>"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " lf t55xx bruteforce m"); + PrintAndLogEx(NORMAL, " lf t55xx bruteforce i default_pwd.dic"); + PrintAndLogEx(NORMAL, ""); + return 0; +} +int usage_t55xx_bruteforce(){ + PrintAndLogEx(NORMAL, "This command uses bruteforce to scan a number range"); + PrintAndLogEx(NORMAL, "press 'enter' to cancel the command"); + PrintAndLogEx(NORMAL, "Usage: lf t55xx bruteforce [h] "); PrintAndLogEx(NORMAL, " password must be 4 bytes (8 hex symbols)"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " - 4 byte hex value to start pwd search at"); PrintAndLogEx(NORMAL, " - 4 byte hex value to end pwd search at"); - PrintAndLogEx(NORMAL, " i <*.dic> - loads a default keys dictionary file <*.dic>"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf t55xx bruteforce aaaaaaaa bbbbbbbb"); - PrintAndLogEx(NORMAL, " lf t55xx bruteforce i default_pwd.dic"); PrintAndLogEx(NORMAL, ""); return 0; } @@ -224,10 +236,9 @@ int CmdT55xxSetConfig(const char *Cmd) { uint8_t cmdp = 0; bool errors = false; while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - tmp = param_getchar(Cmd, cmdp); + tmp = tolower(param_getchar(Cmd, cmdp)); switch(tmp) { case 'h': - case 'H': return usage_t55xx_config(); case 'b': errors |= param_getdec(Cmd, cmdp+1, &bitRate); @@ -292,12 +303,10 @@ int CmdT55xxSetConfig(const char *Cmd) { config.offset = offset; cmdp+=2; break; - case 'Q': case 'q': config.Q5 = true; cmdp++; break; - case 'S': case 's': config.ST = true; cmdp++; @@ -343,8 +352,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 if (!AquireData(page1, block, usepwd, password) ) return 0; if (!DecodeT55xxBlock()) return 0; - char blk[10]={0}; - sprintf(blk,"%02d", block); + char blk[10] = {0}; + sprintf(blk, "%02d", block); printT55xxBlock(blk); return 1; } @@ -358,22 +367,18 @@ int CmdT55xxReadBlock(const char *Cmd) { bool errors = false; uint8_t cmdp = 0; while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + switch ( tolower(param_getchar(Cmd, cmdp))) { case 'h': - case 'H': return usage_t55xx_read(); case 'b': - case 'B': errors |= param_getdec(Cmd, cmdp+1, &block); cmdp += 2; break; case 'o': - case 'O': override = true; cmdp++; break; case 'p': - case 'P': password = param_get32ex(Cmd, cmdp+1, 0, 16); usepwd = true; cmdp += 2; @@ -1503,23 +1508,68 @@ bool IsCancelled(void) { return false; } -int CmdT55xxBruteForce(const char *Cmd) { - +int CmdT55xxChkPwds(const char *Cmd) { // load a default pwd file. char line[9]; char filename[FILE_PATH_SIZE] = {0}; int keycnt = 0; uint8_t stKeyBlock = 20; uint8_t *keyBlock = NULL, *p = NULL; - uint32_t start_password = 0x00000000; //start password - uint32_t end_password = 0xFFFFFFFF; //end password bool found = false; + uint8_t timeout = 0; memset(line, 0, sizeof(line)); char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_t55xx_bruteforce(); + if (cmdp == 'h') return usage_t55xx_chk(); + + /* + if ( T55xxReadBlock(7, 0, 0, 0, 0) ) { + + // now try to validate it.. + PrintAndLogEx(WARNING, "\n Block 7 was readable"); + return 1; + } + */ + + uint64_t t1 = msclock(); + if ( cmdp == 'm' ) { + UsbCommand c = {CMD_T55XX_CHKPWDS, {0,0,0} }; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + + while ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { + timeout++; + printf("."); fflush(stdout); + if (timeout > 180) { + PrintAndLogEx(WARNING, "\nno response from Proxmark. Aborting..."); + return 2; + } + } + + if ( resp.arg[0] ) { + PrintAndLogEx(SUCCESS, "\nFound a candidate [ %08X ]. Trying to validate", resp.arg[1]); + + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, resp.arg[1])) { + PrintAndLogEx(NORMAL, "Aquireing data from device failed. Quitting"); + return 2; + } + + found = tryDetectModulation(); + if (found) { + PrintAndLogEx(NORMAL, "Found valid password: [ %08X ]", resp.arg[1]); + } else { + PrintAndLogEx(NORMAL, "Password NOT found."); + } + } else { + PrintAndLogEx(NORMAL, "Password NOT found."); + } + + goto out; + } + keyBlock = calloc(stKeyBlock, 4); if (keyBlock == NULL) return 1; @@ -1569,7 +1619,7 @@ int CmdT55xxBruteForce(const char *Cmd) { num_to_bytes( strtoll(line, NULL, 16), 4, keyBlock + 4*keycnt); - PrintAndLogEx(NORMAL, "chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4 * keycnt, 4) ); +// PrintAndLogEx(NORMAL, "chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4 * keycnt, 4) ); keycnt++; memset(line, 0, sizeof(line)); } @@ -1609,60 +1659,78 @@ int CmdT55xxBruteForce(const char *Cmd) { } found = tryDetectModulation(); - if ( found ) { - PrintAndLogEx(NORMAL, "Found valid password: [%08X]", testpwd); - //free(keyBlock); - //return 0; - } + if ( found ) + break; + } - PrintAndLogEx(NORMAL, "Password NOT found."); - free(keyBlock); - return 0; + if ( found ) + PrintAndLogEx(NORMAL, "Found valid password: [ %08X ]", testpwd); + else + PrintAndLogEx(NORMAL, "Password NOT found."); } + free(keyBlock); + +out: + t1 = msclock() - t1; + PrintAndLogEx(SUCCESS, "\nTime in bruteforce: %.0f seconds\n", (float)t1/1000.0); + return 0; +} + +int CmdT55xxBruteForce(const char *Cmd) { + + uint32_t start_password = 0x00000000; //start password + uint32_t end_password = 0xFFFFFFFF; //end password + uint32_t curr = 0; + bool found = false; + + + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_t55xx_bruteforce(); + + uint64_t t1 = msclock(); + // Try to read Block 7, first :) // incremental pwd range search start_password = param_get32ex(Cmd, 0, 0, 16); end_password = param_get32ex(Cmd, 1, 0, 16); + curr = start_password; + if ( start_password >= end_password ) { - free(keyBlock); return usage_t55xx_bruteforce(); } PrintAndLogEx(NORMAL, "Search password range [%08X -> %08X]", start_password, end_password); - - uint32_t i = start_password; - while ((!found) && (i <= end_password)){ + while ((!found) || (curr <= end_password)){ printf("."); fflush(stdout); if (IsCancelled()) { - free(keyBlock); return 0; } - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) { + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr)) { PrintAndLogEx(NORMAL, "Aquireing data from device failed. Quitting"); - free(keyBlock); return 0; } found = tryDetectModulation(); if (found) break; - i++; + ++curr; } PrintAndLogEx(NORMAL, ""); if (found) - PrintAndLogEx(NORMAL, "Found valid password: [%08x]", i); + PrintAndLogEx(NORMAL, "Found valid password: [ %08X ]", curr); else - PrintAndLogEx(NORMAL, "Password NOT found. Last tried: [%08x]", --i); + PrintAndLogEx(NORMAL, "Password NOT found. Last tried: [ %08X ]", --curr); - free(keyBlock); + t1 = msclock() - t1; + PrintAndLogEx(SUCCESS, "\nTime in bruteforce: %.0f seconds\n", (float)t1/1000.0); return 0; } @@ -1959,6 +2027,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"bruteforce", CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, + {"chk", CmdT55xxChkPwds, 1, "Check passwords"}, {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, {"deviceconfig", CmdT55xxSetDeviceConfig, 1, "Set/Get T55XX device configuration (startgap, writegap, write0, write1, readgap"}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 15adab0b6..46de0c359 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -133,6 +133,7 @@ t55xx_conf_block_t Get_t55xx_Config(void); void Set_t55xx_Config(t55xx_conf_block_t conf); extern int CmdLFT55XX(const char *Cmd); +extern int CmdT55xxChk(const char *Cmd); extern int CmdT55xxBruteForce(const char *Cmd); extern int CmdT55xxSetConfig(const char *Cmd); extern int CmdT55xxReadBlock(const char *Cmd); diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 44d031334..a54b27e0f 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -140,6 +140,8 @@ typedef struct{ #define CMD_COTAG 0x0225 #define CMD_SET_LF_T55XX_CONFIG 0x0226 +#define CMD_T55XX_CHKPWDS 0x0230 + /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ // For the 13.56 MHz tags