diff --git a/CHANGELOG.md b/CHANGELOG.md index 1532b044b..f7cd6d8d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added bruteforce function for the magic byte in `cmdlfnexwatch.c` and ability to clone with psk2 modulation (@Guilhem7, @MaximeBosca) - Changed `hw setmux` - improve user feedback for special case (@iceman1001) - Changed 'filename' - unified file name param across client (@iceman1001) - Fix `lf em 4x05 brute/chk` - fixed input params crash (@iceman1001) diff --git a/client/src/cmdlfnexwatch.c b/client/src/cmdlfnexwatch.c index d46c40046..39a3ff7cc 100644 --- a/client/src/cmdlfnexwatch.c +++ b/client/src/cmdlfnexwatch.c @@ -24,6 +24,8 @@ #include "cmdlft55xx.h" // clone.. #include "cmdlfem4x05.h" // #include "cliparser.h" +#include "util.h" + typedef enum { SCRAMBLE, @@ -52,7 +54,7 @@ static uint8_t nexwatch_parity(uint8_t hexid[5]) { } /// NETWATCH checksum -/// @param magic = 0xBE Quadrakey, 0x88 Nexkey +/// @param magic = 0xBE Quadrakey, 0x88 Nexkey, 0x86 Honeywell /// @param id = descrambled id (printed card number) /// @param parity = the parity based upon the scrambled raw id. static uint8_t nexwatch_checksum(uint8_t magic, uint32_t id, uint8_t parity) { @@ -108,6 +110,20 @@ static int nexwatch_scamble(NexWatchScramble_t action, uint32_t *id, uint32_t *s return PM3_SUCCESS; } +static int nexwatch_magic_bruteforce(uint32_t cn, uint8_t calc_parity, uint8_t chk) { + for (uint8_t magic = 0; magic < 255; magic++) { + uint8_t temp_checksum; + temp_checksum = nexwatch_checksum(magic, cn, calc_parity); + if (temp_checksum == chk) { + PrintAndLogEx(SUCCESS, " Magic number : " _GREEN_("0x%X"), magic); + return PM3_SUCCESS; + } + } + PrintAndLogEx(DEBUG, "DEBUG: Error - Magic number not found"); + return PM3_ESOFT; +} + + int demodNexWatch(bool verbose) { (void) verbose; // unused so far if (PSKDemod(0, 0, 100, false) != PM3_SUCCESS) { @@ -204,10 +220,13 @@ int demodNexWatch(bool verbose) { if (m_idx < ARRAYLEN(items)) { PrintAndLogEx(SUCCESS, " fingerprint : " _GREEN_("%s"), items[m_idx].desc); + } else { + nexwatch_magic_bruteforce(cn, calc_parity, chk); } PrintAndLogEx(SUCCESS, " 88bit id : " _YELLOW_("%"PRIu32) " (" _YELLOW_("0x%08"PRIx32)")", cn, cn); PrintAndLogEx(SUCCESS, " mode : %x", mode); + if (parity == calc_parity) { PrintAndLogEx(DEBUG, " parity : %s (0x%X)", _GREEN_("ok"), parity); } else { @@ -285,6 +304,8 @@ static int CmdNexWatchClone(const char *Cmd) { arg_lit0(NULL, "hc", "Honeywell credential"), arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_str0(NULL, "magic", "", "optional - magic hex data. 1 byte"), + arg_lit0(NULL, "psk2", "optional - specify writing a tag in psk2 modulation"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -301,6 +322,10 @@ static int CmdNexWatchClone(const char *Cmd) { bool use_unk = arg_get_lit(ctx, 6); bool q5 = arg_get_lit(ctx, 7); bool em = arg_get_lit(ctx, 8); + bool use_psk2 = arg_get_lit(ctx, 10); + uint8_t magic_arg; + int magic_len = 0; + CLIGetHexWithReturn(ctx, 9, &magic_arg, &magic_len); CLIParserFree(ctx); if (use_nexkey && use_quadrakey) { @@ -316,6 +341,13 @@ static int CmdNexWatchClone(const char *Cmd) { // 56000000 00213C9F 8F150C00 bool use_raw = (raw_len != 0); + bool use_custom_magic = (magic_len != 0); + + if (magic_len > 1) { + PrintAndLogEx(FAILED, "Can't specify a magic number bigger than one byte"); + return PM3_EINVARG; + } + if (use_raw && cn != -1) { PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time"); return PM3_EINVARG; @@ -336,20 +368,27 @@ static int CmdNexWatchClone(const char *Cmd) { } uint8_t magic = 0xBE; - if (use_nexkey) - magic = 0x88; + if (use_custom_magic) { + magic = magic_arg; + } else { + if (use_nexkey) + magic = 0x88; - if (use_quadrakey) - magic = 0xBE; + if (use_quadrakey) + magic = 0xBE; - if (use_unk) - magic = 0x86; + if (use_unk) + magic = 0x86; + + } + PrintAndLogEx(INFO, "Magic byte selected : 0x%X", magic); uint32_t blocks[4]; //Nexwatch - compat mode, PSK, data rate 40, 3 data blocks blocks[0] = T55x7_MODULATION_PSK1 | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT; char cardtype[16] = {"T55x7"}; + // Q5 if (q5) { blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; @@ -368,6 +407,19 @@ static int CmdNexWatchClone(const char *Cmd) { raw[10] |= nexwatch_checksum(magic, cn, parity); } + if (use_psk2) { + blocks[0] = 270464; + uint8_t * res_shifted = calloc(96, sizeof(uint8_t)); + uint8_t * res = calloc(96, sizeof(uint8_t)); + bytes_to_bytebits(raw, 12, res); + psk1TOpsk2(res, 96); + memcpy(res_shifted, &res[1], 95 * sizeof(uint8_t)); + free(res); + bits_to_array(res_shifted, 96, raw); + free(res_shifted); + } + + for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); } @@ -408,6 +460,8 @@ static int CmdNexWatchSim(const char *Cmd) { arg_lit0(NULL, "nc", "Nexkey credential"), arg_lit0(NULL, "qc", "Quadrakey credential"), arg_lit0(NULL, "hc", "Honeywell credential"), + arg_str0(NULL, "magic", "", "optional - magic hex data. 1 byte"), + arg_lit0(NULL, "psk2", "optional - specify writing a tag in psk2 modulation"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false);