diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 86d44cd9a..bc0c255fa 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -27,6 +27,7 @@ #include "BigBuf.h" #include "spiffs.h" #include "appmain.h" // tear +#include "bruteforce.h" // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) // TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 3bed45d1d..a4083d3d0 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -349,26 +349,50 @@ int CmdEM4x50Brute(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 brute", "Tries to bruteforce the password of a EM4x50 card.\n" - "Function can be stopped by pressing pm3 button.", - "lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000\n" + "Function can be stopped by pressing pm3 button.\n", + + "lf em 4x50 brute --mode range --begin 12330000 --end 12340000 -> tries pwds from 0x12330000 to 0x12340000\n" + "lf em 4x50 brute --mode charset --digits --uppercase -> tries all combinations of ASCII codes for digits and uppercase letters\n" ); void *argtable[] = { arg_param_begin, - arg_str1(NULL, "first", "", "first password (start), 4 bytes, lsb"), - arg_str1(NULL, "last", "", "last password (stop), 4 bytes, lsb"), + arg_str1(NULL, "mode", "", "Bruteforce mode (range|charset)"), + arg_str0(NULL, "begin", "", "Range mode - start of the key range"), + arg_str0(NULL, "end", "", "Range mode - end of the key range"), + arg_lit0(NULL, "digits", "Charset mode - include ASCII codes for digits"), + arg_lit0(NULL, "uppercase", "Charset mode - include ASCII codes for uppercase letters"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - int first_len = 0; - uint8_t first[4] = {0, 0, 0, 0}; - CLIGetHexWithReturn(ctx, 1, first, &first_len); - int last_len = 0; - uint8_t last[4] = {0, 0, 0, 0}; - CLIGetHexWithReturn(ctx, 2, last, &last_len); - CLIParserFree(ctx); + em4x50_data_t etd; + + int mode_len = 64; + char mode[64]; + CLIGetStrWithReturn(ctx, 1, (uint8_t*) mode, &mode_len); + PrintAndLogEx(INFO, "Chosen mode: %s", mode); + + if(strcmp(mode, "range") == 0){ + etd.bruteforce_mode = BRUTEFORCE_MODE_RANGE; + } else if(strcmp(mode, "charset") == 0){ + etd.bruteforce_mode = BRUTEFORCE_MODE_CHARSET; + } else { + PrintAndLogEx(FAILED, "unknown bruteforce mode: %s", mode); + return PM3_EINVARG; + } + + PrintAndLogEx(INFO, "Chosen mode2: %d", etd.bruteforce_mode); + + // int first_len = 0; + // uint8_t first[4] = {0, 0, 0, 0}; + // CLIGetHexWithReturn(ctx, 1, first, &first_len); + // int last_len = 0; + // uint8_t last[4] = {0, 0, 0, 0}; + // CLIGetHexWithReturn(ctx, 2, last, &last_len); + CLIParserFree(ctx); +/* if (first_len != 4) { PrintAndLogEx(FAILED, "password length must be 4 bytes"); return PM3_EINVARG; @@ -410,7 +434,7 @@ int CmdEM4x50Brute(const char *Cmd) { PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", resp.data.asDwords[0]); else PrintAndLogEx(WARNING, "brute pwd failed"); - +*/ return PM3_SUCCESS; } diff --git a/common/bruteforce.c b/common/bruteforce.c new file mode 100644 index 000000000..1d5535277 --- /dev/null +++ b/common/bruteforce.c @@ -0,0 +1,149 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- + +#include "bruteforce.h" +#include +#include + +uint8_t charset_digits[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', +}; + +uint8_t charset_uppercase[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'W', + 'X', 'Y', 'Z' +}; + +void generator_init(generator_context_t* ctx, uint8_t mode){ + memset(ctx, 0, sizeof(generator_context_t)); + ctx->mode = mode; +} + +int generator_set_charset(generator_context_t* ctx, uint8_t charsets){ + if (ctx->mode != BRUTEFORCE_MODE_CHARSET){ + return -1; + } + + if(charsets & CHARSET_DIGITS){ + memcpy(ctx->charset, charset_digits, sizeof(charset_digits)); + ctx->charset_length += sizeof(charset_digits); + } + + if(charsets & CHARSET_UPPERCASE){ + memcpy(ctx->charset+ctx->charset_length, charset_uppercase, sizeof(charset_uppercase)); + ctx->charset_length += sizeof(charset_uppercase); + } +} + +int generate32(generator_context_t *ctx){ + + switch(ctx->mode){ + case BRUTEFORCE_MODE_RANGE: + return _generate_mode_range32(ctx); + case BRUTEFORCE_MODE_CHARSET: + return _generate_mode_charset32(ctx); + } +} + +int _generate_mode_range32(generator_context_t *ctx){ + + if(ctx->current_key32 >= ctx->range_high){ + return GENERATOR_END; + } + + // we use flag1 as indicator if value of range_low was already emitted + // so the range generated is + if(ctx->current_key32 <= ctx->range_low && ctx->flag1==false){ + ctx->current_key32 = ctx->range_low; + ctx->pos[0] = true; + return GENERATOR_NEXT; + } + + ctx->current_key32++; + return GENERATOR_NEXT; +} + +int _generate_mode_charset32(generator_context_t *ctx){ + + if(ctx->flag1) + return GENERATOR_END; + + char str[5]; + for (int i = 0; i < 5;i++) + str[i] = ctx->charset[ctx->pos[i]]; + str[4] = 0; + printf("%s\n", str); + + ctx->current_key32 = ctx->charset[ctx->pos[0]] << 24 | ctx->charset[ctx->pos[1]] << 16 | + ctx->charset[ctx->pos[2]] << 8 | ctx->charset[ctx->pos[3]]; + + + if(array_increment(ctx->pos, 4, ctx->charset_length) == -1) + // set flag1 to emit value last time and end generation + ctx->flag1 = true; + + return GENERATOR_NEXT; +} + +// increments values in array with carryover using modulo limit for each byte +// this is used to iterate each byte in key over charset table +// returns -1 if incrementing reaches its end +int array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo){ + + uint8_t prev_value; + + // check if we reached max value already + uint8_t i; + for (i = 0; i < data_len; i++) + if(data[i] < modulo - 1) + break; + + if(i == data_len) + return -1; + + for (uint8_t pos = data_len - 1;; pos--){ + prev_value = ++data[pos]; + data[pos] = data[pos] % modulo; + if (prev_value == data[pos]) + return 0; + else if (pos == 0){ + // we cannot carryover to next byte + // with the max value check in place before, we should not reach this place + return -1; + } + } + + return 0; +} + +/* +int main(){ + generator_context_t ctx; + generator_init(&ctx, BRUTEFORCE_MODE_CHARSET); + generator_set_charset(&ctx, CHARSET_DIGITS | CHARSET_UPPERCASE); + + int ret = 0; + while( (ret=generate32(&ctx)) == GENERATOR_NEXT){ + printf("%X\n", ctx.current_key32); + } + + // printf("Charset len: %d\n", ctx.charset_length); + // printf("Digits len: %d\n", sizeof(charset_digits)); + // printf("Uppercase len: %d\n", sizeof(charset_uppercase)); + return 1; +} +*/ \ No newline at end of file diff --git a/common/bruteforce.h b/common/bruteforce.h new file mode 100644 index 000000000..2b856dfa7 --- /dev/null +++ b/common/bruteforce.h @@ -0,0 +1,78 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// functions for bruteforcing card keys +//----------------------------------------------------------------------------- + +#ifndef __BRUTEFORCE_H +#define __BRUTEFORCE_H + +#include "common.h" + +typedef uint8_t bruteforce_mode_t; +// bruteforcing all keys sequentially between X and Y +#define BRUTEFORCE_MODE_RANGE 1 + +// try keys based on limited charset/passphrases +// some payment systems use user-provided passphrase as system key +#define BRUTEFORCE_MODE_CHARSET 2 + +// "smart" mode - try some predictable patterns +#define BRUTEFORCE_MODE_SMART 3 + + +typedef uint8_t bruteforce_charset_t; +#define CHARSET_DIGITS 1 +#define CHARSET_UPPERCASE 2 + +#define GENERATOR_END 0 +#define GENERATOR_NEXT 1 +#define GENERATOR_ERROR 2 + +#define CHARSET_DIGITS_SIZE 10 +#define CHARSET_UPPERCASE_SIZE 25 + +extern uint8_t charset_digits[]; +extern uint8_t charset_uppercase[]; + +// structure to hold key generator temporary data +typedef struct { + // position of each of 4 bytes in 32 bit key in charset mode + // add more bytes to support larger keys + // pos[0] is most significant byte - all maths avoid relying on little/big endian memory layout + uint8_t pos[4]; + uint32_t current_key32; + uint8_t mode; + uint8_t charset[ + CHARSET_DIGITS_SIZE + + CHARSET_UPPERCASE_SIZE + ]; + uint8_t charset_length; + + uint32_t range_low; + uint32_t range_high; + // flags to use internally by generators as they wish + bool flag1, flag2, flag3; + +} generator_context_t; + +void generator_init(generator_context_t *ctx, uint8_t mode); +int generator_set_charset(generator_context_t *ctx, uint8_t charsets); +int generate32(generator_context_t *ctx); +int _generate_mode_range32(generator_context_t *ctx); +int _generate_mode_charset32(generator_context_t *ctx); +int _generate_mode_smart32(generator_context_t *ctx); +int array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo); +#endif \ No newline at end of file diff --git a/include/em4x50.h b/include/em4x50.h index bed01901c..9bf1ffc24 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -20,6 +20,7 @@ #define EM4X50_H__ #include "common.h" +#include "bruteforce.h" #define EM4X50_NO_WORDS 34 @@ -62,6 +63,8 @@ typedef struct { uint32_t password2; uint32_t word; uint32_t addresses; + bruteforce_mode_t bruteforce_mode; + bruteforce_charset_t bruteforce_charset; } PACKED em4x50_data_t; typedef struct {