diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 2059066dc..20baa6449 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -35,40 +35,24 @@ #include "cmdlf.h" // lf_read #include "util_posix.h" #include "lfdemod.h" +#include "wiegand_formats.h" #ifndef BITS # define BITS 96 #endif static int CmdHelp(const char *Cmd); -/* -static int usage_lf_hid_read(void) { + +static int usage_lf_hid_watch(void) { PrintAndLogEx(NORMAL, "Enables HID compatible reader mode printing details."); PrintAndLogEx(NORMAL, "By default, values are printed and logged until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, "If the [1] option is provided, reader mode is exited after reading a single HID card."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hid read [h] [1]"); + PrintAndLogEx(NORMAL, "Usage: lf hid watch [h]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " 1 : (optional) stop after reading a single card"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf hid read"); - PrintAndLogEx(NORMAL, " lf hid read 1"); - return PM3_SUCCESS; -} -*/ -static int usage_lf_hid_wiegand(void) { - PrintAndLogEx(NORMAL, "This command converts facility code/card number to Wiegand code"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hid wiegand [h] [OEM] [FC] [CN]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " OEM - OEM number / site code"); - PrintAndLogEx(NORMAL, " FC - facility code"); - PrintAndLogEx(NORMAL, " CN - card number"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf hid wiegand 0 101 2001"); + PrintAndLogEx(NORMAL, " lf hid watch"); return PM3_SUCCESS; } static int usage_lf_hid_sim(void) { @@ -101,19 +85,21 @@ static int usage_lf_hid_brute(void) { PrintAndLogEx(NORMAL, "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step"); PrintAndLogEx(NORMAL, "if cardnumber is not given, it starts with 1 and goes up to 65535"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] a f c d "); + PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w [ (decimal)>] {...}"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " a : 26|33|34|35|37|40|44|84"); - PrintAndLogEx(NORMAL, " f : 8-bit value HID facility code"); - PrintAndLogEx(NORMAL, " c : (optional) cardnumber to start with, max 65535"); + PrintAndLogEx(NORMAL, " w : see `wiegand list` for available formats"); + PrintAndLogEx(NORMAL, " f : facility code"); + PrintAndLogEx(NORMAL, " c : card number to start with"); + PrintAndLogEx(NORMAL, " i : issue level"); + PrintAndLogEx(NORMAL, " o : OEM code"); PrintAndLogEx(NORMAL, " d : delay betweens attempts in ms. Default 1000ms"); PrintAndLogEx(NORMAL, " v : verbose logging, show all tries"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf hid brute a 26 f 224"); - PrintAndLogEx(NORMAL, " lf hid brute a 26 f 21 d 2000"); - PrintAndLogEx(NORMAL, " lf hid brute v a 26 f 21 c 200 d 2000"); + PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 224"); + PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 21 d 2000"); + PrintAndLogEx(NORMAL, " lf hid brute v w H10301 f 21 c 200 d 2000"); return PM3_SUCCESS; } @@ -128,17 +114,33 @@ static int sendPing(void) { return PM3_ETIMEOUT; return PM3_SUCCESS; } -static int sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, uint8_t *bits, bool verbose) { +static int sendTry(uint8_t format_idx, wiegand_card_t *card, uint32_t delay, bool verbose) { + + wiegand_message_t packed; + memset(&packed, 0, sizeof(wiegand_message_t)); + + if (HIDPack(format_idx, card, &packed) == false) { + PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); + return PM3_ESOFT; + } - // this should be optional. if (verbose) - PrintAndLogEx(INFO, "Trying FC: %u; CN: %u", fc, cn); + PrintAndLogEx(INFO, "Trying FC: %u; CN: %u; Issue level: %u; OEM: %u", card->FacilityCode, card->CardNumber, card->IssueLevel, card->OEM); - calcWiegand(fmtlen, fc, cn, bits, 0); + lf_hidsim_t payload; + payload.hi2 = packed.Top; + payload.hi = packed.Mid; + payload.lo = packed.Bot; clearCommandBuffer(); - SendCommandMIX(CMD_LF_HID_SIMULATE, bytebits_to_byte(bits, 32), bytebits_to_byte(bits + 32, 32), 0, NULL, 0); + SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload)); +/* + PacketResponseNG resp; + WaitForResponse(CMD_LF_HID_SIMULATE, &resp); + if (resp.status == PM3_EOPABORTED) + return resp.status; +*/ msleep(delay); return sendPing(); } @@ -258,18 +260,18 @@ static int CmdHIDRead(const char *Cmd) { lf_read(true, 12000); return CmdHIDDemod(Cmd); } -/* + // this read loops on device side. // uses the demod in lfops.c -static int CmdHIDRead_device(const char *Cmd) { +static int CmdHIDWatch(const char *Cmd) { - if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_lf_hid_read(); - uint8_t findone = (Cmd[0] == '1') ? 1 : 0; + uint8_t ctmp = tolower(param_getchar(Cmd, 0)); + if ( strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_hid_watch(); clearCommandBuffer(); - SendCommandMIX(CMD_LF_HID_DEMOD, findone, 0, 0, NULL, 0); + SendCommandMIX(CMD_LF_HID_DEMOD, 0, 0, 0, NULL, 0); return PM3_SUCCESS; } -*/ + static int CmdHIDSim(const char *Cmd) { lf_hidsim_t payload; payload.longFMT = 0; @@ -319,8 +321,8 @@ static int CmdHIDClone(const char *Cmd) { uint32_t hi2 = 0, hi = 0, lo = 0; uint32_t n = 0, i = 0; - uint8_t ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h') return usage_lf_hid_clone(); + uint8_t ctmp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_hid_clone(); uint8_t longid[1] = {0}; if (strchr(Cmd, 'l') != 0) { i++; @@ -348,202 +350,9 @@ static int CmdHIDClone(const char *Cmd) { } /* -// struct to handle wiegand -typedef struct { - uint8_t FormatLen; - uint8_t SiteCode; - uint8_t FacilityCode; - uint8_t CardNumber; - uint8_t *Wiegand; - size_t Wiegand_n; -} wiegand_t; -*/ - -static void addHIDMarker(uint8_t fmtlen, uint8_t *out) { - // temp array - uint8_t arr[BITS]; - memset(arr, 0, BITS); - - // copy inpu - uint8_t pos = sizeof(arr) - fmtlen; - memcpy(arr + pos, out, fmtlen); - - switch (fmtlen) { - case 26: { - // start sentinel, BITS-bit 27 = 1 - arr[BITS - 27] = 1; - // fmt smaller than 37 used, bit37 = 1 - arr[BITS - 38] = 1; - memcpy(out, arr, BITS); - break; - } - case 34: - // start sentinel, BITS-bit 27 = 1 - arr[BITS - 35] = 1; - - // fmt smaller than 37 used, bit37 = 1 - arr[BITS - 38] = 1; - memcpy(out, arr, BITS); - break; - default: - break; - } -} - -// static void getParity34(uint32_t *hi, uint32_t *lo){ -// uint32_t result = 0; -// int i; - -// // even parity -// for (i = 7;i >= 0;i--) -// result ^= (*hi >> i) & i; -// for (i = 31;i >= 24;i--) -// result ^= (*lo >> i) & 1; - -// *hi |= result << 2; - -// // odd parity bit -// result = 0; -// for (i = 23;i >= 1;i--) -// result ^= (*lo >> i) & 1; - -// *lo |= !result; -// } -// static void getParity37H(uint32_t *hi, uint32_t *lo){ -// uint32_t result = 0; -// int i; - -// // even parity -// for (i = 4;i >= 0;i--) -// result ^= (*hi >> i) & 1; -// for (i = 31;i >= 20;i--) -// result ^= (*lo >> i) & 1; -// *hi |= result << 4; - -// // odd parity -// result = 0; -// for (i = 19;i >= 1;i--) -// result ^= (*lo >> i) & 1; -// *lo |= result; -// } - -//static void calc26(uint16_t fc, uint32_t cardno, uint8_t *out){ -static void calc26(uint16_t fc, uint32_t cardno, uint8_t *out) { - uint8_t wiegand[24]; - num_to_bytebits(fc, 8, wiegand); - num_to_bytebits(cardno, 16, wiegand + 8); - wiegand_add_parity(out, wiegand, sizeof(wiegand)); -} -// static void calc33(uint16_t fc, uint32_t cardno, uint8_t *out){ -// } -static void calc34(uint16_t fc, uint32_t cardno, uint8_t *out) { - uint8_t wiegand[32]; - num_to_bytebits(fc, 16, wiegand); - num_to_bytebits(cardno, 16, wiegand + 16); - wiegand_add_parity(out, wiegand, sizeof(wiegand)); -} -// static void calc35(uint16_t fc, uint32_t cardno, uint8_t *out){ -// *lo = ((cardno & 0xFFFFF) << 1) | fc << 21; -// *hi = (1 << 5) | ((fc >> 11) & 1); -// } -static void calc36(uint8_t oem, uint16_t fc, uint32_t cardno, uint8_t *out) { - // FC 1 - 16 - 16 bit - // cardno 17 - 33 - 16 bit - // oem 34 - 35 - 2 bit - // Odd Parity 0th bit 1-18 - // Even Parity 36th bit 19-35 - uint8_t wiegand[34]; - num_to_bytebits(fc, 16, wiegand); - num_to_bytebits(cardno & 0xFFFF, 16, wiegand + 16); - num_to_bytebits(oem, 2, wiegand + 32); - wiegand_add_parity_swapped(out, wiegand, sizeof(wiegand)); -} -static void calc37S(uint16_t fc, uint32_t cardno, uint8_t *out) { - // FC 2 - 17 - 16 bit - // cardno 18 - 36 - 19 bit - // Even P1 1 - 19 - // Odd P37 19 - 36 - uint8_t wiegand[35]; - num_to_bytebits(fc, 16, wiegand); - num_to_bytebits(cardno, 19, wiegand + 16); - wiegand_add_parity(out, wiegand, sizeof(wiegand)); -} -static void calc37H(uint64_t cardno, uint8_t *out) { - // SC NONE - // cardno 1-35 34 bits - // Even Parity 0th bit 1-18 - // Odd Parity 36th bit 19-35 - uint8_t wiegand[37]; - num_to_bytebits((uint32_t)(cardno >> 32), 2, wiegand); - num_to_bytebits((uint32_t)(cardno >> 0), 32, wiegand + 2); - wiegand_add_parity(out, wiegand, sizeof(wiegand)); - - PrintAndLogEx(NORMAL, "%x %x\n", (uint32_t)(cardno >> 32), (uint32_t)cardno); -} -// static void calc40(uint64_t cardno, uint8_t *out){ -// cardno = (cardno & 0xFFFFFFFFFF); -// *lo = ((cardno & 0xFFFFFFFF) << 1 ); -// *hi = (cardno >> 31); -// } - -void calcWiegand(uint8_t fmtlen, uint16_t fc, uint64_t cardno, uint8_t *bits, uint8_t oem) { - uint32_t cn32 = (cardno & 0xFFFFFFFF); - switch (fmtlen) { - case 26: - calc26(fc, cn32, bits); - break; - // case 33 : calc33(fc, cn32, bits); break; - case 34: - calc34(fc, cn32, bits); - break; - // case 35 : calc35(fc, cn32, bits); break; - case 36: - calc36(oem, fc, cn32, bits); - break; - case 37: - calc37S(fc, cn32, bits); - break; - case 38: - calc37H(cardno, bits); - break; - // case 40 : calc40(cardno, bits); break; - // case 44 : { break; } - // case 84 : { break; } - default: - break; - } -} - -static int CmdHIDWiegand(const char *Cmd) { - uint32_t oem = 0, fc = 0; - uint64_t cardnum = 0; - uint8_t bits[BITS] = {0}; - uint8_t *bs = bits; - - uint8_t ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 3 || ctmp == 'h') return usage_lf_hid_wiegand(); - - oem = param_get8(Cmd, 0); - fc = param_get32ex(Cmd, 1, 0, 10); - cardnum = param_get64ex(Cmd, 2, 0, 10); - - uint8_t fmtlen[] = {26, 33, 34, 35, 36, 37, 38, 40}; - PrintAndLogEx(NORMAL, "HID | OEM | FC | CN | Wiegand | HID Formatted"); PrintAndLogEx(NORMAL, "----+-----+------+---------+-----------+--------------------"); - for (uint8_t i = 0; i < ARRAYLEN(fmtlen); i++) { - memset(bits, 0x00, sizeof(bits)); - calcWiegand(fmtlen[i], fc, cardnum, bs, oem); - PrintAndLogEx(NORMAL, "ice:: %s \n", sprint_bin(bs, fmtlen[i])); - uint64_t wiegand = (uint64_t)bytebits_to_byte(bs, 32) << 32 | bytebits_to_byte(bs + 32, 32); - - addHIDMarker(fmtlen[i], bs); - PrintAndLogEx(NORMAL, "ice:: %s\n", sprint_bin(bs, BITS)); - uint64_t blocks = (uint64_t)bytebits_to_byte(bs + 32, 32) << 32 | bytebits_to_byte(bs + 64, 32); - uint8_t shifts = 64 - fmtlen[i]; - wiegand >>= shifts; - - PrintAndLogEx(NORMAL, " %u | %03u | %03u | %" PRIu64 " | %" PRIX64 " | %" PRIX64, + PrintAndLogEx(NORMAL, " %u | %03u | %03u | %" PRIu64 " | %" PRIX64 " | %" PRIX64, fmtlen[i], oem, fc, @@ -553,26 +362,33 @@ static int CmdHIDWiegand(const char *Cmd) { ); } PrintAndLogEx(NORMAL, "----+-----+-----+-------+-----------+--------------------"); - return PM3_SUCCESS; -} +*/ static int CmdHIDBrute(const char *Cmd) { bool errors = false, verbose = false; - uint32_t fc = 0, cn = 0, delay = 1000; - uint8_t fmtlen = 0; - uint8_t bits[96]; - memset(bits, 0, sizeof(bits)); + uint32_t delay = 1000; uint8_t cmdp = 0; + int format_idx = -1; + char format[16] = {0}; + wiegand_card_t data; + memset(&data, 0, sizeof(wiegand_card_t)); while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_lf_hid_brute(); - case 'f': - fc = param_get32ex(Cmd, cmdp + 1, 0, 10); - if (!fc) + case 'w': + param_getstr(Cmd, cmdp + 1, format, sizeof(format)); + format_idx = HIDFindCardFormat(format); + if (format_idx == -1) { + PrintAndLogEx(WARNING, "Unknown format: %s", format); errors = true; + } + cmdp += 2; + break; + case 'c': + data.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; case 'd': @@ -580,24 +396,17 @@ static int CmdHIDBrute(const char *Cmd) { delay = param_get32ex(Cmd, cmdp + 1, 1000, 10); cmdp += 2; break; - case 'c': - cn = param_get32ex(Cmd, cmdp + 1, 0, 10); - // truncate cardnumber. - cn &= 0xFFFF; + case 'f': + data.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; - case 'a': - fmtlen = param_get8(Cmd, cmdp + 1); + case 'i': + data.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 'o': + data.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; - bool is_ftm_ok = false; - uint8_t ftms[] = {26, 33, 34, 35, 37}; - for (uint8_t i = 0; i < ARRAYLEN(ftms); i++) { - if (ftms[i] == fmtlen) { - is_ftm_ok = true; - } - } - // negated - errors = !is_ftm_ok; break; case 'v': verbose = true; @@ -609,15 +418,11 @@ static int CmdHIDBrute(const char *Cmd) { break; } } - if (fc == 0) errors = true; if (errors) return usage_lf_hid_brute(); PrintAndLogEx(INFO, "Brute-forcing HID reader"); PrintAndLogEx(INFO, "Press pm3-button to abort simulation or run another command"); - uint16_t up = cn; - uint16_t down = cn; - // main loop for (;;) { @@ -632,13 +437,16 @@ static int CmdHIDBrute(const char *Cmd) { } // Do one up - if (up < 0xFFFF) - if (sendTry(fmtlen, fc, up++, delay, bits, verbose) != PM3_SUCCESS) return PM3_ESOFT; + if (data.CardNumber < 0xFFFF) { + data.CardNumber++; + if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT; + } // Do one down (if cardnumber is given) - if (cn > 1) - if (down > 1) - if (sendTry(fmtlen, fc, --down, delay, bits, verbose) != PM3_SUCCESS) return PM3_ESOFT; + if (data.CardNumber > 1) { + data.CardNumber--; + if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT; + } } return PM3_SUCCESS; } @@ -649,8 +457,8 @@ static command_t CommandTable[] = { {"read", CmdHIDRead, IfPm3Lf, "attempt to read and extract tag data"}, {"clone", CmdHIDClone, IfPm3Lf, "clone HID to T55x7"}, {"sim", CmdHIDSim, IfPm3Lf, "simulate HID tag"}, - {"wiegand", CmdHIDWiegand, AlwaysAvailable, "convert facility code/card number to Wiegand code"}, {"brute", CmdHIDBrute, IfPm3Lf, "bruteforce card number against reader"}, + {"watch", CmdHIDWatch, IfPm3Lf, "continuously watch for cards. Reader mode"}, {NULL, NULL, NULL, NULL} };