From 8cb28a21c6a5cc3bfcca4a2a1db2d3fdcca7f4f0 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 28 Nov 2019 00:48:39 +0200 Subject: [PATCH 01/22] add mfp default keys --- client/mifare/mifaredefault.c | 39 +++++++++++++++++++++++++++++++++++ client/mifare/mifaredefault.h | 3 +++ 2 files changed, 42 insertions(+) create mode 100644 client/mifare/mifaredefault.c diff --git a/client/mifare/mifaredefault.c b/client/mifare/mifaredefault.c new file mode 100644 index 000000000..9d3b77d4f --- /dev/null +++ b/client/mifare/mifaredefault.c @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2017 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Mifare default constants +//----------------------------------------------------------------------------- + +#include "mifaredefault.h" +#include "commonutil.h" // ARRAYLEN + +const char* g_mifare_plus_default_keys[] = { + "ffffffffffffffffffffffffffffffff", // default key + "00000000000000000000000000000000", + "a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7", // MAD key + "b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7", + "d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7", // NDEF key + "11111111111111111111111111111111", + "22222222222222222222222222222222", + "33333333333333333333333333333333", + "44444444444444444444444444444444", + "55555555555555555555555555555555", + "66666666666666666666666666666666", + "77777777777777777777777777777777", + "88888888888888888888888888888888", + "99999999999999999999999999999999", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "cccccccccccccccccccccccccccccccc", + "dddddddddddddddddddddddddddddddd", + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "000102030405060708090a0b0c0d0e0f", + "0102030405060708090a0b0c0d0e0f10", + "00010203040506070809101112131415", + "01020304050607080910111213141516" +}; +size_t g_mifare_plus_default_keys_len = ARRAYLEN(g_mifare_plus_default_keys); \ No newline at end of file diff --git a/client/mifare/mifaredefault.h b/client/mifare/mifaredefault.h index 7232510a0..fdccfe22b 100644 --- a/client/mifare/mifaredefault.h +++ b/client/mifare/mifaredefault.h @@ -44,4 +44,7 @@ static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; +extern const char* g_mifare_plus_default_keys[]; +extern size_t g_mifare_plus_default_keys_len; + #endif From 17a2379ddd8f2eb8b1564794daca157441859d67 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 28 Nov 2019 00:49:12 +0200 Subject: [PATCH 02/22] hf mfp check sketch --- client/Makefile | 1 + client/cmdhf14a.c | 23 ++++++++------- client/cmdhf14a.h | 2 +- client/cmdhfmf.c | 4 +-- client/cmdhfmfp.c | 62 +++++++++++++++++++++++++++++++---------- client/mifare/mifare4.c | 37 +++++++++++++----------- client/mifare/mifare4.h | 2 +- 7 files changed, 84 insertions(+), 47 deletions(-) diff --git a/client/Makefile b/client/Makefile index a6d987560..4babb528f 100644 --- a/client/Makefile +++ b/client/Makefile @@ -134,6 +134,7 @@ CORESRCS = uart_posix.c \ CMDSRCS = crapto1/crapto1.c \ crapto1/crypto1.c \ + mifare/mifaredefault.c \ mifare/mfkey.c \ tea.c \ fido/additional_ca.c \ diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 777b7d25c..9c1004439 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -551,30 +551,29 @@ int CmdHF14ASniff(const char *Cmd) { return PM3_SUCCESS; } -int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode) { static uint8_t responseNum = 0; uint16_t cmdc = 0; *dataoutlen = 0; if (activateField) { - responseNum = 1; PacketResponseNG resp; // Anticollision + SELECT card SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout."); return 1; } // check result if (resp.oldarg[0] == 0) { - PrintAndLogEx(ERR, "No card in field."); + if (!silentMode) PrintAndLogEx(ERR, "No card in field."); return 1; } if (resp.oldarg[0] != 1 && resp.oldarg[0] != 2) { - PrintAndLogEx(ERR, "Card not in iso14443-4. res=%" PRId64 ".", resp.oldarg[0]); + if (!silentMode) PrintAndLogEx(ERR, "Card not in iso14443-4. res=%" PRId64 ".", resp.oldarg[0]); return 1; } @@ -583,12 +582,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, 2); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout."); return 1; } if (resp.oldarg[0] == 0) { // ats_len - PrintAndLogEx(ERR, "Can't get ATS."); + if (!silentMode) PrintAndLogEx(ERR, "Can't get ATS."); return 1; } } @@ -610,7 +609,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav int iLen = resp.oldarg[0]; if (!iLen) { - PrintAndLogEx(ERR, "No card response."); + if (!silentMode) PrintAndLogEx(ERR, "No card response."); return 1; } @@ -619,12 +618,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav *dataoutlen = 0; if (maxdataoutlen && *dataoutlen > maxdataoutlen) { - PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); + if (!silentMode) PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); return 2; } if (recv[0] != data[0]) { - PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]); + if (!silentMode) PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]); return 2; } @@ -632,12 +631,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav // CRC Check if (iLen == -1) { - PrintAndLogEx(ERR, "ISO 14443A CRC error."); + if (!silentMode) PrintAndLogEx(ERR, "ISO 14443A CRC error."); return 3; } } else { - PrintAndLogEx(ERR, "Reply timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Reply timeout."); return 4; } diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index fcea5f5cf..f40ea46f0 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -30,6 +30,6 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search); const char *getTagInfo(uint8_t uid); int Hf14443_4aGetCardData(iso14a_card_select_t *card); int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); -int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); #endif diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 23b418599..ad6fe31b2 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -13,7 +13,7 @@ #include #include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer #include "fileutils.h" #include "cmdtrace.h" @@ -4211,7 +4211,7 @@ static int CmdHF14AMfAuth4(const char *Cmd) { return PM3_ESOFT; } - return MifareAuth4(NULL, keyn, key, true, false, true); + return MifareAuth4(NULL, keyn, key, true, false, true, true, false); } // https://www.nxp.com/docs/en/application-note/AN10787.pdf diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index c6af6305a..affd9dd6c 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -88,7 +88,7 @@ static int CmdHFMFPInfo(const char *cmd) { int datalen = 0; // https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161 uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; - int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen); + int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false); if (!res && datalen > 1 && data[0] == 0x09) { SLmode = 0; } @@ -105,7 +105,7 @@ static int CmdHFMFPInfo(const char *cmd) { DropField(); - return 0; + return PM3_SUCCESS; } static int CmdHFMFPWritePerso(const char *cmd) { @@ -169,7 +169,7 @@ static int CmdHFMFPWritePerso(const char *cmd) { } PrintAndLogEx(INFO, "Write OK."); - return 0; + return PM3_SUCCESS; } uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; @@ -245,7 +245,7 @@ static int CmdHFMFPInitPerso(const char *cmd) { PrintAndLogEx(INFO, "Done."); - return 0; + return PM3_SUCCESS; } static int CmdHFMFPCommitPerso(const char *cmd) { @@ -286,7 +286,7 @@ static int CmdHFMFPCommitPerso(const char *cmd) { } PrintAndLogEx(INFO, "Switch level OK."); - return 0; + return PM3_SUCCESS; } static int CmdHFMFPAuth(const char *cmd) { @@ -324,7 +324,7 @@ static int CmdHFMFPAuth(const char *cmd) { return 1; } - return MifareAuth4(NULL, keyn, key, true, false, verbose); + return MifareAuth4(NULL, keyn, key, true, false, true, verbose, false); } static int CmdHFMFPRdbl(const char *cmd) { @@ -392,7 +392,7 @@ static int CmdHFMFPRdbl(const char *cmd) { PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -491,7 +491,7 @@ static int CmdHFMFPRdsc(const char *cmd) { PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -532,7 +532,7 @@ static int CmdHFMFPRdsc(const char *cmd) { } DropField(); - return 0; + return PM3_SUCCESS; } static int CmdHFMFPWrbl(const char *cmd) { @@ -595,7 +595,7 @@ static int CmdHFMFPWrbl(const char *cmd) { PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -634,7 +634,40 @@ static int CmdHFMFPWrbl(const char *cmd) { DropField(); PrintAndLogEx(INFO, "Write OK."); - return 0; + return PM3_SUCCESS; +} + +static int CmdHFMFPChk() { + int res; + bool selectCard = true; + + uint8_t startSector = 0; + uint8_t endSector = 0; + uint8_t startKeyAB = 0; + uint8_t endKeyAB = 0; + + + uint8_t keyn[2] = {0}; + uint8_t key[16] = {0}; + // sector number from 0 + for (uint8_t sector = startSector; sector <= endSector; sector++) { + // 0-keyA 1-keyB + for(uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { + // main cycle with key check + for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { + uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + res = MifareAuth4(NULL, keyn, key, selectCard, true, false, false, true); + selectCard = false; + PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, key, g_mifare_plus_default_keys[i], res); + } + } + } + + DropField(); + + return PM3_SUCCESS; } static int CmdHFMFPMAD(const char *cmd) { @@ -728,7 +761,7 @@ static int CmdHFMFPMAD(const char *cmd) { } } - return 0; + return PM3_SUCCESS; } static int CmdHFMFPNDEF(const char *cmd) { @@ -832,7 +865,7 @@ static int CmdHFMFPNDEF(const char *cmd) { NDEFDecodeAndPrint(data, datalen, verbose); - return 0; + return PM3_SUCCESS; } static command_t CommandTable[] = { @@ -845,6 +878,7 @@ static command_t CommandTable[] = { {"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"}, {"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"}, {"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"}, + {"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"}, {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Checks and prints MAD"}, {"ndef", CmdHFMFPNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, {NULL, NULL, 0, NULL} @@ -853,7 +887,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdHFMFP(const char *Cmd) { diff --git a/client/mifare/mifare4.c b/client/mifare/mifare4.c index 5cdca2e14..7eecbe751 100644 --- a/client/mifare/mifare4.c +++ b/client/mifare/mifare4.c @@ -168,21 +168,24 @@ int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen); } -int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) { +int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode) { uint8_t data[257] = {0}; int datalen = 0; uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; uint8_t RndB[17] = {0}; + if (silentMode) + verbose = false; + if (session) session->Authenticated = false; uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; - int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen); + int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen, silentMode); if (res) { - PrintAndLogEx(ERR, "Exchande raw error: %d", res); - DropField(); + if (!silentMode) PrintAndLogEx(ERR, "Exchande raw error: %d", res); + if (dropFieldIfError) DropField(); return 2; } @@ -190,20 +193,20 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF PrintAndLogEx(INFO, "phase2: %s", sprint_hex(cmd2, 33)); - res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen); + res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen, silentMode); if (res) { - PrintAndLogEx(ERR, "Exchande raw error: %d", res); - DropField(); + if (!silentMode) PrintAndLogEx(ERR, "Exchande raw error: %d", res); + if (dropFieldIfError) DropField(); return 4; } @@ -241,12 +244,12 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF } if (memcmp(&raw[4], &RndA[1], 16)) { - PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd not equal"); + if (!silentMode) PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd is not equal"); if (verbose) { PrintAndLogEx(ERR, "RndA reader: %s", sprint_hex(&RndA[1], 16)); PrintAndLogEx(ERR, "RndA card: %s", sprint_hex(&raw[4], 16)); } - DropField(); + if (dropFieldIfError) DropField(); return 5; } @@ -311,7 +314,7 @@ static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateFi if (VerboseMode) PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen)); - int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen, false); if (VerboseMode) PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen)); @@ -380,7 +383,7 @@ int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum); mf4Session session; - int res = MifareAuth4(&session, keyn, key, true, true, verbose); + int res = MifareAuth4(&session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res); return res; diff --git a/client/mifare/mifare4.h b/client/mifare/mifare4.h index 31eac1fdb..fe07aceaf 100644 --- a/client/mifare/mifare4.h +++ b/client/mifare/mifare4.h @@ -45,7 +45,7 @@ void mfpSetVerboseMode(bool verbose); const char *mfpGetErrorDescription(uint8_t errorCode); int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose); -int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); +int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode); int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); From 133d59e4830eb700a216c9bf58f401ee925e4132 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 28 Nov 2019 14:16:53 +0200 Subject: [PATCH 03/22] added command parsing and result printing --- client/cmdhfmfp.c | 79 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index affd9dd6c..f5d122991 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -637,16 +637,47 @@ static int CmdHFMFPWrbl(const char *cmd) { return PM3_SUCCESS; } -static int CmdHFMFPChk() { +static int CmdHFMFPChk(const char *cmd) { int res; bool selectCard = true; + char* foundKeys[2][64] = {NULL}; - uint8_t startSector = 0; - uint8_t endSector = 0; + CLIParserInit("hf mfp check", + "Checks keys with Mifare Plus card.", + "Usage:\n\thf mfp check -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" + "\thf mfp check -s 2 -a -> check default key list \n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("aA", "keya", "check only key A (by default check all keys)."), + arg_lit0("bB", "keyb", "check only key B (by default check all keys)."), + arg_int0("sS", "startsec", "Start sector Num (0..255)", NULL), + arg_int0("eE", "endsec", "End sector Num (0..255)", NULL), + arg_str0("kK", "key", "", NULL), + arg_str0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool keyA = arg_get_lit(1); + bool keyB = arg_get_lit(2); + uint8_t startSector = arg_get_int_def(3, 0); + uint8_t endSector = arg_get_int_def(4, 0); + uint8_t vkey[16] = {0}; + int vkeylen = 0; + CLIGetHexWithReturn(5, vkey, &vkeylen); + CLIParserFree(); + uint8_t startKeyAB = 0; - uint8_t endKeyAB = 0; - + uint8_t endKeyAB = 1; + if (keyA && !keyB) + endKeyAB = 0; + if (!keyA && keyB) + startKeyAB = 1; + if (endSector < startSector) + endSector = startSector; + uint8_t keyn[2] = {0}; uint8_t key[16] = {0}; // sector number from 0 @@ -655,17 +686,53 @@ static int CmdHFMFPChk() { for(uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { // main cycle with key check for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { + int datalen = 0; + if (param_gethex_to_eol((char *)g_mifare_plus_default_keys[i], 0, (uint8_t *)key, 16, &datalen) > 0) + break; + if (datalen != 16) + break; + uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; keyn[0] = uKeyNum >> 8; keyn[1] = uKeyNum & 0xff; res = MifareAuth4(NULL, keyn, key, selectCard, true, false, false, true); + if (res == 0) { + PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(key, 16)); + foundKeys[keyAB][sector] = (char*)g_mifare_plus_default_keys[i]; + break; + } + + if (res != 5) + break; + selectCard = false; - PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, key, g_mifare_plus_default_keys[i], res); + PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(key, 16), res); } } } DropField(); + + // print result + bool printedHeader = false; + for (uint8_t sector = startSector; sector <= endSector; sector++) { + if (foundKeys[0][sector] != NULL || foundKeys[1][sector] != NULL) { + if (!printedHeader) { + PrintAndLogEx(INFO, ".------.--------------------------------.--------------------------------."); + PrintAndLogEx(INFO, "|sector| key A | key B |"); + PrintAndLogEx(INFO, "|------|--------------------------------|--------------------------------|"); + printedHeader = true; + } + PrintAndLogEx(INFO, "| %02d |%32s|%32s|", + sector, + (foundKeys[0][sector] == NULL) ? "----- " : foundKeys[0][sector], + (foundKeys[1][sector] == NULL) ? "----- " : foundKeys[1][sector]); + } + } + if (!printedHeader) + PrintAndLogEx(INFO, "No keys found("); + else + PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'"); return PM3_SUCCESS; } From 2c101ebbb9a2dd79afac5417bcc91a4152c84065 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 28 Nov 2019 15:16:11 +0200 Subject: [PATCH 04/22] internal keys search works --- client/cmdhfmfp.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index f5d122991..c3944e12d 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -25,6 +25,7 @@ #include "cliparser/cliparser.h" #include "emv/dump.h" #include "mifare/mifaredefault.h" +#include "util_posix.h" static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -645,7 +646,7 @@ static int CmdHFMFPChk(const char *cmd) { CLIParserInit("hf mfp check", "Checks keys with Mifare Plus card.", "Usage:\n\thf mfp check -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" - "\thf mfp check -s 2 -a -> check default key list \n"); + "\thf mfp check -s 2 -a -> check default key list on sector 2, key A\n"); void *argtable[] = { arg_param_begin, @@ -655,6 +656,8 @@ static int CmdHFMFPChk(const char *cmd) { arg_int0("eE", "endsec", "End sector Num (0..255)", NULL), arg_str0("kK", "key", "", NULL), arg_str0(NULL, NULL, "", NULL), + arg_lit0(NULL, "pattern1b", "check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), + arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -666,6 +669,8 @@ static int CmdHFMFPChk(const char *cmd) { uint8_t vkey[16] = {0}; int vkeylen = 0; CLIGetHexWithReturn(5, vkey, &vkeylen); + bool pattern1b = arg_get_lit(7); + bool pattern2b = arg_get_lit(8); CLIParserFree(); uint8_t startKeyAB = 0; @@ -695,10 +700,15 @@ static int CmdHFMFPChk(const char *cmd) { uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; keyn[0] = uKeyNum >> 8; keyn[1] = uKeyNum & 0xff; + res = MifareAuth4(NULL, keyn, key, selectCard, true, false, false, true); + PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(key, 16), res); if (res == 0) { PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(key, 16)); foundKeys[keyAB][sector] = (char*)g_mifare_plus_default_keys[i]; + DropField(); + selectCard = true; + msleep(50); break; } @@ -706,7 +716,6 @@ static int CmdHFMFPChk(const char *cmd) { break; selectCard = false; - PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(key, 16), res); } } } @@ -725,8 +734,8 @@ static int CmdHFMFPChk(const char *cmd) { } PrintAndLogEx(INFO, "| %02d |%32s|%32s|", sector, - (foundKeys[0][sector] == NULL) ? "----- " : foundKeys[0][sector], - (foundKeys[1][sector] == NULL) ? "----- " : foundKeys[1][sector]); + (foundKeys[0][sector] == NULL) ? "------ " : foundKeys[0][sector], + (foundKeys[1][sector] == NULL) ? "------ " : foundKeys[1][sector]); } } if (!printedHeader) From 9f8a8cce96a74f5fe24b788701fdc50de8078d74 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 28 Nov 2019 15:36:52 +0200 Subject: [PATCH 05/22] refactoring. move key list to uint8_t[16] array --- client/cmdhfmfp.c | 60 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index c3944e12d..b1a764cac 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -638,10 +638,15 @@ static int CmdHFMFPWrbl(const char *cmd) { return PM3_SUCCESS; } +#define AES_KEY_LEN 16 +#define MAX_KEYS_LIST_LEN 1024 + static int CmdHFMFPChk(const char *cmd) { int res; bool selectCard = true; - char* foundKeys[2][64] = {NULL}; + uint8_t keysList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; + size_t keysListLen = 0; + uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {0}; CLIParserInit("hf mfp check", "Checks keys with Mifare Plus card.", @@ -682,30 +687,49 @@ static int CmdHFMFPChk(const char *cmd) { if (endSector < startSector) endSector = startSector; + + if (pattern1b || pattern2b) { + for (int i = 0; i < 0x100; i++) + memset(keysList[i], i, 16); + + keysListLen = 0x100; + } + + if (keysListLen == 0) { + for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { + int datalen = 0; + if (param_gethex_to_eol(g_mifare_plus_default_keys[i], 0, keysList[keysListLen], 16, &datalen) > 0) + break; + if (datalen != 16) + break; + + keysListLen++; + } + } + + if (keysListLen == 0) { + PrintAndLogEx(ERROR, "Key list is empty. Nothing to check."); + return 1; + } + uint8_t keyn[2] = {0}; - uint8_t key[16] = {0}; // sector number from 0 for (uint8_t sector = startSector; sector <= endSector; sector++) { // 0-keyA 1-keyB for(uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { // main cycle with key check - for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { - int datalen = 0; - if (param_gethex_to_eol((char *)g_mifare_plus_default_keys[i], 0, (uint8_t *)key, 16, &datalen) > 0) - break; - if (datalen != 16) - break; - + for (int i = 0; i < keysListLen; i++) { uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; keyn[0] = uKeyNum >> 8; keyn[1] = uKeyNum & 0xff; - res = MifareAuth4(NULL, keyn, key, selectCard, true, false, false, true); - PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(key, 16), res); + res = MifareAuth4(NULL, keyn, keysList[i], selectCard, true, false, false, true); + PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keysList[i], 16), res); if (res == 0) { - PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(key, 16)); - foundKeys[keyAB][sector] = (char*)g_mifare_plus_default_keys[i]; + PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keysList[i], 16)); + foundKeys[keyAB][sector][0] = 0x01; + memcpy(&foundKeys[keyAB][sector][1], keysList[i], AES_KEY_LEN); DropField(); selectCard = true; msleep(50); @@ -725,23 +749,23 @@ static int CmdHFMFPChk(const char *cmd) { // print result bool printedHeader = false; for (uint8_t sector = startSector; sector <= endSector; sector++) { - if (foundKeys[0][sector] != NULL || foundKeys[1][sector] != NULL) { + if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) { if (!printedHeader) { - PrintAndLogEx(INFO, ".------.--------------------------------.--------------------------------."); + PrintAndLogEx(INFO, "\n.------.--------------------------------.--------------------------------."); PrintAndLogEx(INFO, "|sector| key A | key B |"); PrintAndLogEx(INFO, "|------|--------------------------------|--------------------------------|"); printedHeader = true; } PrintAndLogEx(INFO, "| %02d |%32s|%32s|", sector, - (foundKeys[0][sector] == NULL) ? "------ " : foundKeys[0][sector], - (foundKeys[1][sector] == NULL) ? "------ " : foundKeys[1][sector]); + (foundKeys[0][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[0][sector][1], AES_KEY_LEN), + (foundKeys[1][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[1][sector][1], AES_KEY_LEN)); } } if (!printedHeader) PrintAndLogEx(INFO, "No keys found("); else - PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'"); + PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'\n"); return PM3_SUCCESS; } From 385a747dbd7460749f3a73bdc3b8ea47c3a627f1 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 28 Nov 2019 16:24:39 +0200 Subject: [PATCH 06/22] added search 2-byte pattern --- client/cmdhfmfp.c | 50 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index b1a764cac..db8df3e29 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -644,8 +644,8 @@ static int CmdHFMFPWrbl(const char *cmd) { static int CmdHFMFPChk(const char *cmd) { int res; bool selectCard = true; - uint8_t keysList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; - size_t keysListLen = 0; + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; + size_t keyListLen = 0; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {0}; CLIParserInit("hf mfp check", @@ -663,6 +663,7 @@ static int CmdHFMFPChk(const char *cmd) { arg_str0(NULL, NULL, "", NULL), arg_lit0(NULL, "pattern1b", "check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), + arg_str0(NULL, "startp2b", " start pattern for 2-byte search key", NULL), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -676,6 +677,12 @@ static int CmdHFMFPChk(const char *cmd) { CLIGetHexWithReturn(5, vkey, &vkeylen); bool pattern1b = arg_get_lit(7); bool pattern2b = arg_get_lit(8); + uint16_t startPattern = 0x0000; + uint8_t vpattern[2]; + int vpatternlen = 0; + CLIGetHexWithReturn(9, vpattern, &vpatternlen); + if (vpatternlen > 0 && vpatternlen <= 2) + startPattern = (vpattern[0] << 8) + vpattern[1]; CLIParserFree(); uint8_t startKeyAB = 0; @@ -688,48 +695,61 @@ static int CmdHFMFPChk(const char *cmd) { if (endSector < startSector) endSector = startSector; - if (pattern1b || pattern2b) { + if (pattern1b) { for (int i = 0; i < 0x100; i++) - memset(keysList[i], i, 16); + memset(keyList[i], i, 16); - keysListLen = 0x100; + keyListLen = 0x100; + } + + if (pattern2b) { + for (uint32_t i = startPattern; i < 0x10000; i++) { + keyList[keyListLen][0] = (i >> 8) & 0xff; + keyList[keyListLen][1] = i & 0xff; + memcpy(&keyList[keyListLen][2], &keyList[keyListLen][0], 2); + memcpy(&keyList[keyListLen][4], &keyList[keyListLen][0], 4); + memcpy(&keyList[keyListLen][8], &keyList[keyListLen][0], 8); + keyListLen++; + if (keyListLen == MAX_KEYS_LIST_LEN) + break; + } + startPattern = (keyList[keyListLen - 1][0] << 8) + keyList[keyListLen - 1][1]; } - if (keysListLen == 0) { + if (keyListLen == 0) { for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { int datalen = 0; - if (param_gethex_to_eol(g_mifare_plus_default_keys[i], 0, keysList[keysListLen], 16, &datalen) > 0) + if (param_gethex_to_eol(g_mifare_plus_default_keys[i], 0, keyList[keyListLen], 16, &datalen) > 0) break; if (datalen != 16) break; - keysListLen++; + keyListLen++; } } - if (keysListLen == 0) { + if (keyListLen == 0) { PrintAndLogEx(ERROR, "Key list is empty. Nothing to check."); return 1; } - uint8_t keyn[2] = {0}; // sector number from 0 for (uint8_t sector = startSector; sector <= endSector; sector++) { // 0-keyA 1-keyB for(uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { // main cycle with key check - for (int i = 0; i < keysListLen; i++) { + for (int i = 0; i < keyListLen; i++) { uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; keyn[0] = uKeyNum >> 8; keyn[1] = uKeyNum & 0xff; - res = MifareAuth4(NULL, keyn, keysList[i], selectCard, true, false, false, true); - PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keysList[i], 16), res); + res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true); + PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); if (res == 0) { - PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keysList[i], 16)); + PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); foundKeys[keyAB][sector][0] = 0x01; - memcpy(&foundKeys[keyAB][sector][1], keysList[i], AES_KEY_LEN); + memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); DropField(); selectCard = true; msleep(50); From 1efc731fac29867e64686979cb35ae840851d428 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 29 Nov 2019 17:23:30 +0200 Subject: [PATCH 07/22] refactoring and break operation via keyboard --- client/cmdhfmfp.c | 103 +++++++++++++++++++++++++++++++--------------- include/pm3_cmd.h | 2 + 2 files changed, 71 insertions(+), 34 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index db8df3e29..6a64b01f5 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -641,9 +641,72 @@ static int CmdHFMFPWrbl(const char *cmd) { #define AES_KEY_LEN 16 #define MAX_KEYS_LIST_LEN 1024 -static int CmdHFMFPChk(const char *cmd) { + int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1]) { int res; bool selectCard = true; + uint8_t keyn[2] = {0}; + + // sector number from 0 + for (uint8_t sector = startSector; sector <= endSector; sector++) { + // 0-keyA 1-keyB + for(uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { + // main cycle with key check + for (int i = 0; i < keyListLen; i++) { + if (i % 10 == 0) { + if (kbd_enter_pressed()) { + PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); + DropField(); + return PM3_EOPABORTED; + } + } + + uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + + for (int retry = 0; retry < 4; retry++) { + res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true); + if (res != 2) + break; + + printf("retried[%d]...\n", retry); + + DropField(); + selectCard = true; + msleep(100); + } + + PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); + + // key for [sector,keyAB] found + if (res == 0) { + PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + foundKeys[keyAB][sector][0] = 0x01; + memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); + DropField(); + selectCard = true; + msleep(50); + break; + } + + // 5 - auth error (rnd not equal) + if (res != 5) { + DropField(); + return PM3_ECARDEXCHANGE; + } + + selectCard = false; + } + } + } + + DropField(); + return PM3_SUCCESS; +} + +static int CmdHFMFPChk(const char *cmd) { + int res; uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; size_t keyListLen = 0; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {0}; @@ -733,45 +796,17 @@ static int CmdHFMFPChk(const char *cmd) { return 1; } - uint8_t keyn[2] = {0}; - // sector number from 0 - for (uint8_t sector = startSector; sector <= endSector; sector++) { - // 0-keyA 1-keyB - for(uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { - // main cycle with key check - for (int i = 0; i < keyListLen; i++) { - uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; - keyn[0] = uKeyNum >> 8; - keyn[1] = uKeyNum & 0xff; - - res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true); - PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); - if (res == 0) { - PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); - foundKeys[keyAB][sector][0] = 0x01; - memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); - DropField(); - selectCard = true; - msleep(50); - break; - } - - if (res != 5) - break; - - selectCard = false; - } - } - } - - DropField(); + + res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys); + printf("--- res: %d\n", res); // print result bool printedHeader = false; for (uint8_t sector = startSector; sector <= endSector; sector++) { if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) { if (!printedHeader) { - PrintAndLogEx(INFO, "\n.------.--------------------------------.--------------------------------."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, ".------.--------------------------------.--------------------------------."); PrintAndLogEx(INFO, "|sector| key A | key B |"); PrintAndLogEx(INFO, "|------|--------------------------------|--------------------------------|"); printedHeader = true; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 892ec533f..e775b3413 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -590,6 +590,8 @@ typedef struct { #define PM3_EWRONGANSVER -16 // Memory out-of-bounds error client/pm3: error when a read/write is outside the expected array #define PM3_EOUTOFBOUND -17 +// exchange with card error client/pm3: error when cant get answer from card or got an incorrect answer +#define PM3_ECARDEXCHANGE -18 // No data pm3: no data available, no host frame available (not really an error) #define PM3_ENODATA -98 // Quit program client: reserved, order to quit the program From a861d2971cff72b8c0fd196bd62540c90186da9c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 29 Nov 2019 17:29:36 +0200 Subject: [PATCH 08/22] specify key in the command line --- client/cmdhfmfp.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 6a64b01f5..f3ad37405 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -735,17 +735,30 @@ static int CmdHFMFPChk(const char *cmd) { bool keyB = arg_get_lit(2); uint8_t startSector = arg_get_int_def(3, 0); uint8_t endSector = arg_get_int_def(4, 0); + uint8_t vkey[16] = {0}; int vkeylen = 0; CLIGetHexWithReturn(5, vkey, &vkeylen); + if (vkeylen > 0) { + if (vkeylen == 16) { + memcpy(&keyList[keyListLen], vkey, 16); + keyListLen++; + } else { + PrintAndLogEx(ERROR, "Specified key must have 16 bytes length."); + return PM3_EINVARG; + } + } + bool pattern1b = arg_get_lit(7); bool pattern2b = arg_get_lit(8); + uint16_t startPattern = 0x0000; uint8_t vpattern[2]; int vpatternlen = 0; CLIGetHexWithReturn(9, vpattern, &vpatternlen); if (vpatternlen > 0 && vpatternlen <= 2) startPattern = (vpattern[0] << 8) + vpattern[1]; + CLIParserFree(); uint8_t startKeyAB = 0; @@ -793,7 +806,7 @@ static int CmdHFMFPChk(const char *cmd) { if (keyListLen == 0) { PrintAndLogEx(ERROR, "Key list is empty. Nothing to check."); - return 1; + return PM3_EINVARG; } From 8e6f08835d81684c91c47a388b8769803d5fbd19 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 29 Nov 2019 17:34:54 +0200 Subject: [PATCH 09/22] added some error handling --- client/cmdhfmfp.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index f3ad37405..3d1f41b8f 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -751,13 +751,26 @@ static int CmdHFMFPChk(const char *cmd) { bool pattern1b = arg_get_lit(7); bool pattern2b = arg_get_lit(8); + + if (pattern1b && pattern2b) { + PrintAndLogEx(ERROR, "Pattern search mode must be 2-byte or 1-byte only."); + return PM3_EINVARG; + } uint16_t startPattern = 0x0000; uint8_t vpattern[2]; int vpatternlen = 0; CLIGetHexWithReturn(9, vpattern, &vpatternlen); - if (vpatternlen > 0 && vpatternlen <= 2) - startPattern = (vpattern[0] << 8) + vpattern[1]; + if (vpatternlen > 0) { + if (vpatternlen > 0 && vpatternlen <= 2) { + startPattern = (vpattern[0] << 8) + vpattern[1]; + } else { + PrintAndLogEx(ERROR, "Pattern must be 2-byte length."); + return PM3_EINVARG; + } + if (!pattern2b) + PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); + } CLIParserFree(); @@ -809,7 +822,6 @@ static int CmdHFMFPChk(const char *cmd) { return PM3_EINVARG; } - res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys); printf("--- res: %d\n", res); From 34e38c9dc5449fa2a20fbe020560c135e53a24c6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 30 Nov 2019 23:45:51 +0200 Subject: [PATCH 10/22] added json save mfp --- client/fileutils.c | 30 ++++++++++++++++++++++++++++++ client/fileutils.h | 1 + 2 files changed, 31 insertions(+) diff --git a/client/fileutils.c b/client/fileutils.c index ebdb662ca..092e0fb66 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -352,6 +352,36 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s case jsf15: case jsfLegic: case jsfT5555: + case jsfMfPlusKeys: + JsonSaveStr(root, "FileType", "mfp"); + + JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7); + JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1); + JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2); + uint8_t atslen = data[13]; + if (atslen > 0) + JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen); + + uint8_t vdata[2][64][16 + 1] = {0}; + memcpy(vdata, &data[14 + atslen], 2 * 64 * 17); + + for (size_t i = 0; i < datalen; i++) { + char path[PATH_MAX_LENGTH] = {0}; + + if (vdata[0][i][0]) { + memset(path, 0x00, sizeof(path)); + sprintf(path, "$.SectorKeys.%d.KeyA", mfSectorNum(i)); + JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], 16); + } + + if (vdata[1][i][0]) { + memset(path, 0x00, sizeof(path)); + sprintf(path, "$.SectorKeys.%d.KeyB", mfSectorNum(i)); + JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], 16); + } + + } + break; default: break; } diff --git a/client/fileutils.h b/client/fileutils.h index eb4b57c82..bfd418a2c 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -61,6 +61,7 @@ typedef enum { jsfLegic, jsfT55x7, jsfT5555, + jsfMfPlusKeys, } JSONFileType; typedef enum { From 0cb7637e1f9acc127c7ff46d419103a54f10d6a6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 30 Nov 2019 23:46:37 +0200 Subject: [PATCH 11/22] added save keys to json for mfp check --- client/cmdhf14a.h | 4 +- client/cmdhfmfp.c | 122 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 105 insertions(+), 21 deletions(-) diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index f40ea46f0..83fb2c69d 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh -// 2011, Merlok -// 2015,216,2017 iceman, marshmellow, piwi +// 2011,2019 Merlok +// 2015,2016,2017 iceman, marshmellow, piwi // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of // the license. diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 3d1f41b8f..6a7a7e411 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -26,6 +26,7 @@ #include "emv/dump.h" #include "mifare/mifaredefault.h" #include "util_posix.h" +#include "fileutils.h" static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -705,6 +706,21 @@ static int CmdHFMFPWrbl(const char *cmd) { return PM3_SUCCESS; } +void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t *keyListLen, uint32_t *startPattern) { + for (uint32_t pt = *startPattern; pt < 0x10000; pt++) { + keyList[*keyListLen][0] = (pt >> 8) & 0xff; + keyList[*keyListLen][1] = pt & 0xff; + memcpy(&keyList[*keyListLen][2], &keyList[*keyListLen][0], 2); + memcpy(&keyList[*keyListLen][4], &keyList[*keyListLen][0], 4); + memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8); + (*keyListLen)++; + *startPattern = pt; + if (*keyListLen == MAX_KEYS_LIST_LEN) + break; + } + (*startPattern)++; +} + static int CmdHFMFPChk(const char *cmd) { int res; uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; @@ -722,11 +738,12 @@ static int CmdHFMFPChk(const char *cmd) { arg_lit0("bB", "keyb", "check only key B (by default check all keys)."), arg_int0("sS", "startsec", "Start sector Num (0..255)", NULL), arg_int0("eE", "endsec", "End sector Num (0..255)", NULL), - arg_str0("kK", "key", "", NULL), - arg_str0(NULL, NULL, "", NULL), + arg_str0("kK", "key", "", "Key for checking (HEX 16 bytes)"), + arg_str0("dD", "dict", "", "file with keys dictionary"), arg_lit0(NULL, "pattern1b", "check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), - arg_str0(NULL, "startp2b", " start pattern for 2-byte search key", NULL), + arg_str0(NULL, "startp2b", "", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), + arg_str0("jJ", "json", "", "json file to save keys"), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -745,19 +762,47 @@ static int CmdHFMFPChk(const char *cmd) { keyListLen++; } else { PrintAndLogEx(ERROR, "Specified key must have 16 bytes length."); + CLIParserFree(); return PM3_EINVARG; } } + uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0}; + int dict_filenamelen = 0; + if (CLIParamStrToBuf(arg_get_str(6), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { + PrintAndLogEx(FAILED, "File name too long or invalid."); + CLIParserFree(); + return PM3_EINVARG; + } + +/* char *dict_path; + int res = searchFile(&dict_path, DICTIONARIES_SUBDIR, filename, ".dic", false); + if (res != PM3_SUCCESS) { + CLIParserFree(); + return PM3_EFILE; + } + f = fopen(dict_path, "r"); + if (!f) { + PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", dict_path); + free(dict_path); + CLIParserFree(); + return PM3_EFILE; + } + free(dict_path); + + + */ + bool pattern1b = arg_get_lit(7); bool pattern2b = arg_get_lit(8); if (pattern1b && pattern2b) { PrintAndLogEx(ERROR, "Pattern search mode must be 2-byte or 1-byte only."); + CLIParserFree(); return PM3_EINVARG; } - uint16_t startPattern = 0x0000; + uint32_t startPattern = 0x0000; uint8_t vpattern[2]; int vpatternlen = 0; CLIGetHexWithReturn(9, vpattern, &vpatternlen); @@ -766,12 +811,22 @@ static int CmdHFMFPChk(const char *cmd) { startPattern = (vpattern[0] << 8) + vpattern[1]; } else { PrintAndLogEx(ERROR, "Pattern must be 2-byte length."); + CLIParserFree(); return PM3_EINVARG; } if (!pattern2b) PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); } + uint8_t jsonname[250] = {0}; + int jsonnamelen = 0; + if (CLIParamStrToBuf(arg_get_str(10), jsonname, sizeof(jsonname), &jsonnamelen)) { + PrintAndLogEx(ERROR, "Invalid json name."); + CLIParserFree(); + return PM3_EINVARG; + } + jsonname[jsonnamelen] = 0; + CLIParserFree(); uint8_t startKeyAB = 0; @@ -791,19 +846,8 @@ static int CmdHFMFPChk(const char *cmd) { keyListLen = 0x100; } - if (pattern2b) { - for (uint32_t i = startPattern; i < 0x10000; i++) { - keyList[keyListLen][0] = (i >> 8) & 0xff; - keyList[keyListLen][1] = i & 0xff; - memcpy(&keyList[keyListLen][2], &keyList[keyListLen][0], 2); - memcpy(&keyList[keyListLen][4], &keyList[keyListLen][0], 4); - memcpy(&keyList[keyListLen][8], &keyList[keyListLen][0], 8); - keyListLen++; - if (keyListLen == MAX_KEYS_LIST_LEN) - break; - } - startPattern = (keyList[keyListLen - 1][0] << 8) + keyList[keyListLen - 1][1]; - } + if (pattern2b) + Fill2bPattern(keyList, &keyListLen, &startPattern); if (keyListLen == 0) { for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { @@ -822,8 +866,18 @@ static int CmdHFMFPChk(const char *cmd) { return PM3_EINVARG; } - res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys); - printf("--- res: %d\n", res); + while (true) { + res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys); + printf("--- res: %d\n", res); + if (res == PM3_EOPABORTED) + break; + if (pattern2b && startPattern < 0x10000) { + keyListLen = 0; + Fill2bPattern(keyList, &keyListLen, &startPattern); + continue; + } + break; + } // print result bool printedHeader = false; @@ -847,6 +901,36 @@ static int CmdHFMFPChk(const char *cmd) { else PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'\n"); + // save keys to json + if ((jsonnamelen > 0) && printedHeader) { + // Mifare Plus info + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + + uint8_t data[10 + 1 + 2 + 1 + 256 + 2 * 64 * (AES_KEY_LEN + 1)] = {0}; + uint8_t atslen = 0; + if (select_status == 1 || select_status == 2) { + memcpy(data, card.uid, card.uidlen); + data[10] = card.sak; + data[11] = card.atqa[1]; + data[12] = card.atqa[0]; + atslen = card.ats_len; + data[13] = atslen; + memcpy(&data[14], card.ats, atslen); + } + + // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1] + memcpy(&data[14 + atslen], foundKeys, 2 * 64 * (AES_KEY_LEN + 1)); + saveFileJSON((char *)jsonname, jsfMfPlusKeys, data, 64); + } + return PM3_SUCCESS; } From de52ebc3d54562c47ebc4baf37047bd781c16e72 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 00:30:35 +0200 Subject: [PATCH 12/22] 1dd 16 byte key for dictionaries --- client/fileutils.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/fileutils.c b/client/fileutils.c index 092e0fb66..1d3af28da 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -753,9 +753,10 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u // t5577 == 4bytes // mifare == 6 bytes + // mf plus == 16 bytes // iclass == 8 bytes // default to 6 bytes. - if (keylen != 4 && keylen != 6 && keylen != 8) { + if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) { keylen = 6; } @@ -820,9 +821,10 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key // t5577 == 4bytes // mifare == 6 bytes + // mf plus == 16 bytes // iclass == 8 bytes // default to 6 bytes. - if (keylen != 4 && keylen != 6 && keylen != 8) { + if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) { keylen = 6; } From a6a16cfd0ce62994f20e393ce088302aca3633d9 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 00:36:28 +0200 Subject: [PATCH 13/22] add dictionary search check hex --- client/fileutils.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/client/fileutils.c b/client/fileutils.c index 1d3af28da..83f3635a4 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -789,10 +789,17 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u if (line[0] == '#') continue; - if (!isxdigit(line[0])) { - PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen); - continue; + bool searchFail = false; + for (int i = 0; i < keylen; i++) { + if (!isxdigit(line[i])) { + PrintAndLogEx(FAILED, "file content error (pos %d). '%s' must include " _BLUE_("%2d") "HEX symbols", i + 1, line, keylen); + searchFail = true; + break; + } } + if (searchFail) + continue; + uint64_t key = strtoull(line, NULL, 16); @@ -880,10 +887,16 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key if (line[0] == '#') continue; - if (!isxdigit(line[0])) { - PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen); - continue; + bool searchFail = false; + for (int i = 0; i < keylen; i++) { + if (!isxdigit(line[i])) { + PrintAndLogEx(FAILED, "file content error (pos %d). '%s' must include " _BLUE_("%2d") "HEX symbols", i + 1, line, keylen); + searchFail = true; + break; + } } + if (searchFail) + continue; uint64_t key = strtoull(line, NULL, 16); From e88f4e4cd861fe30b06db994798d9cef8842824a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 01:22:05 +0200 Subject: [PATCH 14/22] added hex_to_bytes --- client/util.c | 41 +++++++++++++++++++++++++++++++++++++++++ client/util.h | 1 + 2 files changed, 42 insertions(+) diff --git a/client/util.c b/client/util.c index 58dce8eca..c65f281fe 100644 --- a/client/util.c +++ b/client/util.c @@ -394,6 +394,47 @@ void print_blocks(uint32_t *data, size_t len) { } } +int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen) { + char buf[3]; + int indx = 0; + int bytesValueLen = 0; + while (hexValue[indx]) { + if (hexValue[indx] == '\t' || hexValue[indx] == ' ') { + indx++; + continue; + } + + if (isxdigit(hexValue[indx])) { + buf[strlen(buf) + 1] = 0x00; + buf[strlen(buf)] = hexValue[indx]; + } else { + // if we have symbols other than spaces and hex + return -1; + } + + if (maxBytesValueLen && bytesValueLen >= maxBytesValueLen) { + // if we dont have space in buffer and have symbols to translate + return -2; + } + + if (strlen(buf) >= 2) { + uint32_t temp = 0; + sscanf(buf, "%x", &temp); + bytesValue[bytesValueLen] = (uint8_t)(temp & 0xff); + buf[0] = 0; + bytesValueLen++; + } + + indx++; + } + + if (strlen(buf) > 0) + //error when not completed hex bytes + return -3; + + return bytesValueLen; +} + // takes a number (uint64_t) and creates a binarray in dest. void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { while (len--) { diff --git a/client/util.h b/client/util.h index d549458c4..afa12811b 100644 --- a/client/util.h +++ b/client/util.h @@ -55,6 +55,7 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st void print_blocks(uint32_t *data, size_t len); +int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen); void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest); void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest); uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); From 1daf155b9c7618987178d2194bc9c46e29c440fc Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 10:45:02 +0200 Subject: [PATCH 15/22] added dictionary --- client/cmdhfmfp.c | 29 +++++++++++++++------ client/fileutils.c | 65 +++++++++++++++++++++++++--------------------- client/fileutils.h | 18 ++++++++++++- 3 files changed, 73 insertions(+), 39 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 6a7a7e411..f185d4456 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -723,6 +723,7 @@ void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t *keyL static int CmdHFMFPChk(const char *cmd) { int res; + FILE *dictionary_file = NULL; uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; size_t keyListLen = 0; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {0}; @@ -775,23 +776,20 @@ static int CmdHFMFPChk(const char *cmd) { return PM3_EINVARG; } -/* char *dict_path; - int res = searchFile(&dict_path, DICTIONARIES_SUBDIR, filename, ".dic", false); + char *dict_path; + res = searchFile(&dict_path, DICTIONARIES_SUBDIR, (char *)dict_filename, ".dic", false); if (res != PM3_SUCCESS) { CLIParserFree(); return PM3_EFILE; } - f = fopen(dict_path, "r"); - if (!f) { + dictionary_file = fopen(dict_path, "r"); + if (!dictionary_file) { PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", dict_path); free(dict_path); CLIParserFree(); return PM3_EFILE; } - free(dict_path); - - - */ + free(dict_path); bool pattern1b = arg_get_lit(7); bool pattern2b = arg_get_lit(8); @@ -801,6 +799,12 @@ static int CmdHFMFPChk(const char *cmd) { CLIParserFree(); return PM3_EINVARG; } + + if (dictionary_file && (pattern1b || pattern2b)) { + PrintAndLogEx(ERROR, "Pattern search mode and dictionary mode can't be used in one command."); + CLIParserFree(); + return PM3_EINVARG; + } uint32_t startPattern = 0x0000; uint8_t vpattern[2]; @@ -839,6 +843,7 @@ static int CmdHFMFPChk(const char *cmd) { if (endSector < startSector) endSector = startSector; + // 1-byte pattern search mode if (pattern1b) { for (int i = 0; i < 0x100; i++) memset(keyList[i], i, 16); @@ -846,8 +851,16 @@ static int CmdHFMFPChk(const char *cmd) { keyListLen = 0x100; } + // 2-byte pattern search mode if (pattern2b) Fill2bPattern(keyList, &keyListLen, &startPattern); + + // dictionary mode + if (dictionary_file) { + size_t endFilePosition = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), &keyListLen, 16, NULL, 0, &endFilePosition); + printf("---endFilePosition %d", endFilePosition); + } if (keyListLen == 0) { for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { diff --git a/client/fileutils.c b/client/fileutils.c index 83f3635a4..a69de8d96 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -745,12 +745,6 @@ out: } int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt) { - - if (data == NULL) return PM3_EINVARG; - char *path; - if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS) - return PM3_EFILE; - // t5577 == 4bytes // mifare == 6 bytes // mf plus == 16 bytes @@ -759,6 +753,20 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) { keylen = 6; } + + return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL); +} + +int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, + size_t startFilePosition, size_t *endFilePosition) { + if (endFilePosition) + *endFilePosition = 0; + if (data == NULL) return PM3_EINVARG; + uint16_t vkeycnt = 0; + + char *path; + if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS) + return PM3_EFILE; // double up since its chars keylen <<= 1; @@ -774,7 +782,10 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u retval = PM3_EFILE; goto out; } - + + if (startFilePosition) + fseek(f, startFilePosition, SEEK_SET); + // read file while (fgets(line, sizeof(line), f)) { @@ -789,30 +800,32 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u if (line[0] == '#') continue; - bool searchFail = false; - for (int i = 0; i < keylen; i++) { - if (!isxdigit(line[i])) { - PrintAndLogEx(FAILED, "file content error (pos %d). '%s' must include " _BLUE_("%2d") "HEX symbols", i + 1, line, keylen); - searchFail = true; - break; - } - } - if (searchFail) + if (CheckStringIsHEXValue(line)) continue; + // cant store more data + if (maxdatalen && (counter + keylen > maxdatalen)) { + retval = 1; + int pos = ftell(f) - strlen(line) - 2; // 2 - `\r\n` + if (endFilePosition && (pos > 0)) + *endFilePosition = pos; + break; + } - uint64_t key = strtoull(line, NULL, 16); - - num_to_bytes(key, keylen >> 1, data + counter); - (*keycnt)++; + if (hex_to_bytes(line, data + counter, keylen >> 1) != (keylen >> 1)) + continue; + + vkeycnt++; memset(line, 0, sizeof(line)); counter += (keylen >> 1); } fclose(f); - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), *keycnt, path); + PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path); if (datalen) *datalen = counter; + if (keycnt) + *keycnt = vkeycnt; out: free(path); return retval; @@ -887,15 +900,7 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key if (line[0] == '#') continue; - bool searchFail = false; - for (int i = 0; i < keylen; i++) { - if (!isxdigit(line[i])) { - PrintAndLogEx(FAILED, "file content error (pos %d). '%s' must include " _BLUE_("%2d") "HEX symbols", i + 1, line, keylen); - searchFail = true; - break; - } - } - if (searchFail) + if (CheckStringIsHEXValue(line)) continue; uint64_t key = strtoull(line, NULL, 16); diff --git a/client/fileutils.h b/client/fileutils.h index bfd418a2c..58d05d366 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -176,13 +176,29 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ * * @param preferredName * @param data The data array to store the loaded bytes from file - * @param maxdatalen maximum size of data array in bytes * @param datalen the number of bytes loaded from file * @param keylen the number of bytes a key per row is * @return 0 for ok, 1 for failz */ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt); +/** + * @brief Utility function to load data from a DICTIONARY textfile. This method takes a preferred name. + * E.g. mfc_default_keys.dic + * can be executed several times for big dictionaries and checks length of buffer + * + * @param preferredName + * @param data The data array to store the loaded bytes from file + * @param maxdatalen maximum size of data array in bytes + * @param datalen the number of bytes loaded from file + * @param keylen the number of bytes a key per row is + * @param startFilePosition + * @param endFilePosition + * @return 0 for ok, 1 for failz +*/ +int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, + size_t startFilePosition, size_t *endFilePosition); + /** * @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name. * E.g. mfc_default_keys.dic From ca462424d0773ef0c3551ab0461b03cdc5d41b2b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 10:56:41 +0200 Subject: [PATCH 16/22] refactoring --- client/cmdhfmfp.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index f185d4456..80419fa40 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -723,7 +723,6 @@ void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t *keyL static int CmdHFMFPChk(const char *cmd) { int res; - FILE *dictionary_file = NULL; uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; size_t keyListLen = 0; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {0}; @@ -775,21 +774,6 @@ static int CmdHFMFPChk(const char *cmd) { CLIParserFree(); return PM3_EINVARG; } - - char *dict_path; - res = searchFile(&dict_path, DICTIONARIES_SUBDIR, (char *)dict_filename, ".dic", false); - if (res != PM3_SUCCESS) { - CLIParserFree(); - return PM3_EFILE; - } - dictionary_file = fopen(dict_path, "r"); - if (!dictionary_file) { - PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", dict_path); - free(dict_path); - CLIParserFree(); - return PM3_EFILE; - } - free(dict_path); bool pattern1b = arg_get_lit(7); bool pattern2b = arg_get_lit(8); @@ -800,7 +784,7 @@ static int CmdHFMFPChk(const char *cmd) { return PM3_EINVARG; } - if (dictionary_file && (pattern1b || pattern2b)) { + if (dict_filenamelen && (pattern1b || pattern2b)) { PrintAndLogEx(ERROR, "Pattern search mode and dictionary mode can't be used in one command."); CLIParserFree(); return PM3_EINVARG; @@ -856,7 +840,7 @@ static int CmdHFMFPChk(const char *cmd) { Fill2bPattern(keyList, &keyListLen, &startPattern); // dictionary mode - if (dictionary_file) { + if (dict_filenamelen) { size_t endFilePosition = 0; res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), &keyListLen, 16, NULL, 0, &endFilePosition); printf("---endFilePosition %d", endFilePosition); @@ -864,10 +848,7 @@ static int CmdHFMFPChk(const char *cmd) { if (keyListLen == 0) { for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { - int datalen = 0; - if (param_gethex_to_eol(g_mifare_plus_default_keys[i], 0, keyList[keyListLen], 16, &datalen) > 0) - break; - if (datalen != 16) + if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16) break; keyListLen++; From 131730e7dbdc5adfba4bf1ae78e90b47509156e1 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 11:01:56 +0200 Subject: [PATCH 17/22] fix docstrings --- client/fileutils.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/fileutils.h b/client/fileutils.h index 58d05d366..612c9fee6 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -176,8 +176,9 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ * * @param preferredName * @param data The data array to store the loaded bytes from file - * @param datalen the number of bytes loaded from file + * @param datalen the number of bytes loaded from file. may be NULL * @param keylen the number of bytes a key per row is + * @param keycnt key count that lays in data. may be NULL * @return 0 for ok, 1 for failz */ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt); @@ -190,10 +191,11 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u * @param preferredName * @param data The data array to store the loaded bytes from file * @param maxdatalen maximum size of data array in bytes - * @param datalen the number of bytes loaded from file + * @param datalen the number of bytes loaded from file. may be NULL * @param keylen the number of bytes a key per row is - * @param startFilePosition - * @param endFilePosition + * @param keycnt key count that lays in data. may be NULL + * @param startFilePosition start position in dictionary file. used for big dictionaries. + * @param endFilePosition in case we have keys in file and maxdatalen reached it returns current key position in file. may be NULL * @return 0 for ok, 1 for failz */ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, From 94eb741a4fa8780bef14b4c9e7fa7027bf307b74 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 22:33:50 +0200 Subject: [PATCH 18/22] refactoring + make dictionary works --- client/cmdhfmfp.c | 8 ++++++-- client/fileutils.c | 12 ++++++------ client/util.c | 5 ++--- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 80419fa40..541847897 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -842,8 +842,10 @@ static int CmdHFMFPChk(const char *cmd) { // dictionary mode if (dict_filenamelen) { size_t endFilePosition = 0; - res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), &keyListLen, 16, NULL, 0, &endFilePosition); - printf("---endFilePosition %d", endFilePosition); + uint16_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition); + keyListLen = keycnt; + printf("---endFilePosition %d\n", endFilePosition); } if (keyListLen == 0) { @@ -870,6 +872,8 @@ static int CmdHFMFPChk(const char *cmd) { Fill2bPattern(keyList, &keyListLen, &startPattern); continue; } + if (dict_filenamelen) { + } break; } diff --git a/client/fileutils.c b/client/fileutils.c index a69de8d96..ebe29f0bd 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -785,10 +785,10 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale if (startFilePosition) fseek(f, startFilePosition, SEEK_SET); - + // read file - while (fgets(line, sizeof(line), f)) { - + while (!feof(f) && fgets(line, sizeof(line), f)) { + // add null terminator line[keylen] = 0; @@ -800,7 +800,7 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale if (line[0] == '#') continue; - if (CheckStringIsHEXValue(line)) + if (!CheckStringIsHEXValue(line)) continue; // cant store more data @@ -811,10 +811,10 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale *endFilePosition = pos; break; } - + if (hex_to_bytes(line, data + counter, keylen >> 1) != (keylen >> 1)) continue; - + vkeycnt++; memset(line, 0, sizeof(line)); counter += (keylen >> 1); diff --git a/client/util.c b/client/util.c index c65f281fe..887f52857 100644 --- a/client/util.c +++ b/client/util.c @@ -395,7 +395,7 @@ void print_blocks(uint32_t *data, size_t len) { } int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen) { - char buf[3]; + char buf[4] = {0}; int indx = 0; int bytesValueLen = 0; while (hexValue[indx]) { @@ -405,7 +405,6 @@ int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValue } if (isxdigit(hexValue[indx])) { - buf[strlen(buf) + 1] = 0x00; buf[strlen(buf)] = hexValue[indx]; } else { // if we have symbols other than spaces and hex @@ -421,7 +420,7 @@ int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValue uint32_t temp = 0; sscanf(buf, "%x", &temp); bytesValue[bytesValueLen] = (uint8_t)(temp & 0xff); - buf[0] = 0; + memset(buf, 0, sizeof(buf)); bytesValueLen++; } From 2dfbe151b9e6511d627c895107308f7612f5f9bc Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 23:21:00 +0200 Subject: [PATCH 19/22] hf mfp check: dictionary works, verbose mode works --- client/cmdhfmfp.c | 49 +++++++++++++++++++----- client/dictionaries/mfp_default_keys.dic | 27 +++++++++++++ client/fileutils.c | 22 +++++++---- client/fileutils.h | 3 +- 4 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 client/dictionaries/mfp_default_keys.dic diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 541847897..a616fcc00 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -643,7 +643,8 @@ static int CmdHFMFPWrbl(const char *cmd) { #define MAX_KEYS_LIST_LEN 1024 int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, - uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1]) { + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], + bool verbose) { int res; bool selectCard = true; uint8_t keyn[2] = {0}; @@ -655,6 +656,8 @@ static int CmdHFMFPWrbl(const char *cmd) { // main cycle with key check for (int i = 0; i < keyListLen; i++) { if (i % 10 == 0) { + if (!verbose) + printf("."); if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); DropField(); @@ -671,18 +674,25 @@ static int CmdHFMFPWrbl(const char *cmd) { if (res != 2) break; - printf("retried[%d]...\n", retry); + if (verbose) + PrintAndLogEx(WARNING, "retried[%d]...", retry); + else + printf("R"); DropField(); selectCard = true; msleep(100); } - PrintAndLogEx(WARNING, "sector %d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); + if (verbose) + PrintAndLogEx(WARNING, "sector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); // key for [sector,keyAB] found if (res == 0) { - PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + if (verbose) + PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + else + printf("+"); foundKeys[keyAB][sector][0] = 0x01; memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); DropField(); @@ -693,6 +703,10 @@ static int CmdHFMFPWrbl(const char *cmd) { // 5 - auth error (rnd not equal) if (res != 5) { + if (verbose) + PrintAndLogEx(ERR, "Exchange error. Aborted."); + else + printf("E"); DropField(); return PM3_ECARDEXCHANGE; } @@ -744,6 +758,7 @@ static int CmdHFMFPChk(const char *cmd) { arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), arg_str0(NULL, "startp2b", "", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), arg_str0("jJ", "json", "", "json file to save keys"), + arg_lit0("vV", "verbose", "verbose mode."), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -815,6 +830,8 @@ static int CmdHFMFPChk(const char *cmd) { } jsonname[jsonnamelen] = 0; + bool verbose = arg_get_lit(11); + CLIParserFree(); uint8_t startKeyAB = 0; @@ -840,12 +857,13 @@ static int CmdHFMFPChk(const char *cmd) { Fill2bPattern(keyList, &keyListLen, &startPattern); // dictionary mode + size_t endFilePosition = 0; if (dict_filenamelen) { - size_t endFilePosition = 0; uint16_t keycnt = 0; - res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition); + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition, true); keyListLen = keycnt; - printf("---endFilePosition %d\n", endFilePosition); + if (endFilePosition) + PrintAndLogEx(SUCCESS, "First part of dictionary successfully loaded."); } if (keyListLen == 0) { @@ -862,20 +880,31 @@ static int CmdHFMFPChk(const char *cmd) { return PM3_EINVARG; } + if (!verbose) + printf("Search keys:"); while (true) { - res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys); - printf("--- res: %d\n", res); + res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); if (res == PM3_EOPABORTED) break; if (pattern2b && startPattern < 0x10000) { + if (!verbose) + printf("p"); keyListLen = 0; Fill2bPattern(keyList, &keyListLen, &startPattern); continue; } - if (dict_filenamelen) { + if (dict_filenamelen && endFilePosition) { + if (!verbose) + printf("d"); + uint16_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); + keyListLen = keycnt; + continue; } break; } + if (!verbose) + printf("\n"); // print result bool printedHeader = false; diff --git a/client/dictionaries/mfp_default_keys.dic b/client/dictionaries/mfp_default_keys.dic new file mode 100644 index 000000000..0f20b69bf --- /dev/null +++ b/client/dictionaries/mfp_default_keys.dic @@ -0,0 +1,27 @@ +ffffffffffffffffffffffffffffffff +00000000000000000000000000000000 +a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7 +b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7 +d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 +11111111111111111111111111111111 +22222222222222222222222222222222 +33333333333333333333333333333333 +44444444444444444444444444444444 +55555555555555555555555555555555 +66666666666666666666666666666666 +77777777777777777777777777777777 +88888888888888888888888888888888 +99999999999999999999999999999999 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +cccccccccccccccccccccccccccccccc +dddddddddddddddddddddddddddddddd +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +000102030405060708090a0b0c0d0e0f +0102030405060708090a0b0c0d0e0f10 +00010203040506070809101112131415 +01020304050607080910111213141516 +16151413121110090807060504030201 +15141312111009080706050403020100 +0f0e0d0c0b0a09080706050403020100 +100f0e0d0c0b0a090807060504030201 diff --git a/client/fileutils.c b/client/fileutils.c index ebe29f0bd..624c0259d 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -754,11 +754,11 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u keylen = 6; } - return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL); + return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL, true); } int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, - size_t startFilePosition, size_t *endFilePosition) { + size_t startFilePosition, size_t *endFilePosition, bool verbose) { if (endFilePosition) *endFilePosition = 0; if (data == NULL) return PM3_EINVARG; @@ -787,7 +787,13 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale fseek(f, startFilePosition, SEEK_SET); // read file - while (!feof(f) && fgets(line, sizeof(line), f)) { + while (!feof(f)) { + size_t filepos = ftell(f); + if (!fgets(line, sizeof(line), f)) { + if (endFilePosition) + *endFilePosition = 0; + break; + } // add null terminator line[keylen] = 0; @@ -804,11 +810,10 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale continue; // cant store more data - if (maxdatalen && (counter + keylen > maxdatalen)) { + if (maxdatalen && (counter + (keylen >> 1) > maxdatalen)) { retval = 1; - int pos = ftell(f) - strlen(line) - 2; // 2 - `\r\n` - if (endFilePosition && (pos > 0)) - *endFilePosition = pos; + if (endFilePosition) + *endFilePosition = filepos; break; } @@ -820,7 +825,8 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale counter += (keylen >> 1); } fclose(f); - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path); + if (verbose) + PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path); if (datalen) *datalen = counter; diff --git a/client/fileutils.h b/client/fileutils.h index 612c9fee6..c9de3b4fb 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -196,10 +196,11 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u * @param keycnt key count that lays in data. may be NULL * @param startFilePosition start position in dictionary file. used for big dictionaries. * @param endFilePosition in case we have keys in file and maxdatalen reached it returns current key position in file. may be NULL + * @param verbose print messages if true * @return 0 for ok, 1 for failz */ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, - size_t startFilePosition, size_t *endFilePosition); + size_t startFilePosition, size_t *endFilePosition, bool verbose); /** * @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name. From bc27b0e910790be0ffe78f36200c3c1a1bf820b7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 23:36:34 +0200 Subject: [PATCH 20/22] add some help --- client/cmdhfmfp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index a616fcc00..9187c5ce7 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -741,10 +741,14 @@ static int CmdHFMFPChk(const char *cmd) { size_t keyListLen = 0; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {0}; - CLIParserInit("hf mfp check", + CLIParserInit("hf mfp chk", "Checks keys with Mifare Plus card.", - "Usage:\n\thf mfp check -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" - "\thf mfp check -s 2 -a -> check default key list on sector 2, key A\n"); + "Usage:\n" + " hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" + " hf mfp chk -s 2 -a -> check default key list on sector 2, key A\n" + " hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n" + " hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n" + " hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00\n"); void *argtable[] = { arg_param_begin, From 256782402eaf3792a0592de167804a090f69d348 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 23:39:41 +0200 Subject: [PATCH 21/22] fix linux make errors --- client/cmdhfmfp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 9187c5ce7..3081f77f4 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -780,7 +780,7 @@ static int CmdHFMFPChk(const char *cmd) { memcpy(&keyList[keyListLen], vkey, 16); keyListLen++; } else { - PrintAndLogEx(ERROR, "Specified key must have 16 bytes length."); + PrintAndLogEx(ERR, "Specified key must have 16 bytes length."); CLIParserFree(); return PM3_EINVARG; } @@ -798,13 +798,13 @@ static int CmdHFMFPChk(const char *cmd) { bool pattern2b = arg_get_lit(8); if (pattern1b && pattern2b) { - PrintAndLogEx(ERROR, "Pattern search mode must be 2-byte or 1-byte only."); + PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only."); CLIParserFree(); return PM3_EINVARG; } if (dict_filenamelen && (pattern1b || pattern2b)) { - PrintAndLogEx(ERROR, "Pattern search mode and dictionary mode can't be used in one command."); + PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command."); CLIParserFree(); return PM3_EINVARG; } @@ -817,7 +817,7 @@ static int CmdHFMFPChk(const char *cmd) { if (vpatternlen > 0 && vpatternlen <= 2) { startPattern = (vpattern[0] << 8) + vpattern[1]; } else { - PrintAndLogEx(ERROR, "Pattern must be 2-byte length."); + PrintAndLogEx(ERR, "Pattern must be 2-byte length."); CLIParserFree(); return PM3_EINVARG; } @@ -828,7 +828,7 @@ static int CmdHFMFPChk(const char *cmd) { uint8_t jsonname[250] = {0}; int jsonnamelen = 0; if (CLIParamStrToBuf(arg_get_str(10), jsonname, sizeof(jsonname), &jsonnamelen)) { - PrintAndLogEx(ERROR, "Invalid json name."); + PrintAndLogEx(ERR, "Invalid json name."); CLIParserFree(); return PM3_EINVARG; } @@ -880,7 +880,7 @@ static int CmdHFMFPChk(const char *cmd) { } if (keyListLen == 0) { - PrintAndLogEx(ERROR, "Key list is empty. Nothing to check."); + PrintAndLogEx(ERR, "Key list is empty. Nothing to check."); return PM3_EINVARG; } From 8132de9b4fe29b97020eb72b7f3cf6cef73aa32c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sun, 1 Dec 2019 23:43:47 +0200 Subject: [PATCH 22/22] fix braces --- client/cmdhfmfp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 3081f77f4..2c0fc56eb 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -737,9 +737,9 @@ void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t *keyL static int CmdHFMFPChk(const char *cmd) { int res; - uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {0}; + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; size_t keyListLen = 0; - uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {0}; + uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; CLIParserInit("hf mfp chk", "Checks keys with Mifare Plus card.",