mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
add smart bruteforce mode to MF Classic and EM4x50
This commit is contained in:
parent
8e0e8e2240
commit
dd859a2061
9 changed files with 323 additions and 37 deletions
|
@ -643,9 +643,9 @@ static bool brute(const em4x50_data_t *etd, uint32_t *pwd) {
|
||||||
|
|
||||||
bf_generator_init(&ctx, etd->bruteforce_mode, BF_KEY_SIZE_32);
|
bf_generator_init(&ctx, etd->bruteforce_mode, BF_KEY_SIZE_32);
|
||||||
|
|
||||||
if (etd->bruteforce_mode == BF_MODE_CHARSET){
|
if (etd->bruteforce_mode == BF_MODE_CHARSET) {
|
||||||
bf_generator_set_charset(&ctx, etd->bruteforce_charset);
|
bf_generator_set_charset(&ctx, etd->bruteforce_charset);
|
||||||
} else if (etd->bruteforce_mode == BF_MODE_RANGE){
|
} else if (etd->bruteforce_mode == BF_MODE_RANGE) {
|
||||||
ctx.range_low = etd->password1;
|
ctx.range_low = etd->password1;
|
||||||
ctx.range_high = etd->password2;
|
ctx.range_high = etd->password2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,6 +749,7 @@ SRCS = mifare/aiddesfire.c \
|
||||||
|
|
||||||
# common
|
# common
|
||||||
SRCS += bucketsort.c \
|
SRCS += bucketsort.c \
|
||||||
|
bruteforce.c \
|
||||||
cardhelper.c \
|
cardhelper.c \
|
||||||
crapto1/crapto1.c \
|
crapto1/crapto1.c \
|
||||||
crapto1/crypto1.c \
|
crapto1/crypto1.c \
|
||||||
|
|
|
@ -2337,3 +2337,39 @@ EA0CA627FD06
|
||||||
# Hotel key
|
# Hotel key
|
||||||
CE0F4F15E909
|
CE0F4F15E909
|
||||||
D60DE9436219
|
D60DE9436219
|
||||||
|
|
||||||
|
# ATM Arena de Girona, spanish transport card
|
||||||
|
|
||||||
|
A00000000000
|
||||||
|
A01000000000
|
||||||
|
A02000000000
|
||||||
|
A03000000000
|
||||||
|
A04000000000
|
||||||
|
A05000000000
|
||||||
|
A06000000000
|
||||||
|
A07000000000
|
||||||
|
A08000000000
|
||||||
|
A09000000000
|
||||||
|
A10000000000
|
||||||
|
A11000000000
|
||||||
|
A12000000000
|
||||||
|
A13000000000
|
||||||
|
A14000000000
|
||||||
|
A15000000000
|
||||||
|
|
||||||
|
B00000000000
|
||||||
|
B01000000000
|
||||||
|
B02000000000
|
||||||
|
B03000000000
|
||||||
|
B04000000000
|
||||||
|
B05000000000
|
||||||
|
B06000000000
|
||||||
|
B07000000000
|
||||||
|
B08000000000
|
||||||
|
B09000000000
|
||||||
|
B10000000000
|
||||||
|
B11000000000
|
||||||
|
B12000000000
|
||||||
|
B13000000000
|
||||||
|
B14000000000
|
||||||
|
B15000000000
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
// High frequency MIFARE commands
|
// High frequency MIFARE commands
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "bruteforce.h"
|
||||||
#include "cmdhfmf.h"
|
#include "cmdhfmf.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "cmdparser.h" // command_t
|
#include "cmdparser.h" // command_t
|
||||||
|
@ -3369,6 +3370,216 @@ out:
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CmdHF14AMfSmartBrute(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf mf brute",
|
||||||
|
"This is a smart bruteforce, exploiting common patterns, bugs and bad designs in key generators.",
|
||||||
|
"hf mf brute --mini --> Key recovery against MIFARE Mini\n"
|
||||||
|
"hf mf brute --1k --> Key recovery against MIFARE Classic 1k\n"
|
||||||
|
"hf mf brute --2k --> Key recovery against MIFARE 2k\n"
|
||||||
|
"hf mf brute --4k --> Key recovery against MIFARE 4k\n"
|
||||||
|
"hf mf brute --1k --emu --> Target 1K, write keys to emulator memory\n"
|
||||||
|
"hf mf brute --1k --dump --> Target 1K, write keys to file\n");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
|
||||||
|
arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (default)"),
|
||||||
|
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
|
||||||
|
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
|
||||||
|
arg_lit0(NULL, "emu", "Fill simulator keys from found keys"),
|
||||||
|
arg_lit0(NULL, "dump", "Dump found keys to binary file"),
|
||||||
|
arg_lit0(NULL, "mem", "Use dictionary from flashmemory"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
|
|
||||||
|
bool m0 = arg_get_lit(ctx, 2);
|
||||||
|
bool m1 = arg_get_lit(ctx, 3);
|
||||||
|
bool m2 = arg_get_lit(ctx, 4);
|
||||||
|
bool m4 = arg_get_lit(ctx, 5);
|
||||||
|
|
||||||
|
bool transferToEml = arg_get_lit(ctx, 6);
|
||||||
|
bool createDumpFile = arg_get_lit(ctx, 7);
|
||||||
|
bool use_flashmemory = arg_get_lit(ctx, 8);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
//validations
|
||||||
|
|
||||||
|
if ((m0 + m1 + m2 + m4) > 1) {
|
||||||
|
PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
} else if ((m0 + m1 + m2 + m4) == 0) {
|
||||||
|
m1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sectorsCnt = MIFARE_1K_MAXSECTOR;
|
||||||
|
if (m0) {
|
||||||
|
sectorsCnt = MIFARE_MINI_MAXSECTOR;
|
||||||
|
} else if (m1) {
|
||||||
|
sectorsCnt = MIFARE_1K_MAXSECTOR;
|
||||||
|
} else if (m2) {
|
||||||
|
sectorsCnt = MIFARE_2K_MAXSECTOR;
|
||||||
|
} else if (m4) {
|
||||||
|
sectorsCnt = MIFARE_4K_MAXSECTOR;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t chunksize = 100 > (PM3_CMD_DATA_SIZE / MIFARE_KEY_SIZE) ? (PM3_CMD_DATA_SIZE / MIFARE_KEY_SIZE) : 100;
|
||||||
|
uint8_t *keyBlock = calloc(MIFARE_KEY_SIZE, chunksize);
|
||||||
|
|
||||||
|
if (keyBlock == NULL)
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
|
||||||
|
// create/initialize key storage structure
|
||||||
|
sector_t *e_sector = NULL;
|
||||||
|
if (initSectorTable(&e_sector, sectorsCnt) != PM3_SUCCESS) {
|
||||||
|
free(keyBlock);
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize bruteforce engine
|
||||||
|
generator_context_t bctx;
|
||||||
|
bf_generator_init(&bctx, BF_MODE_SMART, BF_KEY_SIZE_48);
|
||||||
|
|
||||||
|
int i = 0, ret;
|
||||||
|
int smart_mode_stage = -1;
|
||||||
|
uint64_t generator_key;
|
||||||
|
|
||||||
|
// time
|
||||||
|
uint64_t t0 = msclock();
|
||||||
|
uint64_t t1 = msclock();
|
||||||
|
uint64_t keys_checked = 0;
|
||||||
|
uint64_t total_keys_checked = 0;
|
||||||
|
|
||||||
|
uint32_t keycnt = 0;
|
||||||
|
bool firstChunk = true, lastChunk = false;
|
||||||
|
|
||||||
|
while (!lastChunk) {
|
||||||
|
keycnt = 0;
|
||||||
|
|
||||||
|
// generate block of keys from generator
|
||||||
|
memset(keyBlock, 0, MIFARE_KEY_SIZE * chunksize);
|
||||||
|
for (i = 0; i < chunksize; i++) {
|
||||||
|
ret = bf_generate(&bctx);
|
||||||
|
if (ret == BF_GENERATOR_ERROR) {
|
||||||
|
PrintAndLogEx(ERR, "Internal bruteforce generator error");
|
||||||
|
free(keyBlock);
|
||||||
|
return PM3_EFAILED;
|
||||||
|
} else if (ret == BF_GENERATOR_END) {
|
||||||
|
lastChunk = true;
|
||||||
|
break;
|
||||||
|
} else if (ret == BF_GENERATOR_NEXT) {
|
||||||
|
generator_key = bf_get_key48(&bctx);
|
||||||
|
num_to_bytes(generator_key, MIFARE_KEY_SIZE, keyBlock + (i * MIFARE_KEY_SIZE));
|
||||||
|
keycnt++;
|
||||||
|
|
||||||
|
if (smart_mode_stage != bctx.smart_mode_stage) {
|
||||||
|
smart_mode_stage = bctx.smart_mode_stage;
|
||||||
|
PrintAndLogEx(INFO, "Running bruteforce stage %d", smart_mode_stage);
|
||||||
|
|
||||||
|
if (msclock() - t1 > 0 && keys_checked > 0) {
|
||||||
|
PrintAndLogEx(INFO, "Current cracking speed (keys/s): %d",
|
||||||
|
keys_checked / ((msclock() - t1) / 1000));
|
||||||
|
|
||||||
|
t1 = msclock();
|
||||||
|
keys_checked = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int strategy = 2; // width first on all sectors
|
||||||
|
ret = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, keycnt, keyBlock, e_sector, false, false);
|
||||||
|
|
||||||
|
keys_checked += keycnt;
|
||||||
|
total_keys_checked += keycnt;
|
||||||
|
|
||||||
|
if (firstChunk)
|
||||||
|
firstChunk = false;
|
||||||
|
|
||||||
|
if (ret == PM3_SUCCESS || ret == 2)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
PrintAndLogEx(INFO, "Time in brute mode: " _YELLOW_("%.1fs") "\n", (float)((msclock() - t0) / 1000.0));
|
||||||
|
PrintAndLogEx(INFO, "Total keys checked: " _YELLOW_("%d") "\n", total_keys_checked);
|
||||||
|
// check..
|
||||||
|
uint8_t found_keys = 0;
|
||||||
|
for (i = 0; i < sectorsCnt; ++i) {
|
||||||
|
|
||||||
|
if (e_sector[i].foundKey[0])
|
||||||
|
found_keys++;
|
||||||
|
|
||||||
|
if (e_sector[i].foundKey[1])
|
||||||
|
found_keys++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_keys == 0) {
|
||||||
|
PrintAndLogEx(WARNING, "No keys found");
|
||||||
|
} else {
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
|
||||||
|
|
||||||
|
printKeyTable(sectorsCnt, e_sector);
|
||||||
|
|
||||||
|
if (use_flashmemory && found_keys == (sectorsCnt << 1)) {
|
||||||
|
PrintAndLogEx(SUCCESS, "Card dumped as well. run " _YELLOW_("`%s %c`"),
|
||||||
|
"hf mf esave",
|
||||||
|
GetFormatFromSector(sectorsCnt)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transferToEml) {
|
||||||
|
// fast push mode
|
||||||
|
g_conn.block_after_ACK = true;
|
||||||
|
uint8_t block[MFBLOCK_SIZE] = {0x00};
|
||||||
|
for (i = 0; i < sectorsCnt; ++i) {
|
||||||
|
uint8_t b = mfFirstBlockOfSector(i) + mfNumBlocksPerSector(i) - 1;
|
||||||
|
mfEmlGetMem(block, b, 1);
|
||||||
|
|
||||||
|
if (e_sector[i].foundKey[0])
|
||||||
|
num_to_bytes(e_sector[i].Key[0], MIFARE_KEY_SIZE, block);
|
||||||
|
|
||||||
|
if (e_sector[i].foundKey[1])
|
||||||
|
num_to_bytes(e_sector[i].Key[1], MIFARE_KEY_SIZE, block + 10);
|
||||||
|
|
||||||
|
if (i == sectorsCnt - 1) {
|
||||||
|
// Disable fast mode on last packet
|
||||||
|
g_conn.block_after_ACK = false;
|
||||||
|
}
|
||||||
|
mfEmlSetMem(block, b, 1);
|
||||||
|
}
|
||||||
|
PrintAndLogEx(SUCCESS, "Found keys have been transferred to the emulator memory");
|
||||||
|
|
||||||
|
if (found_keys == (sectorsCnt << 1)) {
|
||||||
|
FastDumpWithEcFill(sectorsCnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createDumpFile) {
|
||||||
|
|
||||||
|
char *fptr = GenerateFilename("hf-mf-", "-key.bin");
|
||||||
|
if (createMfcKeyDump(fptr, sectorsCnt, e_sector) != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(ERR, "Failed to save keys to file");
|
||||||
|
}
|
||||||
|
free(fptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(keyBlock);
|
||||||
|
free(e_sector);
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdHF14AMfChk(const char *Cmd) {
|
static int CmdHF14AMfChk(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf mf chk",
|
CLIParserInit(&ctx, "hf mf chk",
|
||||||
|
@ -9054,6 +9265,7 @@ static command_t CommandTable[] = {
|
||||||
{"nested", CmdHF14AMfNested, IfPm3Iso14443a, "Nested attack"},
|
{"nested", CmdHF14AMfNested, IfPm3Iso14443a, "Nested attack"},
|
||||||
{"hardnested", CmdHF14AMfNestedHard, AlwaysAvailable, "Nested attack for hardened MIFARE Classic cards"},
|
{"hardnested", CmdHF14AMfNestedHard, AlwaysAvailable, "Nested attack for hardened MIFARE Classic cards"},
|
||||||
{"staticnested", CmdHF14AMfNestedStatic, IfPm3Iso14443a, "Nested attack against static nonce MIFARE Classic cards"},
|
{"staticnested", CmdHF14AMfNestedStatic, IfPm3Iso14443a, "Nested attack against static nonce MIFARE Classic cards"},
|
||||||
|
{"brute", CmdHF14AMfSmartBrute, IfPm3Iso14443a, "Smart bruteforce to exploit weak key generators"},
|
||||||
{"autopwn", CmdHF14AMfAutoPWN, IfPm3Iso14443a, "Automatic key recovery tool for MIFARE Classic"},
|
{"autopwn", CmdHF14AMfAutoPWN, IfPm3Iso14443a, "Automatic key recovery tool for MIFARE Classic"},
|
||||||
// {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"},
|
// {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"},
|
||||||
{"nack", CmdHf14AMfNack, IfPm3Iso14443a, "Test for MIFARE NACK bug"},
|
{"nack", CmdHf14AMfNack, IfPm3Iso14443a, "Test for MIFARE NACK bug"},
|
||||||
|
|
|
@ -386,10 +386,9 @@ int CmdEM4x50Brute(const char *Cmd) {
|
||||||
etd.bruteforce_mode = BF_MODE_RANGE;
|
etd.bruteforce_mode = BF_MODE_RANGE;
|
||||||
} else if (strcmp(mode, "charset") == 0) {
|
} else if (strcmp(mode, "charset") == 0) {
|
||||||
etd.bruteforce_mode = BF_MODE_CHARSET;
|
etd.bruteforce_mode = BF_MODE_CHARSET;
|
||||||
} else if (strcmp(mode, "smart") == 0){
|
} else if (strcmp(mode, "smart") == 0) {
|
||||||
etd.bruteforce_mode = BF_MODE_SMART;
|
etd.bruteforce_mode = BF_MODE_SMART;
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
PrintAndLogEx(FAILED, "Unknown bruteforce mode: %s", mode);
|
PrintAndLogEx(FAILED, "Unknown bruteforce mode: %s", mode);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
@ -471,7 +470,7 @@ int CmdEM4x50Brute(const char *Cmd) {
|
||||||
|
|
||||||
dur_s -= dur_h * 3600 + dur_m * 60;
|
dur_s -= dur_h * 3600 + dur_m * 60;
|
||||||
|
|
||||||
if ( no_iter > 0 )
|
if (no_iter > 0)
|
||||||
PrintAndLogEx(INFO, "Estimated duration: %ih %im %is", dur_h, dur_m, dur_s);
|
PrintAndLogEx(INFO, "Estimated duration: %ih %im %is", dur_h, dur_m, dur_s);
|
||||||
else
|
else
|
||||||
PrintAndLogEx(INFO, "Estimated duration: unknown");
|
PrintAndLogEx(INFO, "Estimated duration: unknown");
|
||||||
|
|
|
@ -327,6 +327,7 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 0, "hf mf nested" },
|
{ 0, "hf mf nested" },
|
||||||
{ 1, "hf mf hardnested" },
|
{ 1, "hf mf hardnested" },
|
||||||
{ 0, "hf mf staticnested" },
|
{ 0, "hf mf staticnested" },
|
||||||
|
{ 0, "hf mf brute" },
|
||||||
{ 0, "hf mf autopwn" },
|
{ 0, "hf mf autopwn" },
|
||||||
{ 0, "hf mf nack" },
|
{ 0, "hf mf nack" },
|
||||||
{ 0, "hf mf chk" },
|
{ 0, "hf mf chk" },
|
||||||
|
@ -501,8 +502,6 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 1, "hf vas help" },
|
{ 1, "hf vas help" },
|
||||||
{ 0, "hf vas reader" },
|
{ 0, "hf vas reader" },
|
||||||
{ 1, "hf vas decrypt" },
|
{ 1, "hf vas decrypt" },
|
||||||
{ 1, "hf waveshare help" },
|
|
||||||
{ 0, "hf waveshare loadbmp" },
|
|
||||||
{ 1, "hf xerox help" },
|
{ 1, "hf xerox help" },
|
||||||
{ 0, "hf xerox info" },
|
{ 0, "hf xerox info" },
|
||||||
{ 0, "hf xerox reader" },
|
{ 0, "hf xerox reader" },
|
||||||
|
|
|
@ -30,6 +30,8 @@ uint8_t charset_uppercase[] = {
|
||||||
|
|
||||||
smart_generator_t *smart_generators[] = {
|
smart_generator_t *smart_generators[] = {
|
||||||
smart_generator_byte_repeat,
|
smart_generator_byte_repeat,
|
||||||
|
smart_generator_msb_byte_only,
|
||||||
|
smart_generator_nibble_sequence,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,16 +108,16 @@ int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get current key casted to 32 bit
|
// get current key casted to 32 bit
|
||||||
uint32_t bf_get_key32(generator_context_t *ctx){
|
uint32_t bf_get_key32(generator_context_t *ctx) {
|
||||||
return ctx->current_key & 0xFFFFFFFF;
|
return ctx->current_key & 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get current key casted to 48 bit
|
// get current key casted to 48 bit
|
||||||
uint64_t bf_get_key48(generator_context_t *ctx){
|
uint64_t bf_get_key48(generator_context_t *ctx) {
|
||||||
return ctx->current_key & 0xFFFFFFFFFFFF;
|
return ctx->current_key & 0xFFFFFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bf_generator_clear(generator_context_t *ctx){
|
void bf_generator_clear(generator_context_t *ctx) {
|
||||||
ctx->flag1 = 0;
|
ctx->flag1 = 0;
|
||||||
ctx->flag2 = 0;
|
ctx->flag2 = 0;
|
||||||
ctx->flag3 = 0;
|
ctx->flag3 = 0;
|
||||||
|
@ -146,7 +148,7 @@ int _bf_generate_mode_range(generator_context_t *ctx) {
|
||||||
|
|
||||||
int _bf_generate_mode_charset(generator_context_t *ctx) {
|
int _bf_generate_mode_charset(generator_context_t *ctx) {
|
||||||
|
|
||||||
if (ctx->key_length != BF_KEY_SIZE_32 && ctx->key_length != BF_KEY_SIZE_48){
|
if (ctx->key_length != BF_KEY_SIZE_32 && ctx->key_length != BF_KEY_SIZE_48) {
|
||||||
return BF_GENERATOR_ERROR;
|
return BF_GENERATOR_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +158,7 @@ int _bf_generate_mode_charset(generator_context_t *ctx) {
|
||||||
uint8_t key_byte = 0;
|
uint8_t key_byte = 0;
|
||||||
ctx->current_key = 0;
|
ctx->current_key = 0;
|
||||||
|
|
||||||
for (key_byte = 0; key_byte < ctx->key_length; key_byte++)
|
for (key_byte = 0; key_byte < ctx->key_length; key_byte++) {
|
||||||
{
|
|
||||||
ctx->current_key |= (uint64_t) ctx->charset[ctx->pos[key_byte]] << ((ctx->key_length - key_byte - 1) * 8);
|
ctx->current_key |= (uint64_t) ctx->charset[ctx->pos[key_byte]] << ((ctx->key_length - key_byte - 1) * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,17 +169,17 @@ int _bf_generate_mode_charset(generator_context_t *ctx) {
|
||||||
return BF_GENERATOR_NEXT;
|
return BF_GENERATOR_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _bf_generate_mode_smart(generator_context_t *ctx){
|
int _bf_generate_mode_smart(generator_context_t *ctx) {
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
while(1){
|
while (1) {
|
||||||
if (smart_generators[ctx->smart_mode_stage] == NULL)
|
if (smart_generators[ctx->smart_mode_stage] == NULL)
|
||||||
return BF_GENERATOR_END;
|
return BF_GENERATOR_END;
|
||||||
|
|
||||||
ret = smart_generators[ctx->smart_mode_stage](ctx);
|
ret = smart_generators[ctx->smart_mode_stage](ctx);
|
||||||
|
|
||||||
switch (ret){
|
switch (ret) {
|
||||||
case BF_GENERATOR_NEXT:
|
case BF_GENERATOR_NEXT:
|
||||||
return ret;
|
return ret;
|
||||||
case BF_GENERATOR_ERROR:
|
case BF_GENERATOR_ERROR:
|
||||||
|
@ -192,7 +193,7 @@ int _bf_generate_mode_smart(generator_context_t *ctx){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int smart_generator_byte_repeat(generator_context_t *ctx){
|
int smart_generator_byte_repeat(generator_context_t *ctx) {
|
||||||
// key consists of repeated single byte
|
// key consists of repeated single byte
|
||||||
uint32_t current_byte = ctx->counter1;
|
uint32_t current_byte = ctx->counter1;
|
||||||
|
|
||||||
|
@ -201,13 +202,59 @@ int smart_generator_byte_repeat(generator_context_t *ctx){
|
||||||
|
|
||||||
ctx->current_key = 0;
|
ctx->current_key = 0;
|
||||||
|
|
||||||
for (uint8_t key_byte = 0; key_byte < ctx->key_length;key_byte++){
|
for (uint8_t key_byte = 0; key_byte < ctx->key_length; key_byte++) {
|
||||||
ctx->current_key |= (uint64_t)current_byte << ((ctx->key_length - key_byte - 1) * 8);
|
ctx->current_key |= (uint64_t)current_byte << ((ctx->key_length - key_byte - 1) * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->counter1++;
|
ctx->counter1++;
|
||||||
return BF_GENERATOR_NEXT;
|
return BF_GENERATOR_NEXT;
|
||||||
}
|
}
|
||||||
int smart_generator_test2(generator_context_t *ctx){
|
int smart_generator_msb_byte_only(generator_context_t *ctx) {
|
||||||
return 0;
|
// key of one byte (most significant one) and all others being zero
|
||||||
|
uint32_t current_byte = ctx->counter1;
|
||||||
|
|
||||||
|
if (current_byte > 0xFF)
|
||||||
|
return BF_GENERATOR_END;
|
||||||
|
|
||||||
|
ctx->current_key = (uint64_t)current_byte << ((ctx->key_length - 1) * 8);
|
||||||
|
|
||||||
|
ctx->counter1++;
|
||||||
|
return BF_GENERATOR_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int smart_generator_nibble_sequence(generator_context_t *ctx) {
|
||||||
|
// patterns like A0A1A2A3...F0F1F2F3
|
||||||
|
// also with offsets - A1A2A3, A2A3A4, etc
|
||||||
|
// counter1 is high nibble (A, B, C), counter2 is low nibble (0,1, etc)
|
||||||
|
|
||||||
|
if(ctx->counter1 == 0){ // init values on first generator call
|
||||||
|
ctx->counter1 = 0x0A;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t key_byte;
|
||||||
|
|
||||||
|
// we substract %2 value because max_offset must be even number
|
||||||
|
uint8_t max_offset = 10 - (ctx->key_length / 2) - (ctx->key_length/2) % 2;
|
||||||
|
|
||||||
|
if(ctx->counter1 == 0x10){
|
||||||
|
return BF_GENERATOR_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->current_key = 0;
|
||||||
|
|
||||||
|
for (key_byte = 0; key_byte < ctx->key_length; key_byte++) {
|
||||||
|
ctx->current_key |= (uint64_t) ctx->counter1 << (((ctx->key_length - key_byte - 1) * 8) + 4);
|
||||||
|
ctx->current_key |= (uint64_t) (key_byte + ctx->counter2) %10 << ((ctx->key_length - key_byte - 1) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// counter 2 is the offset
|
||||||
|
ctx->counter2++;
|
||||||
|
|
||||||
|
if(ctx->counter2 == max_offset){
|
||||||
|
ctx->counter2 = 0;
|
||||||
|
ctx->counter1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BF_GENERATOR_NEXT;
|
||||||
}
|
}
|
|
@ -96,7 +96,8 @@ typedef int (smart_generator_t)(generator_context_t *ctx);
|
||||||
int bf_generate_mode_smart(generator_context_t *ctx);
|
int bf_generate_mode_smart(generator_context_t *ctx);
|
||||||
|
|
||||||
int smart_generator_byte_repeat(generator_context_t *ctx);
|
int smart_generator_byte_repeat(generator_context_t *ctx);
|
||||||
int smart_generator_test2(generator_context_t *ctx);
|
int smart_generator_msb_byte_only(generator_context_t *ctx);
|
||||||
|
int smart_generator_nibble_sequence(generator_context_t *ctx);
|
||||||
|
|
||||||
extern smart_generator_t *smart_generators[]; // array of smart cracking functions
|
extern smart_generator_t *smart_generators[]; // array of smart cracking functions
|
||||||
|
|
||||||
|
|
|
@ -490,6 +490,7 @@ Check column "offline" for their availability.
|
||||||
|`hf mf nested `|N |`Nested attack`
|
|`hf mf nested `|N |`Nested attack`
|
||||||
|`hf mf hardnested `|Y |`Nested attack for hardened MIFARE Classic cards`
|
|`hf mf hardnested `|Y |`Nested attack for hardened MIFARE Classic cards`
|
||||||
|`hf mf staticnested `|N |`Nested attack against static nonce MIFARE Classic cards`
|
|`hf mf staticnested `|N |`Nested attack against static nonce MIFARE Classic cards`
|
||||||
|
|`hf mf brute `|N |`Smart bruteforce to exploit weak key generators`
|
||||||
|`hf mf autopwn `|N |`Automatic key recovery tool for MIFARE Classic`
|
|`hf mf autopwn `|N |`Automatic key recovery tool for MIFARE Classic`
|
||||||
|`hf mf nack `|N |`Test for MIFARE NACK bug`
|
|`hf mf nack `|N |`Test for MIFARE NACK bug`
|
||||||
|`hf mf chk `|N |`Check keys`
|
|`hf mf chk `|N |`Check keys`
|
||||||
|
@ -754,16 +755,6 @@ Check column "offline" for their availability.
|
||||||
|`hf vas decrypt `|Y |`Decrypt a previously captured VAS cryptogram`
|
|`hf vas decrypt `|Y |`Decrypt a previously captured VAS cryptogram`
|
||||||
|
|
||||||
|
|
||||||
### hf waveshare
|
|
||||||
|
|
||||||
{ Waveshare NFC ePaper... }
|
|
||||||
|
|
||||||
|command |offline |description
|
|
||||||
|------- |------- |-----------
|
|
||||||
|`hf waveshare help `|Y |`This help`
|
|
||||||
|`hf waveshare loadbmp `|N |`Load BMP file to Waveshare NFC ePaper`
|
|
||||||
|
|
||||||
|
|
||||||
### hf xerox
|
### hf xerox
|
||||||
|
|
||||||
{ Fuji/Xerox cartridge RFIDs... }
|
{ Fuji/Xerox cartridge RFIDs... }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue