From ced9b0c6f82df3a75334d4df5bf800d5cc46a8b0 Mon Sep 17 00:00:00 2001 From: Gabriele Gristina Date: Sat, 5 Jun 2021 22:11:18 +0200 Subject: [PATCH] Added new feature: autodetect hash-mode --- docs/changes.txt | 1 + include/types.h | 4 + src/Makefile | 1 + src/hashcat.c | 324 +++++++++++++++++++++++++++++++++++++ src/interface.c | 6 +- src/modules/module_02000.c | 3 +- src/modules/module_09000.c | 3 +- src/modules/module_99999.c | 3 +- src/status.c | 2 + src/terminal.c | 5 + src/user_options.c | 6 + 11 files changed, 352 insertions(+), 6 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 5c2c5e26a..acfe0ebe5 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -41,6 +41,7 @@ - RC4 Kernels: Improved performance by 20%+ for hash-modes Kerberos 5 (etype 23), MS Office (<= 2003) and PDF (<= 1.6) by using new RC4 code - Status Screen: Show currently running kernel type (pure, optimized) and generator type (host, device) - UTF8-to-UTF16: Replaced naive UTF8 to UTF16 conversion with true conversion for RAR3, AES Crypt, MultiBit HD (scrypt) and Umbraco HMAC-SHA1 +- Autodetect hash-type: performs an automatic analysis of the hashlist, associating compatible algorithms, or executing the attack if only one compatible format is found. ## ## Technical diff --git a/include/types.h b/include/types.h index 354702779..fbbf235fc 100644 --- a/include/types.h +++ b/include/types.h @@ -210,6 +210,7 @@ typedef enum status_rc STATUS_ABORTED_RUNTIME = 11, STATUS_ERROR = 13, STATUS_ABORTED_FINISH = 14, + STATUS_AUTODETECT = 16, } status_rc_t; @@ -443,6 +444,7 @@ typedef enum opts_type OPTS_TYPE_MP_MULTI_DISABLE = (1ULL << 52), // do not multiply the kernel-accel with the multiprocessor count per device to allow more fine-tuned workload settings OPTS_TYPE_NATIVE_THREADS = (1ULL << 53), // forces "native" thread count: CPU=1, GPU-Intel=8, GPU-AMD=64 (wavefront), GPU-NV=32 (warps) OPTS_TYPE_POST_AMP_UTF16LE = (1ULL << 54), // run the utf8 to utf16le conversion kernel after they have been processed from amplifiers + OPTS_TYPE_AUTODETECT_DISABLE = (1ULL << 55), // skip autodetect engine } opts_type_t; @@ -594,6 +596,7 @@ typedef enum user_options_defaults { ADVICE_DISABLE = false, ATTACK_MODE = ATTACK_MODE_STRAIGHT, + AUTODETECT = false, BENCHMARK_ALL = false, BENCHMARK = false, BITMAP_MAX = 18, @@ -1939,6 +1942,7 @@ typedef struct user_options char **hc_argv; bool attack_mode_chgd; + bool autodetect; #ifdef WITH_BRAIN bool brain_host_chgd; bool brain_port_chgd; diff --git a/src/Makefile b/src/Makefile index 2f9f07432..77029e3f9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -189,6 +189,7 @@ endif ## because LZMA SDK ifeq ($(CC),clang) CFLAGS += -Wno-enum-conversion +CFLAGS += -Wno-typedef-redefinition endif ## because ZLIB diff --git a/src/hashcat.c b/src/hashcat.c index 7fa047ca7..459892bab 100644 --- a/src/hashcat.c +++ b/src/hashcat.c @@ -28,6 +28,7 @@ #include "event.h" #include "hashes.h" #include "hwmon.h" +#include "hlfmt.h" #include "induct.h" #include "interface.h" #include "logfile.h" @@ -1138,6 +1139,271 @@ int hashcat_session_init (hashcat_ctx_t *hashcat_ctx, const char *install_folder return 0; } +bool autodetect_hashmode_test (hashcat_ctx_t *hashcat_ctx) +{ + hashconfig_t *hashconfig = hashcat_ctx->hashconfig; + hashes_t *hashes = hashcat_ctx->hashes; + module_ctx_t *module_ctx = hashcat_ctx->module_ctx; + user_options_t *user_options = hashcat_ctx->user_options; + user_options_extra_t *user_options_extra = hashcat_ctx->user_options_extra; + + // check for file or hash on command line + // if file, find out if binary file + + if (hashconfig->opts_type & OPTS_TYPE_AUTODETECT_DISABLE) return false; + + if (hashconfig->opts_type & OPTS_TYPE_BINARY_HASHFILE) + { + if (hashconfig->opts_type & OPTS_TYPE_BINARY_HASHFILE_OPTIONAL) + { + hashes->hashlist_mode = (hc_path_exist (user_options_extra->hc_hash) == true) ? HL_MODE_FILE_PLAIN : HL_MODE_ARG; + + if (hashes->hashlist_mode == HL_MODE_FILE_PLAIN) + { + hashes->hashfile = user_options_extra->hc_hash; + } + } + else + { + hashes->hashlist_mode = HL_MODE_FILE_BINARY; + + if (hc_path_read (user_options_extra->hc_hash) == false) return false; + + hashes->hashfile = user_options_extra->hc_hash; + } + } + else + { + hashes->hashlist_mode = (hc_path_exist (user_options_extra->hc_hash) == true) ? HL_MODE_FILE_PLAIN : HL_MODE_ARG; + + if (hashes->hashlist_mode == HL_MODE_FILE_PLAIN) + { + hashes->hashfile = user_options_extra->hc_hash; + } + } + + /** + * load hashes, part I: find input mode + */ + + const char *hashfile = hashes->hashfile; + const u32 hashlist_mode = hashes->hashlist_mode; + + u32 hashlist_format = HLFMT_HASHCAT; + + if (hashlist_mode == HL_MODE_FILE_PLAIN) + { + HCFILE fp; + + if (hc_fopen (&fp, hashfile, "rb") == false) return false; + + hashlist_format = hlfmt_detect (hashcat_ctx, &fp, 100); + + hc_fclose (&fp); + } + + hashes->hashlist_format = hashlist_format; + + /** + * load hashes, part II: allocate required memory, set pointers + */ + + void *digest = hccalloc (1, hashconfig->dgst_size); + salt_t *salt = (salt_t *) hccalloc (1, sizeof (salt_t)); + void *esalt = NULL; + void *hook_salt = NULL; + + if (hashconfig->esalt_size > 0) + { + esalt = hccalloc (1, hashconfig->esalt_size); + } + + if (hashconfig->hook_salt_size > 0) + { + hook_salt = hccalloc (1, hashconfig->hook_salt_size); + } + + hashinfo_t *hash_info = (hashinfo_t *) hcmalloc (sizeof (hashinfo_t)); + + hash_info->user = (user_t *) hcmalloc (sizeof (user_t)); + hash_info->orighash = (char *) hcmalloc (256); + hash_info->split = (split_t *) hcmalloc (sizeof (split_t)); + + hash_t *hashes_buf = (hash_t *) hcmalloc (sizeof (hash_t)); + + hashes_buf->digest = digest; + hashes_buf->salt = salt; + hashes_buf->esalt = esalt; + hashes_buf->hook_salt = hook_salt; + + hashes->hashes_buf = hashes_buf; + hashes->digests_buf = digest; + hashes->salts_buf = salt; + hashes->esalts_buf = esalt; + hashes->hook_salts_buf = hook_salt; + + bool success = false; + + if (hashlist_mode == HL_MODE_ARG) + { + char *input_buf = user_options_extra->hc_hash; + + size_t input_len = strlen (input_buf); + + char *hash_buf = NULL; + int hash_len = 0; + + hlfmt_hash (hashcat_ctx, hashlist_format, input_buf, input_len, &hash_buf, &hash_len); + + bool hash_fmt_error = false; + + if (hash_len < 1) hash_fmt_error = true; + if (hash_buf == NULL) hash_fmt_error = true; + + if (hash_fmt_error) return false; + + const int parser_status = module_ctx->module_hash_decode (hashconfig, digest, salt, esalt, hook_salt, hash_info, hash_buf, hash_len); + + if (parser_status == PARSER_OK) success = true; + } + else if (hashlist_mode == HL_MODE_FILE_PLAIN) + { + HCFILE fp; + + if (hc_fopen (&fp, hashfile, "rb") == false) return false; + + char *line_buf = (char *) hcmalloc (HCBUFSIZ_LARGE); + + while (!hc_feof (&fp)) + { + const size_t line_len = fgetl (&fp, line_buf, HCBUFSIZ_LARGE); + + if (line_len == 0) continue; + + char *hash_buf = NULL; + int hash_len = 0; + + hlfmt_hash (hashcat_ctx, hashlist_format, line_buf, line_len, &hash_buf, &hash_len); + + bool hash_fmt_error = false; + + if (hash_len < 1) hash_fmt_error = true; + if (hash_buf == NULL) hash_fmt_error = true; + + if (hash_fmt_error) continue; + + int parser_status = module_ctx->module_hash_decode (hashconfig, digest, salt, esalt, hook_salt, hash_info, hash_buf, hash_len); + + if (parser_status == PARSER_OK) + { + success = true; + + break; + } + } + + hcfree (line_buf); + + hc_fclose (&fp); + } + else if (hashlist_mode == HL_MODE_FILE_BINARY) + { + char *input_buf = user_options_extra->hc_hash; + + size_t input_len = strlen (input_buf); + + if (module_ctx->module_hash_binary_parse != MODULE_DEFAULT) + { + const int hashes_parsed = module_ctx->module_hash_binary_parse (hashconfig, user_options, user_options_extra, hashes); + + if (hashes_parsed > 0) success = true; + } + else + { + const int parser_status = module_ctx->module_hash_decode (hashconfig, digest, salt, esalt, hook_salt, hash_info, input_buf, input_len); + + if (parser_status == PARSER_OK) success = true; + } + } + + hcfree (digest); + hcfree (salt); + hcfree (hash_info); + hcfree (hashes_buf); + + if (hashconfig->esalt_size > 0) + { + hcfree (esalt); + } + + if (hashconfig->hook_salt_size > 0) + { + hcfree (hook_salt); + } + + hashes->digests_buf = NULL; + hashes->salts_buf = NULL; + hashes->esalts_buf = NULL; + hashes->hook_salts_buf = NULL; + + return success; +} + +int autodetect_hashmodes (hashcat_ctx_t *hashcat_ctx, int *modes_buf) +{ + folder_config_t *folder_config = hashcat_ctx->folder_config; + user_options_t *user_options = hashcat_ctx->user_options; + + int modes_cnt = 0; + + // save quiet state so we can restore later + + const bool quiet_sav = user_options->quiet; + + user_options->quiet = true; + + char *modulefile = (char *) hcmalloc (HCBUFSIZ_TINY); + + // brute force all the modes + + for (int i = 0; i < MODULE_HASH_MODES_MAXIMUM; i++) + { + user_options->hash_mode = i; + + // this is just to find out of that hash-mode exists or not + + module_filename (folder_config, i, modulefile, HCBUFSIZ_TINY); + + if (hc_path_exist (modulefile) == false) continue; + + // we know it exists, so load the plugin + + const int hashconfig_init_rc = hashconfig_init (hashcat_ctx); + + if (hashconfig_init_rc == 0) + { + const bool test_rc = autodetect_hashmode_test (hashcat_ctx); + + if (test_rc == true) + { + modes_buf[modes_cnt] = i; + + modes_cnt++; + } + } + + // clean up + + hashconfig_destroy (hashcat_ctx); + } + + hcfree (modulefile); + + user_options->quiet = quiet_sav; + + return modes_cnt; +} + int hashcat_session_execute (hashcat_ctx_t *hashcat_ctx) { folder_config_t *folder_config = hashcat_ctx->folder_config; @@ -1170,6 +1436,64 @@ int hashcat_session_execute (hashcat_ctx_t *hashcat_ctx) dictstat_read (hashcat_ctx); + // autodetect + + if (user_options->autodetect == true) + { + status_ctx->devices_status = STATUS_AUTODETECT; + + int *modes_buf = (int *) hccalloc (MODULE_HASH_MODES_MAXIMUM, sizeof (int)); + + if (!modes_buf) return -1; + + const int modes_cnt = autodetect_hashmodes (hashcat_ctx, modes_buf); + + if (modes_cnt > 0) + { + event_log_info (hashcat_ctx, "The following %d hash-mode match the structure of your input hash:", modes_cnt); + event_log_info (hashcat_ctx, NULL); + event_log_info (hashcat_ctx, " # | Name | Category"); + event_log_info (hashcat_ctx, " ======+=====================================================+======================================"); + + for (int i = 0; i < modes_cnt; i++) + { + user_options->hash_mode = modes_buf[i]; + + if (hashconfig_init (hashcat_ctx) == 0) + { + event_log_info (hashcat_ctx, "%7u | %-51s | %s", hashcat_ctx->hashconfig->hash_mode, hashcat_ctx->hashconfig->hash_name, strhashcategory (hashcat_ctx->hashconfig->hash_category)); + + if (modes_cnt != 1) hashconfig_destroy (hashcat_ctx); // keep for later + } + } + + event_log_info (hashcat_ctx, NULL); + + if (modes_cnt > 1) + { + event_log_error (hashcat_ctx, "Please specify the hash-mode by argument (-m)."); + + return -1; + } + else // 1 + { + event_log_warning (hashcat_ctx, "You have not specified -m to select the correct hash-mode."); + event_log_warning (hashcat_ctx, "It was automatically selected by hashcat because it was the only hash-mode matching your input hash."); + event_log_warning (hashcat_ctx, "Under no circumstances it is not to be understood as a guarantee this is the right hash-mode."); + event_log_warning (hashcat_ctx, "Do not report hashcat issues if you do not know exactly how the hash was extracted."); + event_log_warning (hashcat_ctx, NULL); + + user_options->autodetect = false; + } + } + else + { + if (user_options->show == false) event_log_error (hashcat_ctx, "No hash-mode matches the structure of the input hash."); + + return -1; + } + } + /** * outer loop */ diff --git a/src/interface.c b/src/interface.c index c49f30610..8b0d4c8a3 100644 --- a/src/interface.c +++ b/src/interface.c @@ -259,7 +259,7 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx) { if ((hashconfig->opts_type & OPTS_TYPE_KEYBOARD_MAPPING) == 0) { - event_log_error (hashcat_ctx, "Parameter --keyboard-layout-mapping not valid for hash-type %u", hashconfig->hash_mode); + if (user_options->autodetect == false) event_log_error (hashcat_ctx, "Parameter --keyboard-layout-mapping not valid for hash-type %u", hashconfig->hash_mode); return -1; } @@ -288,7 +288,7 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx) } else { - event_log_error (hashcat_ctx, "Parameter --hex-salt not valid for hash-type %u", hashconfig->hash_mode); + if (user_options->autodetect == false) event_log_error (hashcat_ctx, "Parameter --hex-salt not valid for hash-type %u", hashconfig->hash_mode); return -1; } @@ -302,7 +302,7 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx) { if (hashconfig->opts_type & OPTS_TYPE_SUGGEST_KG) { - if (user_options->quiet == false) + if (user_options->quiet == false && user_options->autodetect == false) { event_log_warning (hashcat_ctx, "This hash-mode is known to emit multiple valid password candidates for the same hash."); event_log_warning (hashcat_ctx, "Use --keep-guessing to prevent hashcat from shutdown after the hash has been cracked."); diff --git a/src/modules/module_02000.c b/src/modules/module_02000.c index 0c21c8862..19fb60394 100644 --- a/src/modules/module_02000.c +++ b/src/modules/module_02000.c @@ -20,7 +20,8 @@ static const u32 HASH_CATEGORY = HASH_CATEGORY_PLAIN; static const char *HASH_NAME = "STDOUT"; static const u64 KERN_TYPE = 2000; static const u32 OPTI_TYPE = 0; -static const u64 OPTS_TYPE = OPTS_TYPE_SELF_TEST_DISABLE; +static const u64 OPTS_TYPE = OPTS_TYPE_SELF_TEST_DISABLE + | OPTS_TYPE_AUTODETECT_DISABLE; static const u32 SALT_TYPE = SALT_TYPE_NONE; static const char *ST_PASS = "hashcat"; static const char *ST_HASH = "hashcat"; diff --git a/src/modules/module_09000.c b/src/modules/module_09000.c index a6341d273..5b7c87c07 100644 --- a/src/modules/module_09000.c +++ b/src/modules/module_09000.c @@ -21,7 +21,8 @@ static const char *HASH_NAME = "Password Safe v2"; static const u64 KERN_TYPE = 9000; static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE; static const u64 OPTS_TYPE = OPTS_TYPE_PT_GENERATE_LE - | OPTS_TYPE_BINARY_HASHFILE; + | OPTS_TYPE_BINARY_HASHFILE + | OPTS_TYPE_AUTODETECT_DISABLE; static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED; static const char *ST_PASS = "hashcat"; static const char *ST_HASH = "0a3f352686e5eb5be173e668a4fff5cd5df420927e1da2d5d4052340160637e3e6a5a92841a188ed240e13b919f3d91694bd4c0acba79271e9c08a83ea5ad387cbb74d5884066a1cb5a8caa80d847079168f84823847c631dbe3a834f1bc496acfebac3bff1608bf1c857717f8f428e07b5e2cb12aaeddfa83d7dcb6d840234d08b84f8ca6c6e562af73eea13148f7902bcaf0220d3e36eeeff1d37283dc421483a2791182614ebb"; diff --git a/src/modules/module_99999.c b/src/modules/module_99999.c index 959786003..e079aa7ba 100644 --- a/src/modules/module_99999.c +++ b/src/modules/module_99999.c @@ -30,7 +30,8 @@ static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE | OPTI_TYPE_RAW_HASH; static const u64 OPTS_TYPE = OPTS_TYPE_PT_GENERATE_LE | OPTS_TYPE_PT_ADD80 - | OPTS_TYPE_PT_ADDBITS14; + | OPTS_TYPE_PT_ADDBITS14 + | OPTS_TYPE_AUTODETECT_DISABLE; static const u32 SALT_TYPE = SALT_TYPE_NONE; static const char *ST_PASS = "hashcat"; static const char *ST_HASH = "hashcat"; diff --git a/src/status.c b/src/status.c index dc39cf71e..93d4404fe 100644 --- a/src/status.c +++ b/src/status.c @@ -34,6 +34,7 @@ static const char *ST_0012 = "Running (Checkpoint Quit requested)"; static const char *ST_0013 = "Error"; static const char *ST_0014 = "Aborted (Finish)"; static const char *ST_0015 = "Running (Quit after attack requested)"; +static const char *ST_0016 = "Autodetect"; static const char *ST_9999 = "Unknown! Bug!"; static const char UNITS[7] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E' }; @@ -292,6 +293,7 @@ const char *status_get_status_string (const hashcat_ctx_t *hashcat_ctx) case STATUS_ABORTED_RUNTIME: return ST_0011; case STATUS_ERROR: return ST_0013; case STATUS_ABORTED_FINISH: return ST_0014; + case STATUS_AUTODETECT: return ST_0016; } return ST_9999; diff --git a/src/terminal.c b/src/terminal.c index b8206bd32..9a9bc357a 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -68,6 +68,11 @@ void welcome_screen (hashcat_ctx_t *hashcat_ctx, const char *version_tag) event_log_info (hashcat_ctx, "%s (%s) starting in progress-only mode...", PROGNAME, version_tag); event_log_info (hashcat_ctx, NULL); } + else if (user_options->autodetect == true) + { + event_log_info (hashcat_ctx, "%s (%s) starting in autodetect mode...", PROGNAME, version_tag); + event_log_info (hashcat_ctx, NULL); + } else { event_log_info (hashcat_ctx, "%s (%s) starting...", PROGNAME, version_tag); diff --git a/src/user_options.c b/src/user_options.c index ce4d93a24..70c929d53 100644 --- a/src/user_options.c +++ b/src/user_options.c @@ -157,6 +157,7 @@ int user_options_init (hashcat_ctx_t *hashcat_ctx) user_options->advice_disable = ADVICE_DISABLE; user_options->attack_mode = ATTACK_MODE; + user_options->autodetect = AUTODETECT; user_options->backend_devices = NULL; user_options->backend_ignore_cuda = BACKEND_IGNORE_CUDA; user_options->backend_ignore_opencl = BACKEND_IGNORE_OPENCL; @@ -664,6 +665,11 @@ int user_options_sanity (hashcat_ctx_t *hashcat_ctx) return -1; } + if (user_options->hash_mode == 0 && user_options->hash_mode_chgd == false) + { + user_options->autodetect = true; + } + if (user_options->outfile_format == 0) { event_log_error (hashcat_ctx, "Invalid --outfile-format value specified.");