diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index f5ef352b1..2c22e1451 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -136,25 +136,6 @@ static int usage_hf14_autopwn(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn k 0 A FFFFFFFFFFFF * 1 f mfc_default_keys")" -- this command combines the two above (reduce the need for nested / hardnested attacks, by using a dictionary)"); return PM3_SUCCESS; } -static int usage_hf14_chk(void) { - PrintAndLogEx(NORMAL, "Usage: hf mf chk [h] |<*card memory> [t|d] [] []"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " * all sectors based on card memory, other values then below defaults to 1k"); - PrintAndLogEx(NORMAL, " 0 - MINI(320 bytes)"); - PrintAndLogEx(NORMAL, " 1 - 1K"); - PrintAndLogEx(NORMAL, " 2 - 2K"); - PrintAndLogEx(NORMAL, " 4 - 4K"); - PrintAndLogEx(NORMAL, " d write keys to binary file"); - PrintAndLogEx(NORMAL, " t write keys to emulator memory\n"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk 0 A 1234567890ab")" -- target block 0, Key A using key 1234567890ab"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk 0 A mfc_default_keys.dic")" -- target block 0, Key A using default dictionary file"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk *1 ? t")" -- target all blocks, all keys, 1K, write to emulator memory"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk *1 ? d")" -- target all blocks, all keys, 1K, write to file"); - return PM3_SUCCESS; -} static int usage_hf14_chk_fast(void) { PrintAndLogEx(NORMAL, "This is a improved checkkeys method speedwise. It checks MIFARE Classic tags sector keys against a dictionary file with keys"); PrintAndLogEx(NORMAL, "Usage: hf mf fchk [h] [t|d|f] [] []"); @@ -3000,55 +2981,95 @@ out: } static int CmdHF14AMfChk(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mf chk", + "Check keys on MIFARE Classic card", + "hf mf chk -* --mini --all -k FFFFFFFFFFFF --> Key recovery against MIFARE Mini\n" + "hf mf chk -* --1k --all -k FFFFFFFFFFFF --> Key recovery against MIFARE Classic 1k\n" + "hf mf chk -* --2k --all -k FFFFFFFFFFFF --> Key recovery against MIFARE 2k\n" + "hf mf chk -* --4k --all -k FFFFFFFFFFFF --> Key recovery against MIFARE 4k\n" + "hf mf chk -* --1k --all --emu --> Check all sectors, all keys, 1K, and write to emulator memory\n" + "hf mf chk -* --1k --all --dump --> Check all sectors, all keys, 1K, and write to file\n" + "hf mf chk -a --blk 0 -f mfc_default_keys.dic --> Check dictionary against block 0 key A"); - char ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 3 || ctmp == 'h') return usage_hf14_chk(); + void *argtable[] = { + arg_param_begin, + arg_strx0("k", "key", "", "Key specified as 12 hex symbols"), + arg_int0(NULL, "blk", "", "Input block number"), + arg_lit0("*", NULL, "Target all blocks"), + arg_lit0("a", NULL, "Input key specified is A key (default)"), + arg_lit0("b", NULL, "Input key specified is B key"), + arg_lit0(NULL, "all", "Target all keys"), + arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"), + arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50"), + 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 file"), + arg_str0("f", "file", "", "filename of dictionary"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - FILE *f; - char filename[FILE_PATH_SIZE] = {0}; - char buf[13]; - uint8_t *keyBlock, *p; - sector_t *e_sector = NULL; + int keylen = 0; + uint8_t key[255 * 6] = {0}; + CLIGetHexWithReturn(ctx, 1, key, &keylen); + + uint8_t blockNo = arg_get_u32_def(ctx, 2, 0); + + bool allBlocks = arg_get_lit(ctx, 3); - uint8_t blockNo = 0; - uint8_t SectorsCnt = 1; uint8_t keyType = 0; - uint32_t keyitems = ARRAYLEN(g_mifare_default_keys); - uint64_t key64 = 0; - int clen = 0; - int transferToEml = 0; - int createDumpFile = 0; - int i, keycnt = 0; - if (param_getchar(Cmd, 0) == '*') { - blockNo = 3; - SectorsCnt = NumOfSectors(param_getchar(Cmd + 1, 0)); + if ((arg_get_lit(ctx, 4) && arg_get_lit(ctx, 5)) || arg_get_lit(ctx, 6)) { + keyType = 2; + } else if (arg_get_lit(ctx, 5)) { + keyType = 1; + } + bool m0 = arg_get_lit(ctx, 7); + bool m1 = arg_get_lit(ctx, 8); + bool m2 = arg_get_lit(ctx, 9); + bool m4 = arg_get_lit(ctx, 10); + + bool transferToEml = arg_get_lit(ctx, 11); + bool createDumpFile = arg_get_lit(ctx, 12); + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 13), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + CLIParserFree(ctx); + + //validations + + if ((m0 + m1 + m2 + m4) > 1) { + PrintAndLogEx(WARNING, "Only specify one MIFARE Type"); + return PM3_EINVARG; + } + + uint8_t SectorsCnt = 1; + 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; + } + + if (allBlocks) { if (SectorsCnt == 0) { - return usage_hf14_chk(); + PrintAndLogEx(WARNING, "Invalid MIFARE Type"); + return PM3_EINVARG; } - } else { - blockNo = param_get8(Cmd, 0); - } - - ctmp = tolower(param_getchar(Cmd, 1)); - clen = param_getlength(Cmd, 1); - if (clen == 1) { - switch (ctmp) { - case 'a': - keyType = 0; - break; - case 'b': - keyType = 1; - break; - case '?': - keyType = 2; - break; - default: - PrintAndLogEx(FAILED, "Key type must be A , B or ?"); - return PM3_ESOFT; - }; + blockNo = 3; } + // Handle Keys + int keycnt = 0; + uint32_t keyitems = ARRAYLEN(g_mifare_default_keys); + uint8_t *keyBlock, *p; // Allocate memory for keys to be tested keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6); if (keyBlock == NULL) return PM3_EMALLOC; @@ -3057,93 +3078,90 @@ static int CmdHF14AMfChk(const char *Cmd) { for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6)); - for (i = 2; param_getchar(Cmd, i); i++) { + // Handle user supplied key + if (keylen > 6) { + // if (keylen != 6) { + // PrintAndLogEx(WARNING, "Input key must include 12 HEX symbols"); + // return PM3_EINVARG; + // } + int numKeys = keylen / 6; - ctmp = tolower(param_getchar(Cmd, i)); - clen = param_getlength(Cmd, i); + + + p = realloc(keyBlock, 6 * (keyitems + numKeys)); + if (!p) { + PrintAndLogEx(FAILED, "cannot allocate memory for Keys"); + free(keyBlock); + return PM3_EMALLOC; + } + keyBlock = p; + + memcpy(keyBlock + 6 * keycnt, key, 6 * numKeys); + + for (int i = 0; i < numKeys; i++) { + PrintAndLogEx(NORMAL, "[%2d] key %s", keycnt, sprint_hex((keyBlock + 6 * keycnt), 6)); + keycnt++; + } - if (clen == 12) { + } - if (param_gethex(Cmd, i, keyBlock + 6 * keycnt, 12)) { - PrintAndLogEx(FAILED, "not hex, skipping"); + // Handle user supplied dictionary file + FILE *f; + char buf[13]; + if (fnlen > 0) { + char *dict_path; + int res = searchFile(&dict_path, DICTIONARIES_SUBDIR, filename, ".dic", false); + if (res != PM3_SUCCESS) { + free(keyBlock); + return PM3_EFILE; + } + f = fopen(dict_path, "r"); + if (!f) { + PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", dict_path); + free(dict_path); + free(keyBlock); + return PM3_EFILE; + } + free(dict_path); + // load keys from dictionary file + while (fgets(buf, sizeof(buf), f)) { + if (strlen(buf) < 12 || buf[11] == '\n') + continue; + + while (fgetc(f) != '\n' && !feof(f)) ; //goto next line + + if (buf[0] == '#') continue; //The line start with # is comment, skip + + // codesmell, only checks first char? + if (!isxdigit(buf[0])) { + PrintAndLogEx(FAILED, "File content error. '" _YELLOW_("%s")"' must include 12 HEX symbols", buf); continue; } + buf[12] = 0; + if (keyitems - keycnt < 2) { p = realloc(keyBlock, 6 * (keyitems += 64)); if (!p) { - PrintAndLogEx(FAILED, "cannot allocate memory for Keys"); + PrintAndLogEx(FAILED, "Cannot allocate memory for defKeys"); free(keyBlock); + fclose(f); return PM3_EMALLOC; } keyBlock = p; } - PrintAndLogEx(NORMAL, "[%2d] key %s", keycnt, sprint_hex((keyBlock + 6 * keycnt), 6)); + memset(keyBlock + 6 * keycnt, 0, 6); + num_to_bytes(strtoll(buf, NULL, 16), 6, keyBlock + 6 * keycnt); + //PrintAndLogEx(NORMAL, "check key[%2d] %012" PRIx64, keycnt, bytes_to_num(keyBlock + 6*keycnt, 6)); keycnt++; - } else if (clen == 1) { - if (ctmp == 't') { transferToEml = 1; continue; } - if (ctmp == 'd') { createDumpFile = 1; continue; } - } else { - // May be a dic file - if (param_getstr(Cmd, i, filename, sizeof(filename)) >= FILE_PATH_SIZE) { - PrintAndLogEx(FAILED, "File name too long"); - free(keyBlock); - return PM3_EINVARG; - } - - char *dict_path; - int res = searchFile(&dict_path, DICTIONARIES_SUBDIR, filename, ".dic", false); - if (res != PM3_SUCCESS) { - free(keyBlock); - return PM3_EFILE; - } - f = fopen(dict_path, "r"); - if (!f) { - PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", dict_path); - free(dict_path); - free(keyBlock); - return PM3_EFILE; - } - free(dict_path); - - // load keys from dictionary file - while (fgets(buf, sizeof(buf), f)) { - if (strlen(buf) < 12 || buf[11] == '\n') - continue; - - while (fgetc(f) != '\n' && !feof(f)) ; //goto next line - - if (buf[0] == '#') continue; //The line start with # is comment, skip - - // codesmell, only checks first char? - if (!isxdigit(buf[0])) { - PrintAndLogEx(FAILED, "File content error. '" _YELLOW_("%s")"' must include 12 HEX symbols", buf); - continue; - } - - buf[12] = 0; - - if (keyitems - keycnt < 2) { - p = realloc(keyBlock, 6 * (keyitems += 64)); - if (!p) { - PrintAndLogEx(FAILED, "Cannot allocate memory for defKeys"); - free(keyBlock); - fclose(f); - return PM3_EMALLOC; - } - keyBlock = p; - } - memset(keyBlock + 6 * keycnt, 0, 6); - num_to_bytes(strtoll(buf, NULL, 16), 6, keyBlock + 6 * keycnt); - //PrintAndLogEx(NORMAL, "check key[%2d] %012" PRIx64, keycnt, bytes_to_num(keyBlock + 6*keycnt, 6)); - keycnt++; - memset(buf, 0, sizeof(buf)); - } - fclose(f); - PrintAndLogEx(SUCCESS, "Loaded %2d keys from " _YELLOW_("%s"), keycnt, filename); + memset(buf, 0, sizeof(buf)); } + fclose(f); + PrintAndLogEx(SUCCESS, "Loaded %2d keys from " _YELLOW_("%s"), keycnt, filename); } + uint64_t key64 = 0; + if (keycnt == 0) { PrintAndLogEx(INFO, "No key specified, trying default keys"); for (; keycnt < ARRAYLEN(g_mifare_default_keys); keycnt++) @@ -3158,6 +3176,7 @@ static int CmdHF14AMfChk(const char *Cmd) { } // create/initialize key storage structure + sector_t *e_sector = NULL; int32_t res = initSectorTable(&e_sector, SectorsCnt); if (res != SectorsCnt) { free(keyBlock); @@ -3181,7 +3200,7 @@ static int CmdHF14AMfChk(const char *Cmd) { // loop sectors but block is used as to keep track of from which blocks to test int b = blockNo; - for (i = 0; i < SectorsCnt; ++i) { + for (int i = 0; i < SectorsCnt; ++i) { // skip already found keys. if (e_sector[i].foundKey[trgKeyType]) continue; @@ -3218,7 +3237,7 @@ static int CmdHF14AMfChk(const char *Cmd) { // loop sectors but block is used as to keep track of from which blocks to test int b = blockNo; - for (i = 0; i < SectorsCnt; i++) { + for (int i = 0; i < SectorsCnt; i++) { // KEY A but not KEY B if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) { @@ -3269,7 +3288,7 @@ out: // fast push mode conn.block_after_ACK = true; uint8_t block[16] = {0x00}; - for (i = 0; i < SectorsCnt; ++i) { + for (int i = 0; i < SectorsCnt; ++i) { uint8_t blockno = FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1; mfEmlGetMem(block, blockno, 1); diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index 0019b6f2b..d52517f0a 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -586,7 +586,7 @@ static void show_help(bool showFullHelp, char *exec_name) { PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -w -- wait for serial port", exec_name); PrintAndLogEx(NORMAL, " %s -- runs the pm3 client in OFFLINE mode", exec_name); PrintAndLogEx(NORMAL, "\n to execute different commands from terminal:\n"); - PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -c \"hf mf chk 1* ?\" -- execute cmd and quit client", exec_name); + PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -c \"hf mf chk --1k -* --all\" -- execute cmd and quit client", exec_name); PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -l hf_read -- execute lua script " _YELLOW_("`hf_read`")" and quit client", exec_name); PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -s mycmds.txt -- execute each pm3 cmd in file and quit client", exec_name); PrintAndLogEx(NORMAL, "\n to flash fullimage and bootloader:\n"); diff --git a/doc/cheatsheet.md b/doc/cheatsheet.md index 2c436cbb6..471f20132 100644 --- a/doc/cheatsheet.md +++ b/doc/cheatsheet.md @@ -224,12 +224,22 @@ Check for default keys ``` Options --- -<*card memory> [t|d|s|ss] -* : all sectors -card memory : 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K -d : write keys to binary file + -h, --help This help + -k, --key Key specified as 12 hex symbols + --blk Input block number + -* Target all blocks + -a Input key specified is A key (default) + -b Input key specified is B key + --all Target all keys + --mini MIFARE Classic Mini / S20 + --1k MIFARE Classic 1k / S50 + --2k MIFARE Classic/Plus 2k + --4k MIFARE Classic 4k / S70 + --emu Fill simulator keys from found keys + --dump Dump found keys to file + -f, --file filename of dictionary -pm3 --> hf mf chk *1 ? d mfc_default_keys +pm3 --> hf mf chk -* --1k --all -f mfc_default_keys ``` Check for default keys from local memory @@ -315,7 +325,7 @@ pm3 --> hf mf sim -u 353c2aa6 Simulate MIFARE Sequence ``` -pm3 --> hf mf chk *1 ? d mfc_default_keys +pm3 --> hf mf chk -* --1k --all -f mfc_default_keys pm3 --> hf mf dump 1 pm3 --> script run data_mf_bin2eml -i dumpdata.bin pm3 --> hf mf eload 353C2AA6 @@ -324,7 +334,7 @@ pm3 --> hf mf sim -u 353c2aa6 Clone MIFARE 1K Sequence ``` -pm3 --> hf mf chk *1 ? d mfc_default_keys +pm3 --> hf mf chk -* --1k --all -f mfc_default_keys pm3 --> hf mf dump pm3 --> hf mf restore 1 u 4A6CE843 k hf-mf-A29558E4-key.bin f hf-mf-A29558E4-dump.bin ``` diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 368afa836..9811a7414 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -60,7 +60,6 @@ hf felica litedump hf mf hardnested hf mf autopwn hf mf nack -hf mf chk hf mf fchk hf mf decrypt hf mf rdbl