From 85f1785ccb564154a587ccd5dd36a6182473606a Mon Sep 17 00:00:00 2001 From: phaseloop Date: Thu, 15 Dec 2022 20:51:54 +0000 Subject: [PATCH 1/8] initial bruteforce module --- armsrc/em4x50.c | 1 + client/src/cmdlfem4x50.c | 48 +++++++++---- common/bruteforce.c | 149 +++++++++++++++++++++++++++++++++++++++ common/bruteforce.h | 78 ++++++++++++++++++++ include/em4x50.h | 3 + 5 files changed, 267 insertions(+), 12 deletions(-) create mode 100644 common/bruteforce.c create mode 100644 common/bruteforce.h 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 { From f09a8cfa281e49ab4e2e19c8ecc5d6ba095fb130 Mon Sep 17 00:00:00 2001 From: phaseloop Date: Fri, 5 May 2023 12:57:47 +0000 Subject: [PATCH 2/8] add bruteforce parameters to command line --- armsrc/em4x50.c | 2 +- client/src/cmdlfem4x50.c | 97 +++++++++++++++++++++++++++------------- common/bruteforce.h | 1 + 3 files changed, 69 insertions(+), 31 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index bc0c255fa..ed1fdad0e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -703,7 +703,7 @@ void em4x50_login(uint32_t *password, bool ledcontrol) { reply_ng(CMD_LF_EM4X50_LOGIN, status, NULL, 0); } -// envoke password search +// invoke password search void em4x50_brute(em4x50_data_t *etd, bool ledcontrol) { em4x50_setup_read(); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a4083d3d0..a67508848 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -19,6 +19,7 @@ #include "cliparser.h" #include "cmdlfem4x50.h" #include +#include #include "cmdparser.h" // command_t #include "util_posix.h" // msclock #include "fileutils.h" @@ -368,6 +369,7 @@ int CmdEM4x50Brute(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); em4x50_data_t etd; + bzero(&etd, sizeof(etd)); int mode_len = 64; char mode[64]; @@ -379,48 +381,83 @@ int CmdEM4x50Brute(const char *Cmd) { } else if(strcmp(mode, "charset") == 0){ etd.bruteforce_mode = BRUTEFORCE_MODE_CHARSET; } else { - PrintAndLogEx(FAILED, "unknown bruteforce mode: %s", mode); + PrintAndLogEx(FAILED, "Unknown bruteforce mode: %s", mode); return PM3_EINVARG; } - PrintAndLogEx(INFO, "Chosen mode2: %d", etd.bruteforce_mode); + if(etd.bruteforce_mode == BRUTEFORCE_MODE_RANGE){ + int begin_len = 0; + uint8_t begin[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, begin, &begin_len); + + int end_len = 0; + uint8_t end[4] = {0x0}; + CLIGetHexWithReturn(ctx, 3, end, &end_len); + + if(begin_len!=4){ + PrintAndLogEx(FAILED, "'begin' parameter must be 4 bytes"); + return PM3_EINVARG; + } + + if(end_len!=4){ + PrintAndLogEx(FAILED, "'end' parameter must be 4 bytes"); + return PM3_EINVARG; + } + + etd.password1 = BYTES2UINT32_BE(begin); + etd.password2 = BYTES2UINT32_BE(end); + } else if(etd.bruteforce_mode == BRUTEFORCE_MODE_CHARSET){ + bool enable_digits = arg_get_lit(ctx, 4); + bool enable_uppercase = arg_get_lit(ctx, 5); + + if(enable_digits) + etd.bruteforce_charset |= CHARSET_DIGITS; + if(enable_uppercase) + etd.bruteforce_charset |= CHARSET_UPPERCASE; + + if(etd.bruteforce_charset == 0){ + PrintAndLogEx(FAILED, "Please enable at least one charset when using charset bruteforce mode."); + return PM3_EINVARG; + } + + PrintAndLogEx(INFO, "Enabled charsets: %s%s", + enable_digits ? "digits " : "", + enable_uppercase ? "uppercase " : ""); + + } - // 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; - } - if (last_len != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes"); - return PM3_EINVARG; - } - - em4x50_data_t etd; - etd.password1 = BYTES2UINT32_BE(first); - etd.password2 = BYTES2UINT32_BE(last); - + // 27 passwords/second (empirical value) const int speed = 27; + int no_iter = 0; + + if(etd.bruteforce_mode == BRUTEFORCE_MODE_RANGE){ + no_iter = etd.password2 - etd.password1 + 1; + PrintAndLogEx(INFO, "Trying " _YELLOW_("%i") " passwords in range [0x%08x, 0x%08x]" + , no_iter + , etd.password1 + , etd.password2 + ); + } else if(etd.bruteforce_mode == BRUTEFORCE_MODE_CHARSET){ + unsigned int digits = 0; + + if(etd.bruteforce_charset & CHARSET_DIGITS) + digits += CHARSET_DIGITS_SIZE; + + if(etd.bruteforce_charset & CHARSET_UPPERCASE) + digits += CHARSET_UPPERCASE_SIZE; + + no_iter = pow(digits, 4); + } // print some information - int no_iter = etd.password2 - etd.password1 + 1; int dur_s = no_iter / speed; int dur_h = dur_s / 3600; int dur_m = (dur_s - dur_h * 3600) / 60; dur_s -= dur_h * 3600 + dur_m * 60; - PrintAndLogEx(INFO, "Trying " _YELLOW_("%i") " passwords in range [0x%08x, 0x%08x]" - , no_iter - , etd.password1 - , etd.password2 - ); + PrintAndLogEx(INFO, "Estimated duration: %ih %im %is", dur_h, dur_m, dur_s); // start @@ -434,7 +471,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; } @@ -1214,7 +1251,7 @@ int CmdEM4x50Sim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, - {"brute", CmdEM4x50Brute, IfPm3EM4x50, "Simple bruteforce attack to find password"}, + {"brute", CmdEM4x50Brute, IfPm3EM4x50, "Bruteforce attack to find password"}, {"chk", CmdEM4x50Chk, IfPm3EM4x50, "Check passwords from dictionary"}, {"dump", CmdEM4x50Dump, IfPm3EM4x50, "Dump EM4x50 tag"}, {"info", CmdEM4x50Info, IfPm3EM4x50, "Tag information"}, diff --git a/common/bruteforce.h b/common/bruteforce.h index 2b856dfa7..f01cfd3ca 100644 --- a/common/bruteforce.h +++ b/common/bruteforce.h @@ -34,6 +34,7 @@ typedef uint8_t bruteforce_mode_t; typedef uint8_t bruteforce_charset_t; +// bit flags - can be used together using logical OR #define CHARSET_DIGITS 1 #define CHARSET_UPPERCASE 2 From fa033a98b22f1d94ec208cc7e923356a8d7d0059 Mon Sep 17 00:00:00 2001 From: phaseloop Date: Sat, 6 May 2023 14:45:20 +0000 Subject: [PATCH 3/8] enable em4x50 bruteforce in proxmark firmware --- armsrc/Makefile | 2 ++ armsrc/em4x50.c | 17 +++++++++++++---- common/bruteforce.c | 28 +++++++++++++--------------- common/bruteforce.h | 22 +++++++++++----------- 4 files changed, 39 insertions(+), 30 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index c0703ccf4..4a088cbf6 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -46,6 +46,7 @@ SRC_CRC = crc.c crc16.c crc32.c SRC_ICLASS = iclass.c optimized_cipherutils.c optimized_ikeys.c optimized_elite.c optimized_cipher.c SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c SRC_NFCBARCODE = thinfilm.c +SRC_BRUTEFORCE = bruteforce.c # SRC_BEE = bee.c @@ -143,6 +144,7 @@ THUMBSRC = start.c \ $(SRC_FELICA) \ $(SRC_STANDALONE) \ $(SRC_ZX) \ + $(SRC_BRUTEFORCE) \ appmain.c \ printf.c \ dbprint.c \ diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index ed1fdad0e..5043d753b 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -633,12 +633,21 @@ static int login(uint32_t password) { return PM3_EFAILED; } -// searching for password in given range -static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { +// searching for password using chosen bruteforce algorithm +static bool brute(em4x50_data_t *etd, uint32_t *pwd) { + + generator_context_t ctx; bool pwd_found = false; + int generator_ret = 0; int cnt = 0; - for (*pwd = start; *pwd <= stop; (*pwd)++) { + bf_generator_init(&ctx, etd->bruteforce_mode); + + if(etd->bruteforce_mode == BRUTEFORCE_MODE_CHARSET) + bf_generator_set_charset(&ctx, etd->bruteforce_charset); + + while ( (generator_ret=bf_generate32(&ctx)) == GENERATOR_NEXT) { + *pwd = ctx.current_key32; WDT_HIT(); @@ -715,7 +724,7 @@ void em4x50_brute(em4x50_data_t *etd, bool ledcontrol) { LED_C_OFF(); LED_D_ON(); } - bsuccess = brute(etd->password1, etd->password2, &pwd); + bsuccess = brute(etd, &pwd); } if (ledcontrol) LEDsoff(); diff --git a/common/bruteforce.c b/common/bruteforce.c index 1d5535277..62d411240 100644 --- a/common/bruteforce.c +++ b/common/bruteforce.c @@ -28,12 +28,12 @@ uint8_t charset_uppercase[] = { 'X', 'Y', 'Z' }; -void generator_init(generator_context_t* ctx, uint8_t mode){ +void bf_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){ +int bf_generator_set_charset(generator_context_t* ctx, uint8_t charsets){ if (ctx->mode != BRUTEFORCE_MODE_CHARSET){ return -1; } @@ -47,19 +47,23 @@ int generator_set_charset(generator_context_t* ctx, uint8_t charsets){ memcpy(ctx->charset+ctx->charset_length, charset_uppercase, sizeof(charset_uppercase)); ctx->charset_length += sizeof(charset_uppercase); } + + return 0; } -int generate32(generator_context_t *ctx){ +int bf_generate32(generator_context_t *ctx){ switch(ctx->mode){ case BRUTEFORCE_MODE_RANGE: - return _generate_mode_range32(ctx); + return _bf_generate_mode_range32(ctx); case BRUTEFORCE_MODE_CHARSET: - return _generate_mode_charset32(ctx); + return _bf_generate_mode_charset32(ctx); } + + return GENERATOR_ERROR; } -int _generate_mode_range32(generator_context_t *ctx){ +int _bf_generate_mode_range32(generator_context_t *ctx){ if(ctx->current_key32 >= ctx->range_high){ return GENERATOR_END; @@ -77,22 +81,16 @@ int _generate_mode_range32(generator_context_t *ctx){ return GENERATOR_NEXT; } -int _generate_mode_charset32(generator_context_t *ctx){ +int _bf_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) + if(bf_array_increment(ctx->pos, 4, ctx->charset_length) == -1) // set flag1 to emit value last time and end generation ctx->flag1 = true; @@ -102,7 +100,7 @@ int _generate_mode_charset32(generator_context_t *ctx){ // 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){ +int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo){ uint8_t prev_value; diff --git a/common/bruteforce.h b/common/bruteforce.h index f01cfd3ca..b8ed3d9ca 100644 --- a/common/bruteforce.h +++ b/common/bruteforce.h @@ -13,11 +13,11 @@ // // See LICENSE.txt for the text of the license. //----------------------------------------------------------------------------- -// functions for bruteforcing card keys +// functions for bruteforcing card keys - key generators //----------------------------------------------------------------------------- -#ifndef __BRUTEFORCE_H -#define __BRUTEFORCE_H +#ifndef BRUTEFORCE_H__ +#define BRUTEFORCE_H__ #include "common.h" @@ -69,11 +69,11 @@ typedef struct { } 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 +void bf_generator_init(generator_context_t *ctx, uint8_t mode); +int bf_generator_set_charset(generator_context_t *ctx, uint8_t charsets); +int bf_generate32(generator_context_t *ctx); +int _bf_generate_mode_range32(generator_context_t *ctx); +int _bf_generate_mode_charset32(generator_context_t *ctx); +int _bf_generate_mode_smart32(generator_context_t *ctx); +int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo); +#endif // BRUTEFORCE_H__ \ No newline at end of file From 19d7851c732781215ec163fca123410442c5ab6f Mon Sep 17 00:00:00 2001 From: PhaseLoop Date: Mon, 8 May 2023 17:08:24 +0000 Subject: [PATCH 4/8] run "make style" --- armsrc/em4x50.c | 4 +- client/src/cmdlfem4x50.c | 48 +++++++-------- client/src/pm3line_vocabulory.h | 1 + common/bruteforce.c | 54 ++++++++--------- common/bruteforce.h | 10 ++-- doc/commands.json | 100 ++++++++++++++++++++------------ doc/commands.md | 5 +- 7 files changed, 124 insertions(+), 98 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 5043d753b..d43a6a15f 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -643,10 +643,10 @@ static bool brute(em4x50_data_t *etd, uint32_t *pwd) { bf_generator_init(&ctx, etd->bruteforce_mode); - if(etd->bruteforce_mode == BRUTEFORCE_MODE_CHARSET) + if (etd->bruteforce_mode == BRUTEFORCE_MODE_CHARSET) bf_generator_set_charset(&ctx, etd->bruteforce_charset); - while ( (generator_ret=bf_generate32(&ctx)) == GENERATOR_NEXT) { + while ((generator_ret = bf_generate32(&ctx)) == GENERATOR_NEXT) { *pwd = ctx.current_key32; WDT_HIT(); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a67508848..aeffb9c18 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -373,19 +373,19 @@ int CmdEM4x50Brute(const char *Cmd) { int mode_len = 64; char mode[64]; - CLIGetStrWithReturn(ctx, 1, (uint8_t*) mode, &mode_len); + CLIGetStrWithReturn(ctx, 1, (uint8_t *) mode, &mode_len); PrintAndLogEx(INFO, "Chosen mode: %s", mode); - if(strcmp(mode, "range") == 0){ + if (strcmp(mode, "range") == 0) { etd.bruteforce_mode = BRUTEFORCE_MODE_RANGE; - } else if(strcmp(mode, "charset") == 0){ + } else if (strcmp(mode, "charset") == 0) { etd.bruteforce_mode = BRUTEFORCE_MODE_CHARSET; } else { PrintAndLogEx(FAILED, "Unknown bruteforce mode: %s", mode); return PM3_EINVARG; } - if(etd.bruteforce_mode == BRUTEFORCE_MODE_RANGE){ + if (etd.bruteforce_mode == BRUTEFORCE_MODE_RANGE) { int begin_len = 0; uint8_t begin[4] = {0x0}; CLIGetHexWithReturn(ctx, 2, begin, &begin_len); @@ -394,58 +394,58 @@ int CmdEM4x50Brute(const char *Cmd) { uint8_t end[4] = {0x0}; CLIGetHexWithReturn(ctx, 3, end, &end_len); - if(begin_len!=4){ + if (begin_len != 4) { PrintAndLogEx(FAILED, "'begin' parameter must be 4 bytes"); return PM3_EINVARG; } - if(end_len!=4){ + if (end_len != 4) { PrintAndLogEx(FAILED, "'end' parameter must be 4 bytes"); return PM3_EINVARG; } etd.password1 = BYTES2UINT32_BE(begin); etd.password2 = BYTES2UINT32_BE(end); - } else if(etd.bruteforce_mode == BRUTEFORCE_MODE_CHARSET){ + } else if (etd.bruteforce_mode == BRUTEFORCE_MODE_CHARSET) { bool enable_digits = arg_get_lit(ctx, 4); bool enable_uppercase = arg_get_lit(ctx, 5); - if(enable_digits) + if (enable_digits) etd.bruteforce_charset |= CHARSET_DIGITS; - if(enable_uppercase) + if (enable_uppercase) etd.bruteforce_charset |= CHARSET_UPPERCASE; - - if(etd.bruteforce_charset == 0){ + + if (etd.bruteforce_charset == 0) { PrintAndLogEx(FAILED, "Please enable at least one charset when using charset bruteforce mode."); return PM3_EINVARG; } - PrintAndLogEx(INFO, "Enabled charsets: %s%s", - enable_digits ? "digits " : "", - enable_uppercase ? "uppercase " : ""); + PrintAndLogEx(INFO, "Enabled charsets: %s%s", + enable_digits ? "digits " : "", + enable_uppercase ? "uppercase " : ""); } CLIParserFree(ctx); - + // 27 passwords/second (empirical value) const int speed = 27; int no_iter = 0; - if(etd.bruteforce_mode == BRUTEFORCE_MODE_RANGE){ + if (etd.bruteforce_mode == BRUTEFORCE_MODE_RANGE) { no_iter = etd.password2 - etd.password1 + 1; PrintAndLogEx(INFO, "Trying " _YELLOW_("%i") " passwords in range [0x%08x, 0x%08x]" - , no_iter - , etd.password1 - , etd.password2 - ); - } else if(etd.bruteforce_mode == BRUTEFORCE_MODE_CHARSET){ + , no_iter + , etd.password1 + , etd.password2 + ); + } else if (etd.bruteforce_mode == BRUTEFORCE_MODE_CHARSET) { unsigned int digits = 0; - if(etd.bruteforce_charset & CHARSET_DIGITS) + if (etd.bruteforce_charset & CHARSET_DIGITS) digits += CHARSET_DIGITS_SIZE; - if(etd.bruteforce_charset & CHARSET_UPPERCASE) + if (etd.bruteforce_charset & CHARSET_UPPERCASE) digits += CHARSET_UPPERCASE_SIZE; no_iter = pow(digits, 4); @@ -457,7 +457,7 @@ int CmdEM4x50Brute(const char *Cmd) { int dur_m = (dur_s - dur_h * 3600) / 60; dur_s -= dur_h * 3600 + dur_m * 60; - + PrintAndLogEx(INFO, "Estimated duration: %ih %im %is", dur_h, dur_m, dur_s); // start diff --git a/client/src/pm3line_vocabulory.h b/client/src/pm3line_vocabulory.h index 6b15007c3..f70717c8f 100644 --- a/client/src/pm3line_vocabulory.h +++ b/client/src/pm3line_vocabulory.h @@ -349,6 +349,7 @@ const static vocabulory_t vocabulory[] = { { 0, "hf mf gen3freeze" }, { 0, "hf mf ggetblk" }, { 0, "hf mf gload" }, + { 0, "hf mf gsave" }, { 0, "hf mf gsetblk" }, { 0, "hf mf gview" }, { 0, "hf mf ndefformat" }, diff --git a/common/bruteforce.c b/common/bruteforce.c index 62d411240..d4855aefa 100644 --- a/common/bruteforce.c +++ b/common/bruteforce.c @@ -28,50 +28,50 @@ uint8_t charset_uppercase[] = { 'X', 'Y', 'Z' }; -void bf_generator_init(generator_context_t* ctx, uint8_t mode){ +void bf_generator_init(generator_context_t *ctx, uint8_t mode) { memset(ctx, 0, sizeof(generator_context_t)); ctx->mode = mode; } -int bf_generator_set_charset(generator_context_t* ctx, uint8_t charsets){ - if (ctx->mode != BRUTEFORCE_MODE_CHARSET){ +int bf_generator_set_charset(generator_context_t *ctx, uint8_t charsets) { + if (ctx->mode != BRUTEFORCE_MODE_CHARSET) { return -1; } - if(charsets & CHARSET_DIGITS){ + 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)); + if (charsets & CHARSET_UPPERCASE) { + memcpy(ctx->charset + ctx->charset_length, charset_uppercase, sizeof(charset_uppercase)); ctx->charset_length += sizeof(charset_uppercase); } return 0; } -int bf_generate32(generator_context_t *ctx){ +int bf_generate32(generator_context_t *ctx) { - switch(ctx->mode){ + switch (ctx->mode) { case BRUTEFORCE_MODE_RANGE: return _bf_generate_mode_range32(ctx); case BRUTEFORCE_MODE_CHARSET: return _bf_generate_mode_charset32(ctx); - } + } - return GENERATOR_ERROR; + return GENERATOR_ERROR; } -int _bf_generate_mode_range32(generator_context_t *ctx){ - - if(ctx->current_key32 >= ctx->range_high){ +int _bf_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){ + if (ctx->current_key32 <= ctx->range_low && ctx->flag1 == false) { ctx->current_key32 = ctx->range_low; ctx->pos[0] = true; return GENERATOR_NEXT; @@ -81,44 +81,44 @@ int _bf_generate_mode_range32(generator_context_t *ctx){ return GENERATOR_NEXT; } -int _bf_generate_mode_charset32(generator_context_t *ctx){ +int _bf_generate_mode_charset32(generator_context_t *ctx) { - if(ctx->flag1) + if (ctx->flag1) return GENERATOR_END; 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(bf_array_increment(ctx->pos, 4, ctx->charset_length) == -1) + + if (bf_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 bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo){ - +int bf_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) + if (data[i] < modulo - 1) break; - if(i == data_len) - return -1; + if (i == data_len) + return -1; - for (uint8_t pos = data_len - 1;; pos--){ + 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){ + 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; @@ -144,4 +144,4 @@ int main(){ // 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 index b8ed3d9ca..91e01172d 100644 --- a/common/bruteforce.h +++ b/common/bruteforce.h @@ -25,11 +25,11 @@ 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 +// 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 +// "smart" mode - try some predictable patterns #define BRUTEFORCE_MODE_SMART 3 @@ -57,8 +57,8 @@ typedef struct { uint32_t current_key32; uint8_t mode; uint8_t charset[ - CHARSET_DIGITS_SIZE - + CHARSET_UPPERCASE_SIZE + CHARSET_DIGITS_SIZE + + CHARSET_UPPERCASE_SIZE ]; uint8_t charset_length; @@ -76,4 +76,4 @@ int _bf_generate_mode_range32(generator_context_t *ctx); int _bf_generate_mode_charset32(generator_context_t *ctx); int _bf_generate_mode_smart32(generator_context_t *ctx); int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo); -#endif // BRUTEFORCE_H__ \ No newline at end of file +#endif // BRUTEFORCE_H__ diff --git a/doc/commands.json b/doc/commands.json index a94e5bc6a..633dd198e 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3391,6 +3391,20 @@ ], "usage": "hf jooki sim [-h] [-b ]" }, + "hf ksx6924 balance": { + "command": "hf ksx6924 balance", + "description": "Gets the current purse balance", + "notes": [ + "hf ksx6924 balance" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-k, --keep keep field ON for next command", + "-a, --apdu Show APDU requests and responses" + ], + "usage": "hf ksx6924 balance [-hka]" + }, "hf ksx6924 help": { "command": "hf ksx6924 help", "description": "help This help", @@ -3399,19 +3413,6 @@ "options": [], "usage": "" }, - "hf ksx6924 select": { - "command": "hf ksx6924 select", - "description": "Selects KS X 6924 application, and leaves field up", - "notes": [ - "hf ksx6924 select" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-a, --apdu Show APDU requests and responses" - ], - "usage": "hf ksx6924 select [-ha]" - }, "hf ksx6924 info": { "command": "hf ksx6924 info", "description": "Get info about a KS X 6924 transit card. This application is used by T-Money (South Korea) and Snapper+ (Wellington, New Zealand).", @@ -3426,23 +3427,9 @@ ], "usage": "hf ksx6924 info [-hka]" }, - "hf ksx6924 balance": { - "command": "hf ksx6924 balance", - "description": "Gets the current purse balance", - "notes": [ - "hf ksx6924 balance" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-k, --keep keep field ON for next command", - "-a, --apdu Show APDU requests and responses" - ], - "usage": "hf ksx6924 balance [-hka]" - }, "hf ksx6924 init": { "command": "hf ksx6924 init", - "description": "Perform transaction initialization (mpda)", + "description": "Perform transaction initialization with Mpda (Money of Purchase Transaction)", "notes": [ "hf ksx6924 init 000003e8 -> Mpda" ], @@ -3468,7 +3455,19 @@ ], "usage": "hf ksx6924 prec [-hka] " }, - + "hf ksx6924 select": { + "command": "hf ksx6924 select", + "description": "Selects KS X 6924 application, and leaves field up", + "notes": [ + "hf ksx6924 select" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-a, --apdu Show APDU requests and responses" + ], + "usage": "hf ksx6924 select [-ha]" + }, "hf legic crc": { "command": "hf legic crc", "description": "Calculates the legic crc8/crc16 on the given data", @@ -3971,7 +3970,7 @@ "--1k MIFARE Classic 1k / S50 (def)", "--2k MIFARE Classic/Plus 2k", "--4k MIFARE Classic 4k / S70", - "--emu from emulator memory" + "--emu to emulator memory" ], "usage": "hf mf csave [-h] [-f ] [--mini] [--1k] [--2k] [--4k] [--emu]" }, @@ -4348,6 +4347,27 @@ ], "usage": "hf mf gload [-hv] [--mini] [--1k] [--2k] [--4k] [-p ] [-f ] [--emu] [--start ] [--end ]" }, + "hf mf gsave": { + "command": "hf mf gsave", + "description": "Save `magic gen4 gtu` card memory into three files (BIN/EML/JSON)or into emulator memory", + "notes": [ + "hf mf gsave", + "hf mf gsave --4k", + "hf mf gsave -p DEADBEEF -f hf-mf-01020304.json" + ], + "offline": false, + "options": [ + "-h, --help This help", + "--mini MIFARE Classic Mini / S20", + "--1k MIFARE Classic 1k / S50 (def)", + "--2k MIFARE Classic/Plus 2k", + "--4k MIFARE Classic 4k / S70", + "-p, --pwd password 4bytes", + "-f, --file filename of dump", + "--emu to emulator memory" + ], + "usage": "hf mf gsave [-h] [--mini] [--1k] [--2k] [--4k] [-p ] [-f ] [--emu]" + }, "hf mf gsetblk": { "command": "hf mf gsetblk", "description": "Set block data on a magic gen4 GTU card", @@ -6176,7 +6196,7 @@ }, "hf mfu esave": { "command": "hf mfu esave", - "description": "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json) By default number of pages saved depends on defined tag type. You can overrife this with option --end.", + "description": "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json) By default number of pages saved depends on defined tag type. You can override this with option --end.", "notes": [ "hf mfu esave", "hf mfu esave --end 255 -> saves whole memory", @@ -6192,7 +6212,7 @@ }, "hf mfu eview": { "command": "hf mfu eview", - "description": "Displays emulator memory By default number of pages shown depends on defined tag type. You can overrife this with option --end.", + "description": "Displays emulator memory By default number of pages shown depends on defined tag type. You can override this with option --end.", "notes": [ "hf mfu eview", "hf mfu eview --end 255 -> dumps whole memory" @@ -7799,15 +7819,19 @@ "command": "lf em 4x50 brute", "description": "Tries to bruteforce the password of a EM4x50 card. Function can be stopped by pressing pm3 button.", "notes": [ - "lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000" + "lf em 4x50 brute --mode range --begin 12330000 --end 12340000 -> tries pwds from 0x12330000 to 0x12340000", + "lf em 4x50 brute --mode charset --digits --uppercase -> tries all combinations of ASCII codes for digits and uppercase letters" ], "offline": false, "options": [ "-h, --help This help", - "--first first password (start), 4 bytes, lsb", - "--last last password (stop), 4 bytes, lsb" + "--mode Bruteforce mode (range|charset)", + "--begin Range mode - start of the key range", + "--end Range mode - end of the key range", + "--digits Charset mode - include ASCII codes for digits", + "--uppercase Charset mode - include ASCII codes for uppercase letters" ], - "usage": "lf em 4x50 brute [-h] --first --last " + "usage": "lf em 4x50 brute [-h] --mode [--begin ] [--end ] [--digits] [--uppercase]" }, "lf em 4x50 chk": { "command": "lf em 4x50 chk", @@ -11616,8 +11640,8 @@ } }, "metadata": { - "commands_extracted": 732, + "commands_extracted": 733, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2022-11-20T20:19:15" + "extracted_on": "2023-05-08T17:05:11" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index 4b91901f4..2cd9fe2b3 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -370,7 +370,7 @@ Check column "offline" for their availability. |`hf ksx6924 select `|N |`Select application, and leave field up` |`hf ksx6924 info `|N |`Get info about a KS X 6924 (T-Money, Snapper+) transit card` |`hf ksx6924 balance `|N |`Get current purse balance` -|`hf ksx6924 init `|N |`Perform transaction initialization with Mpda (Money of Purchase Transaction)` +|`hf ksx6924 init `|N |`Perform transaction initialization with Mpda` |`hf ksx6924 prec `|N |`Send proprietary get record command (CLA=90, INS=4C)` @@ -512,6 +512,7 @@ Check column "offline" for their availability. |`hf mf gen3freeze `|N |`Perma lock UID changes. irreversible` |`hf mf ggetblk `|N |`Read block from card` |`hf mf gload `|N |`Load dump to card` +|`hf mf gsave `|N |`Save dump from card into file or emulator` |`hf mf gsetblk `|N |`Write block to card` |`hf mf gview `|N |`View card` |`hf mf ndefformat `|N |`Format MIFARE Classic Tag as NFC Tag` @@ -851,7 +852,7 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`lf em 4x50 help `|Y |`This help` -|`lf em 4x50 brute `|N |`Simple bruteforce attack to find password` +|`lf em 4x50 brute `|N |`Bruteforce attack to find password` |`lf em 4x50 chk `|N |`Check passwords from dictionary` |`lf em 4x50 dump `|N |`Dump EM4x50 tag` |`lf em 4x50 info `|N |`Tag information` From d74b625b8b8d92b4db9913ee12f0e01098e126ea Mon Sep 17 00:00:00 2001 From: PhaseLoop Date: Mon, 8 May 2023 17:20:35 +0000 Subject: [PATCH 5/8] place bruteforce lib with em4x50 in Makefile --- armsrc/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 4a088cbf6..32bfef50c 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -46,7 +46,6 @@ SRC_CRC = crc.c crc16.c crc32.c SRC_ICLASS = iclass.c optimized_cipherutils.c optimized_ikeys.c optimized_elite.c optimized_cipher.c SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c SRC_NFCBARCODE = thinfilm.c -SRC_BRUTEFORCE = bruteforce.c # SRC_BEE = bee.c @@ -78,7 +77,7 @@ else endif ifneq (,$(findstring WITH_EM4x50,$(APP_CFLAGS))) - SRC_EM4x50 = em4x50.c + SRC_EM4x50 = em4x50.c bruteforce.c else SRC_EM4x50 = endif @@ -144,7 +143,6 @@ THUMBSRC = start.c \ $(SRC_FELICA) \ $(SRC_STANDALONE) \ $(SRC_ZX) \ - $(SRC_BRUTEFORCE) \ appmain.c \ printf.c \ dbprint.c \ From 1fd331ea7ff09a07237ab79caade894cbe111417 Mon Sep 17 00:00:00 2001 From: PhaseLoop Date: Mon, 8 May 2023 17:57:14 +0000 Subject: [PATCH 6/8] remove dead code --- common/bruteforce.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/common/bruteforce.c b/common/bruteforce.c index d4855aefa..891796690 100644 --- a/common/bruteforce.c +++ b/common/bruteforce.c @@ -127,21 +127,3 @@ int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo) { 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; -} -*/ From 22ae67d2cfc588b4095d329d21f7bb4f10fb7d85 Mon Sep 17 00:00:00 2001 From: PhaseLoop Date: Fri, 26 May 2023 07:20:27 +0000 Subject: [PATCH 7/8] Revert doc autostyle --- doc/commands.json | 100 ++++++++++++++++++---------------------------- doc/commands.md | 5 +-- 2 files changed, 40 insertions(+), 65 deletions(-) diff --git a/doc/commands.json b/doc/commands.json index 633dd198e..a94e5bc6a 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3391,20 +3391,6 @@ ], "usage": "hf jooki sim [-h] [-b ]" }, - "hf ksx6924 balance": { - "command": "hf ksx6924 balance", - "description": "Gets the current purse balance", - "notes": [ - "hf ksx6924 balance" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-k, --keep keep field ON for next command", - "-a, --apdu Show APDU requests and responses" - ], - "usage": "hf ksx6924 balance [-hka]" - }, "hf ksx6924 help": { "command": "hf ksx6924 help", "description": "help This help", @@ -3413,6 +3399,19 @@ "options": [], "usage": "" }, + "hf ksx6924 select": { + "command": "hf ksx6924 select", + "description": "Selects KS X 6924 application, and leaves field up", + "notes": [ + "hf ksx6924 select" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-a, --apdu Show APDU requests and responses" + ], + "usage": "hf ksx6924 select [-ha]" + }, "hf ksx6924 info": { "command": "hf ksx6924 info", "description": "Get info about a KS X 6924 transit card. This application is used by T-Money (South Korea) and Snapper+ (Wellington, New Zealand).", @@ -3427,9 +3426,23 @@ ], "usage": "hf ksx6924 info [-hka]" }, + "hf ksx6924 balance": { + "command": "hf ksx6924 balance", + "description": "Gets the current purse balance", + "notes": [ + "hf ksx6924 balance" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-k, --keep keep field ON for next command", + "-a, --apdu Show APDU requests and responses" + ], + "usage": "hf ksx6924 balance [-hka]" + }, "hf ksx6924 init": { "command": "hf ksx6924 init", - "description": "Perform transaction initialization with Mpda (Money of Purchase Transaction)", + "description": "Perform transaction initialization (mpda)", "notes": [ "hf ksx6924 init 000003e8 -> Mpda" ], @@ -3455,19 +3468,7 @@ ], "usage": "hf ksx6924 prec [-hka] " }, - "hf ksx6924 select": { - "command": "hf ksx6924 select", - "description": "Selects KS X 6924 application, and leaves field up", - "notes": [ - "hf ksx6924 select" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-a, --apdu Show APDU requests and responses" - ], - "usage": "hf ksx6924 select [-ha]" - }, + "hf legic crc": { "command": "hf legic crc", "description": "Calculates the legic crc8/crc16 on the given data", @@ -3970,7 +3971,7 @@ "--1k MIFARE Classic 1k / S50 (def)", "--2k MIFARE Classic/Plus 2k", "--4k MIFARE Classic 4k / S70", - "--emu to emulator memory" + "--emu from emulator memory" ], "usage": "hf mf csave [-h] [-f ] [--mini] [--1k] [--2k] [--4k] [--emu]" }, @@ -4347,27 +4348,6 @@ ], "usage": "hf mf gload [-hv] [--mini] [--1k] [--2k] [--4k] [-p ] [-f ] [--emu] [--start ] [--end ]" }, - "hf mf gsave": { - "command": "hf mf gsave", - "description": "Save `magic gen4 gtu` card memory into three files (BIN/EML/JSON)or into emulator memory", - "notes": [ - "hf mf gsave", - "hf mf gsave --4k", - "hf mf gsave -p DEADBEEF -f hf-mf-01020304.json" - ], - "offline": false, - "options": [ - "-h, --help This help", - "--mini MIFARE Classic Mini / S20", - "--1k MIFARE Classic 1k / S50 (def)", - "--2k MIFARE Classic/Plus 2k", - "--4k MIFARE Classic 4k / S70", - "-p, --pwd password 4bytes", - "-f, --file filename of dump", - "--emu to emulator memory" - ], - "usage": "hf mf gsave [-h] [--mini] [--1k] [--2k] [--4k] [-p ] [-f ] [--emu]" - }, "hf mf gsetblk": { "command": "hf mf gsetblk", "description": "Set block data on a magic gen4 GTU card", @@ -6196,7 +6176,7 @@ }, "hf mfu esave": { "command": "hf mfu esave", - "description": "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json) By default number of pages saved depends on defined tag type. You can override this with option --end.", + "description": "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json) By default number of pages saved depends on defined tag type. You can overrife this with option --end.", "notes": [ "hf mfu esave", "hf mfu esave --end 255 -> saves whole memory", @@ -6212,7 +6192,7 @@ }, "hf mfu eview": { "command": "hf mfu eview", - "description": "Displays emulator memory By default number of pages shown depends on defined tag type. You can override this with option --end.", + "description": "Displays emulator memory By default number of pages shown depends on defined tag type. You can overrife this with option --end.", "notes": [ "hf mfu eview", "hf mfu eview --end 255 -> dumps whole memory" @@ -7819,19 +7799,15 @@ "command": "lf em 4x50 brute", "description": "Tries to bruteforce the password of a EM4x50 card. Function can be stopped by pressing pm3 button.", "notes": [ - "lf em 4x50 brute --mode range --begin 12330000 --end 12340000 -> tries pwds from 0x12330000 to 0x12340000", - "lf em 4x50 brute --mode charset --digits --uppercase -> tries all combinations of ASCII codes for digits and uppercase letters" + "lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000" ], "offline": false, "options": [ "-h, --help This help", - "--mode Bruteforce mode (range|charset)", - "--begin Range mode - start of the key range", - "--end Range mode - end of the key range", - "--digits Charset mode - include ASCII codes for digits", - "--uppercase Charset mode - include ASCII codes for uppercase letters" + "--first first password (start), 4 bytes, lsb", + "--last last password (stop), 4 bytes, lsb" ], - "usage": "lf em 4x50 brute [-h] --mode [--begin ] [--end ] [--digits] [--uppercase]" + "usage": "lf em 4x50 brute [-h] --first --last " }, "lf em 4x50 chk": { "command": "lf em 4x50 chk", @@ -11640,8 +11616,8 @@ } }, "metadata": { - "commands_extracted": 733, + "commands_extracted": 732, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2023-05-08T17:05:11" + "extracted_on": "2022-11-20T20:19:15" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index 2cd9fe2b3..4b91901f4 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -370,7 +370,7 @@ Check column "offline" for their availability. |`hf ksx6924 select `|N |`Select application, and leave field up` |`hf ksx6924 info `|N |`Get info about a KS X 6924 (T-Money, Snapper+) transit card` |`hf ksx6924 balance `|N |`Get current purse balance` -|`hf ksx6924 init `|N |`Perform transaction initialization with Mpda` +|`hf ksx6924 init `|N |`Perform transaction initialization with Mpda (Money of Purchase Transaction)` |`hf ksx6924 prec `|N |`Send proprietary get record command (CLA=90, INS=4C)` @@ -512,7 +512,6 @@ Check column "offline" for their availability. |`hf mf gen3freeze `|N |`Perma lock UID changes. irreversible` |`hf mf ggetblk `|N |`Read block from card` |`hf mf gload `|N |`Load dump to card` -|`hf mf gsave `|N |`Save dump from card into file or emulator` |`hf mf gsetblk `|N |`Write block to card` |`hf mf gview `|N |`View card` |`hf mf ndefformat `|N |`Format MIFARE Classic Tag as NFC Tag` @@ -852,7 +851,7 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`lf em 4x50 help `|Y |`This help` -|`lf em 4x50 brute `|N |`Bruteforce attack to find password` +|`lf em 4x50 brute `|N |`Simple bruteforce attack to find password` |`lf em 4x50 chk `|N |`Check passwords from dictionary` |`lf em 4x50 dump `|N |`Dump EM4x50 tag` |`lf em 4x50 info `|N |`Tag information` From 0f4b787df1fd63321c174ece3b4f96cb3d38e79f Mon Sep 17 00:00:00 2001 From: PhaseLoop Date: Sat, 27 May 2023 07:18:59 +0000 Subject: [PATCH 8/8] replace bzero with memset --- client/src/cmdlfem4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index aeffb9c18..56bf9f6d7 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -369,7 +369,7 @@ int CmdEM4x50Brute(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); em4x50_data_t etd; - bzero(&etd, sizeof(etd)); + memset(&etd, 0, sizeof(etd)); int mode_len = 64; char mode[64];