diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 6b127c831..aa0f23d8f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -978,6 +978,15 @@ static void PacketReceived(PacketCommandNG *packet) { EM4xLogin(payload->password); break; } + case CMD_LF_EM4X_BF: { + struct p { + uint32_t start_pwd; + uint32_t n; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + EM4xBruteforce(payload->start_pwd, payload->n); + break; + } case CMD_LF_EM4X_READWORD: { struct p { uint32_t password; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 4d25bd314..3d7154eb3 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -2467,7 +2467,7 @@ static uint8_t Prepare_Data(uint16_t data_low, uint16_t data_hi) { // Requires: forwarLink_data filled with valid bits (1 bit per byte) // fwd_bit_count set with number of bits to be sent //==================================================================== -static void SendForward(uint8_t fwd_bit_count) { +static void SendForward(uint8_t fwd_bit_count, bool fast) { // iceman, 21.3us increments for the USclock verification. // 55FC * 8us == 440us / 21.3 === 20.65 steps. could be too short. Go for 56FC instead @@ -2480,9 +2480,10 @@ static void SendForward(uint8_t fwd_bit_count) { fwd_write_ptr = forwardLink_data; fwd_bit_sz = fwd_bit_count; - // Set up FPGA, 125kHz or 95 divisor - LFSetupFPGAForADC(LF_DIVISOR_125, true); - + if (! fast) { + // Set up FPGA, 125kHz or 95 divisor + LFSetupFPGAForADC(LF_DIVISOR_125, true); + } // force 1st mod pulse (start gap must be longer for 4305) fwd_bit_sz--; //prepare next bit modulation fwd_write_ptr++; @@ -2505,13 +2506,59 @@ static void EM4xLoginEx(uint32_t pwd) { forward_ptr = forwardLink_data; uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN); len += Prepare_Data(pwd & 0xFFFF, pwd >> 16); - SendForward(len); + SendForward(len, false); //WaitUS(20); // no wait for login command. // should receive // 0000 1010 ok // 0000 0001 fail } +void EM4xBruteforce(uint32_t start_pwd, uint32_t n) { + // With current timing, 18.6 ms per test = 53.8 pwds/s + reply_ng(CMD_LF_EM4X_BF, PM3_SUCCESS, NULL, 0); + StartTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitMS(20); + LED_A_ON(); + LFSetupFPGAForADC(LF_DIVISOR_125, true); + uint32_t candidates_found = 0; + for (uint32_t pwd = start_pwd; pwd < 0xFFFFFFFF; pwd++) { + if (((pwd - start_pwd) & 0x3F) == 0x00) { + WDT_HIT(); + if (BUTTON_PRESS() || data_available()) { + Dbprintf("EM4x05 Bruteforce Interrupted"); + break; + } + } + // Report progress every 256 attempts + if (((pwd - start_pwd) & 0xFF) == 0x00) { + Dbprintf("Trying: %06Xxx", pwd >> 8); + } + clear_trace(); + + forward_ptr = forwardLink_data; + uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN); + len += Prepare_Data(pwd & 0xFFFF, pwd >> 16); + SendForward(len, true); + + WaitUS(400); + DoPartialAcquisition(0, false, 350, 1000); + uint8_t *mem = BigBuf_get_addr(); + if (mem[334] < 128) { + Dbprintf("Password candidate: " _GREEN_("%08X"), pwd); + if ((n != 0) && (candidates_found == n)) { + Dbprintf("EM4x05 Bruteforce Stopped. %i candidates found", candidates_found); + break; + } + } + // Beware: if smaller, tag might not have time to be back in listening state yet + WaitMS(1); + } + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + void EM4xLogin(uint32_t pwd) { StartTicks(); @@ -2558,7 +2605,7 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { uint8_t len = Prepare_Cmd(FWD_CMD_READ); len += Prepare_Addr(addr); - SendForward(len); + SendForward(len, false); WaitUS(400); @@ -2594,7 +2641,7 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { len += Prepare_Addr(addr); len += Prepare_Data(data & 0xFFFF, data >> 16); - SendForward(len); + SendForward(len, false); if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured StopTicks(); @@ -2636,7 +2683,7 @@ void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) { uint8_t len = Prepare_Cmd(FWD_CMD_PROTECT); len += Prepare_Data(data & 0xFFFF, data >> 16); - SendForward(len); + SendForward(len, false); if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured StopTicks(); diff --git a/armsrc/lfops.h b/armsrc/lfops.h index bf251ac85..0ec050158 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -57,6 +57,7 @@ void T55xxDangerousRawTest(uint8_t *data); void TurnReadLFOn(uint32_t delay); void EM4xLogin(uint32_t pwd); +void EM4xBruteforce(uint32_t start_pwd, uint32_t n); void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd); void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd); void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd); diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 1625aa2ec..459f49a47 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -647,6 +647,7 @@ static command_t CommandTable[] = { {"4x05_write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"}, {"4x05_unlock", CmdEM4x05Unlock, IfPm3Lf, "execute tear off against EM4x05/EM4x69"}, {"4x05_sniff", CmdEM4x05Sniff, IfPm3Lf, "Attempt to recover em4x05 commands from sample buffer"}, + {"4x05_brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"}, {"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 4x50") " -----------------------"}, {"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, {"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index deb47208f..3ad9be5a1 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -1178,6 +1178,48 @@ int CmdEM4x05Chk(const char *Cmd) { return PM3_SUCCESS; } +int CmdEM4x05Brute(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x05_brute", + "This command tries to bruteforce the password of a EM4205/4305/4469/4569\n", + "Note: if you get many false positives, change position on the antenna" + "lf em 4x05_brute\n" + "lf em 4x05_brute -n 1 -> stop after first candidate found\n" + "lf em 4x05_brute -s 0x00000022B8 -> remember to use 0x for hex" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_0("s", "start", "", "Start bruteforce enumeration from this password value"), + arg_int0("n", "", "", "Stop after having found n candidates. Default: 0 => infinite"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint32_t start_pwd = arg_get_u64_def(ctx, 1, 0); + uint32_t n = arg_get_int_def(ctx, 1, 0); + CLIParserFree(ctx); + + PrintAndLogEx(NORMAL, ""); + + struct { + uint32_t start_pwd; + uint32_t n; + } PACKED payload; + + payload.start_pwd = start_pwd; + payload.n = n; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X_BF, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X_BF, &resp, 1000)) { + PrintAndLogEx(WARNING, "(EM4x05 Bruteforce) timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + PrintAndLogEx(INFO, "Bruteforce is running on device side, press button to interrupt"); + return PM3_SUCCESS; +} + typedef struct { uint16_t cnt; uint32_t value; diff --git a/client/src/cmdlfem4x05.h b/client/src/cmdlfem4x05.h index 276afebc2..f6e05c518 100644 --- a/client/src/cmdlfem4x05.h +++ b/client/src/cmdlfem4x05.h @@ -28,5 +28,6 @@ int CmdEM4x05Info(const char *Cmd); int CmdEM4x05Chk(const char *Cmd); int CmdEM4x05Unlock(const char *Cmd); int CmdEM4x05Sniff(const char *Cmd); +int CmdEM4x05Brute(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index be2227b7c..c393ae218 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -500,6 +500,7 @@ typedef struct { #define CMD_LF_EM4X_READWORD 0x0218 #define CMD_LF_EM4X_WRITEWORD 0x0219 #define CMD_LF_EM4X_PROTECTWORD 0x021B +#define CMD_LF_EM4X_BF 0x022A #define CMD_LF_IO_WATCH 0x021A #define CMD_LF_EM410X_WATCH 0x021C #define CMD_LF_EM4X50_INFO 0x0240