From d9ed4e191445d342d11e35fbe4886980e40771a8 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 8 Aug 2016 17:49:30 +0200 Subject: [PATCH 1/1] ADD: J-Run's 2nd phase tool mf_key_brute ref: https://github.com/J-Run/mf_key_brute Estimated time to search keyspace is ~18min. J_Run's 2nd phase of multiple sector nested authentication key recovery You have a known 4 last bytes of a key recovered with mf_nonce_brute tool. First 2 bytes of key will be bruteforced Usage: hf mf keybrute [h] options: h this help target block number target key type candidate key from mf_nonce_brute tool samples: hf mf keybrute 1 A 000011223344 --- client/cmdhfmf.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ client/cmdhfmf.h | 1 + client/mifarehost.c | 47 ++++++++++++++++++++++++++++++++++++++++ client/mifarehost.h | 1 + 4 files changed, 102 insertions(+) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index ec542eb3..d6e39444 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -125,6 +125,21 @@ int usage_hf14_chk(void){ PrintAndLog(" hf mf chk *1 ? d -- target all blocks, all keys, 1K, write to file"); return 0; } +int usage_hf14_keybrute(void){ + PrintAndLog("J_Run's 2nd phase of multiple sector nested authentication key recovery"); + PrintAndLog("You have a known 4 last bytes of a key recovered with mf_nonce_brute tool."); + PrintAndLog("First 2 bytes of key will be bruteforced"); + PrintAndLog(""); + PrintAndLog("Usage: hf mf keybrute [h] "); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" target block number"); + PrintAndLog(" target key type"); + PrintAndLog(" candidate key from mf_nonce_brute tool"); + PrintAndLog("samples:"); + PrintAndLog(" hf mf keybrute 1 A 000011223344"); + return 0; +} int CmdHF14AMifare(const char *Cmd) { uint32_t uid = 0; @@ -1639,6 +1654,43 @@ int CmdHF14AMfDbg(const char *Cmd) { return 0; } +int CmdHF14AMfKeyBrute(const char *Cmd) { + + uint8_t blockNo = 0, keytype = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + uint64_t foundkey = 0; + + char cmdp = param_getchar(Cmd, 0); + if ( cmdp == 'H' || cmdp == 'h') return usage_hf14_keybrute(); + + // block number + blockNo = param_get8(Cmd, 0); + + // keytype + cmdp = param_getchar(Cmd, 1); + if (cmdp == 'B' || cmdp == 'b') keytype = 1; + + // key + if (param_gethex(Cmd, 2, key, 12)) return usage_hf14_keybrute(); + + clock_t t1 = clock(); + time_t start, end; + time(&start); + + if (mfKeyBrute( blockNo, keytype, key, &foundkey)) + PrintAndLog("Found valid key: %012"llx" \n", foundkey); + else + PrintAndLog("Key not found"); + + t1 = clock() - t1; + time(&end); + unsigned long elapsed_time = difftime(end, start); + if ( t1 > 0 ) + PrintAndLog("\nTime in keybrute: %.0f ticks %u seconds\n", (float)t1, elapsed_time); + + return 0; +} + void printKeyTable( uint8_t sectorscnt, sector *e_sector ){ PrintAndLog("|---|----------------|---|----------------|---|"); PrintAndLog("|sec|key A |res|key B |res|"); @@ -2383,6 +2435,7 @@ static command_t CommandTable[] = { {"mifare", CmdHF14AMifare, 0, "Read parity error messages."}, {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, + {"keybrute", CmdHF14AMfKeyBrute, 0, "J_Run's 2nd phase of multiple sector nested authentication key recovery"}, {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"}, {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index d542b367..738b3432 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -44,6 +44,7 @@ int CmdHF14AMfNested(const char* cmd); int CmdHF14AMfNestedHard(const char *Cmd); int CmdHF14AMfSniff(const char* cmd); int CmdHF14AMf1kSim(const char* cmd); +int CmdHF14AMfKeyBrute(const char *Cmd); int CmdHF14AMfEClear(const char* cmd); int CmdHF14AMfEGet(const char* cmd); int CmdHF14AMfESet(const char* cmd); diff --git a/client/mifarehost.c b/client/mifarehost.c index 72c1e897..97e53f1e 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -203,6 +203,53 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t key *key = bytes_to_num(resp.d.asBytes, 6); return 0; } +// PM3 imp of J-Run mf_key_brute (part 2) +// ref: https://github.com/J-Run/mf_key_brute +int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey){ + + #define KEYS_IN_BLOCK 85 + #define KEYBLOCK_SIZE 510 + #define CANDIDATE_SIZE 0xFFFF * 6 + uint8_t found = FALSE; + uint64_t key64 = 0; + uint8_t candidates[CANDIDATE_SIZE] = {0x00}; + uint8_t keyBlock[KEYBLOCK_SIZE] = {0x00}; + + memset(candidates, 0, sizeof(candidates)); + memset(keyBlock, 0, sizeof(keyBlock)); + + // Generate all possible keys for the first two unknown bytes. + for (uint16_t i = 0; i < 0xFFFF; ++i) { + uint32_t j = i * 6; + candidates[0 + j] = i >> 8; + candidates[1 + j] = i; + candidates[2 + j] = key[2]; + candidates[3 + j] = key[3]; + candidates[4 + j] = key[4]; + candidates[5 + j] = key[5]; + } + uint32_t counter, i; + for ( i = 0, counter = 1; i < CANDIDATE_SIZE; i += KEYBLOCK_SIZE, ++counter){ + + key64 = 0; + + // copy candidatekeys to test key block + memcpy(keyBlock, candidates + i, KEYBLOCK_SIZE); + + // check a block of generated candidate keys. + if (!mfCheckKeys(blockNo, keyType, TRUE, KEYS_IN_BLOCK, keyBlock, &key64)) { + *resultkey = key64; + found = TRUE; + break; + } + + // progress + if ( counter % 20 == 0 ) + PrintAndLog("tried : %s.. \t %u keys", sprint_hex(candidates + i, 6), counter * KEYS_IN_BLOCK ); + } + return found; +} + // EMULATOR diff --git a/client/mifarehost.h b/client/mifarehost.h index 16c84264..1593c390 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -65,6 +65,7 @@ extern char logHexFileName[FILE_PATH_SIZE]; int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate); int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); +int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey); int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); -- 2.39.5