mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -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);
|
||||
|
||||
if (etd->bruteforce_mode == BF_MODE_CHARSET){
|
||||
if (etd->bruteforce_mode == BF_MODE_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_high = etd->password2;
|
||||
}
|
||||
|
|
|
@ -749,6 +749,7 @@ SRCS = mifare/aiddesfire.c \
|
|||
|
||||
# common
|
||||
SRCS += bucketsort.c \
|
||||
bruteforce.c \
|
||||
cardhelper.c \
|
||||
crapto1/crapto1.c \
|
||||
crapto1/crypto1.c \
|
||||
|
|
|
@ -2337,3 +2337,39 @@ EA0CA627FD06
|
|||
# Hotel key
|
||||
CE0F4F15E909
|
||||
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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "bruteforce.h"
|
||||
#include "cmdhfmf.h"
|
||||
#include <ctype.h>
|
||||
#include "cmdparser.h" // command_t
|
||||
|
@ -3369,6 +3370,216 @@ out:
|
|||
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) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mf chk",
|
||||
|
@ -9054,6 +9265,7 @@ static command_t CommandTable[] = {
|
|||
{"nested", CmdHF14AMfNested, IfPm3Iso14443a, "Nested attack"},
|
||||
{"hardnested", CmdHF14AMfNestedHard, AlwaysAvailable, "Nested attack for hardened 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"},
|
||||
// {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"},
|
||||
{"nack", CmdHf14AMfNack, IfPm3Iso14443a, "Test for MIFARE NACK bug"},
|
||||
|
|
|
@ -386,10 +386,9 @@ int CmdEM4x50Brute(const char *Cmd) {
|
|||
etd.bruteforce_mode = BF_MODE_RANGE;
|
||||
} else if (strcmp(mode, "charset") == 0) {
|
||||
etd.bruteforce_mode = BF_MODE_CHARSET;
|
||||
} else if (strcmp(mode, "smart") == 0){
|
||||
} else if (strcmp(mode, "smart") == 0) {
|
||||
etd.bruteforce_mode = BF_MODE_SMART;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "Unknown bruteforce mode: %s", mode);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
|
@ -471,7 +470,7 @@ int CmdEM4x50Brute(const char *Cmd) {
|
|||
|
||||
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);
|
||||
else
|
||||
PrintAndLogEx(INFO, "Estimated duration: unknown");
|
||||
|
|
|
@ -327,6 +327,7 @@ const static vocabulary_t vocabulary[] = {
|
|||
{ 0, "hf mf nested" },
|
||||
{ 1, "hf mf hardnested" },
|
||||
{ 0, "hf mf staticnested" },
|
||||
{ 0, "hf mf brute" },
|
||||
{ 0, "hf mf autopwn" },
|
||||
{ 0, "hf mf nack" },
|
||||
{ 0, "hf mf chk" },
|
||||
|
@ -501,8 +502,6 @@ const static vocabulary_t vocabulary[] = {
|
|||
{ 1, "hf vas help" },
|
||||
{ 0, "hf vas reader" },
|
||||
{ 1, "hf vas decrypt" },
|
||||
{ 1, "hf waveshare help" },
|
||||
{ 0, "hf waveshare loadbmp" },
|
||||
{ 1, "hf xerox help" },
|
||||
{ 0, "hf xerox info" },
|
||||
{ 0, "hf xerox reader" },
|
||||
|
|
|
@ -30,6 +30,8 @@ uint8_t charset_uppercase[] = {
|
|||
|
||||
smart_generator_t *smart_generators[] = {
|
||||
smart_generator_byte_repeat,
|
||||
smart_generator_msb_byte_only,
|
||||
smart_generator_nibble_sequence,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -68,7 +70,7 @@ int bf_generate(generator_context_t *ctx) {
|
|||
|
||||
case BF_MODE_SMART:
|
||||
return _bf_generate_mode_smart(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
return BF_GENERATOR_ERROR;
|
||||
}
|
||||
|
@ -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
|
||||
uint32_t bf_get_key32(generator_context_t *ctx){
|
||||
uint32_t bf_get_key32(generator_context_t *ctx) {
|
||||
return ctx->current_key & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void bf_generator_clear(generator_context_t *ctx){
|
||||
void bf_generator_clear(generator_context_t *ctx) {
|
||||
ctx->flag1 = 0;
|
||||
ctx->flag2 = 0;
|
||||
ctx->flag3 = 0;
|
||||
|
@ -126,7 +128,7 @@ void bf_generator_clear(generator_context_t *ctx){
|
|||
int _bf_generate_mode_range(generator_context_t *ctx) {
|
||||
|
||||
if (ctx->key_length != BF_KEY_SIZE_32 && ctx->key_length != BF_KEY_SIZE_48)
|
||||
return BF_GENERATOR_ERROR;
|
||||
return BF_GENERATOR_ERROR;
|
||||
|
||||
if (ctx->current_key >= ctx->range_high) {
|
||||
return BF_GENERATOR_END;
|
||||
|
@ -146,7 +148,7 @@ int _bf_generate_mode_range(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;
|
||||
}
|
||||
|
||||
|
@ -156,9 +158,8 @@ int _bf_generate_mode_charset(generator_context_t *ctx) {
|
|||
uint8_t key_byte = 0;
|
||||
ctx->current_key = 0;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
if (bf_array_increment(ctx->pos, ctx->key_length, ctx->charset_length) == -1)
|
||||
|
@ -168,17 +169,17 @@ int _bf_generate_mode_charset(generator_context_t *ctx) {
|
|||
return BF_GENERATOR_NEXT;
|
||||
}
|
||||
|
||||
int _bf_generate_mode_smart(generator_context_t *ctx){
|
||||
int _bf_generate_mode_smart(generator_context_t *ctx) {
|
||||
|
||||
int ret;
|
||||
|
||||
while(1){
|
||||
while (1) {
|
||||
if (smart_generators[ctx->smart_mode_stage] == NULL)
|
||||
return BF_GENERATOR_END;
|
||||
return BF_GENERATOR_END;
|
||||
|
||||
ret = smart_generators[ctx->smart_mode_stage](ctx);
|
||||
|
||||
switch (ret){
|
||||
switch (ret) {
|
||||
case BF_GENERATOR_NEXT:
|
||||
return ret;
|
||||
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
|
||||
uint32_t current_byte = ctx->counter1;
|
||||
|
||||
|
@ -201,13 +202,59 @@ int smart_generator_byte_repeat(generator_context_t *ctx){
|
|||
|
||||
ctx->current_key = 0;
|
||||
|
||||
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);
|
||||
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->counter1++;
|
||||
return BF_GENERATOR_NEXT;
|
||||
}
|
||||
int smart_generator_test2(generator_context_t *ctx){
|
||||
return 0;
|
||||
int smart_generator_msb_byte_only(generator_context_t *ctx) {
|
||||
// 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 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
|
||||
|
||||
|
|
|
@ -490,6 +490,7 @@ Check column "offline" for their availability.
|
|||
|`hf mf nested `|N |`Nested attack`
|
||||
|`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 brute `|N |`Smart bruteforce to exploit weak key generators`
|
||||
|`hf mf autopwn `|N |`Automatic key recovery tool for MIFARE Classic`
|
||||
|`hf mf nack `|N |`Test for MIFARE NACK bug`
|
||||
|`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 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
|
||||
|
||||
{ Fuji/Xerox cartridge RFIDs... }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue