/** * Author......: See docs/credits.txt * License.....: MIT */ #include "common.h" #include "types.h" #include "bitops.h" #include "convert.h" #include "memory.h" #include "event.h" #include "interface.h" #include "filehandling.h" #include "loopback.h" #include "outfile.h" #include "potfile.h" #include "locking.h" #include "shared.h" // get rid of this later int sort_by_hash (const void *v1, const void *v2, void *v3); int sort_by_hash_no_salt (const void *v1, const void *v2, void *v3); // get rid of this later // this function is for potfile comparison where the potfile does not contain all the // information requires to do a true sort_by_hash() bsearch static int sort_by_hash_t_salt (const void *v1, const void *v2) { const hash_t *h1 = (const hash_t *) v1; const hash_t *h2 = (const hash_t *) v2; const salt_t *s1 = h1->salt; const salt_t *s2 = h2->salt; const int res1 = (int) s1->salt_len - (int) s2->salt_len; if (res1 != 0) return (res1); //const int res2 = (int) s1->salt_iter - (int) s2->salt_iter; // //if (res2 != 0) return (res2); for (int n = 0; n < 16; n++) { if (s1->salt_buf[n] > s2->salt_buf[n]) return 1; if (s1->salt_buf[n] < s2->salt_buf[n]) return -1; } for (int n = 0; n < 8; n++) { if (s1->salt_buf_pc[n] > s2->salt_buf_pc[n]) return 1; if (s1->salt_buf_pc[n] < s2->salt_buf_pc[n]) return -1; } return 0; } // this function is special and only used whenever --username and --show are used together: // it will sort all tree entries according to the settings stored in hashconfig int sort_pot_tree_by_hash (const void *v1, const void *v2) { const pot_tree_entry_t *t1 = (const pot_tree_entry_t *) v1; const pot_tree_entry_t *t2 = (const pot_tree_entry_t *) v2; const hash_t *h1 = (const hash_t *) t1->nodes->hash_buf; const hash_t *h2 = (const hash_t *) t2->nodes->hash_buf; hashconfig_t *hc = (hashconfig_t *) t1->hashconfig; // is same as t2->hashconfig return sort_by_hash (h1, h2, hc); } // the problem with the GNU tdestroy () function is that it doesn't work with mingw etc // there are 2 alternatives: // 1. recursively delete the entries with entry->left and entry->right // 2. use tdelete () <- this is what we currently use, but this could be slower! void pot_tree_destroy (pot_tree_entry_t *tree) { pot_tree_entry_t *entry = tree; while (tree != NULL) { entry = *(pot_tree_entry_t **) tree; tdelete (entry, (void **) &tree, sort_pot_tree_by_hash); } } int potfile_init (hashcat_ctx_t *hashcat_ctx) { folder_config_t *folder_config = hashcat_ctx->folder_config; potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; user_options_t *user_options = hashcat_ctx->user_options; potfile_ctx->enabled = false; if (user_options->benchmark == true) return 0; if (user_options->example_hashes == true) return 0; if (user_options->keyspace == true) return 0; if (user_options->opencl_info == true) return 0; if (user_options->stdout_flag == true) return 0; if (user_options->speed_only == true) return 0; if (user_options->progress_only == true) return 0; if (user_options->usage == true) return 0; if (user_options->version == true) return 0; if (user_options->potfile_disable == true) return 0; potfile_ctx->enabled = true; if (user_options->potfile_path == NULL) { potfile_ctx->fp = NULL; hc_asprintf (&potfile_ctx->filename, "%s/hashcat.potfile", folder_config->profile_dir); } else { potfile_ctx->filename = hcstrdup (user_options->potfile_path); potfile_ctx->fp = NULL; } // keep all hashes if --username was combined with --left or --show potfile_ctx->keep_all_hashes = false; if (user_options->username == true) { if ((user_options->show == true) || (user_options->left == true)) { potfile_ctx->keep_all_hashes = true; } } // keep all hashes if -m 3000 was combined with --left or --show if (user_options->hash_mode == 3000) { if ((user_options->show == true) || (user_options->left == true)) { potfile_ctx->keep_all_hashes = true; } } // starting from here, we should allocate some scratch buffer for later use u8 *out_buf = (u8 *) hcmalloc (HCBUFSIZ_LARGE); potfile_ctx->out_buf = out_buf; // we need two buffers in parallel u8 *tmp_buf = (u8 *) hcmalloc (HCBUFSIZ_LARGE); potfile_ctx->tmp_buf = tmp_buf; // old potfile detection if (user_options->potfile_path == NULL) { char *potfile_old; hc_asprintf (&potfile_old, "%s/hashcat.pot", folder_config->profile_dir); if (hc_path_exist (potfile_old) == true) { event_log_warning (hashcat_ctx, "Old potfile detected: %s", potfile_old); event_log_warning (hashcat_ctx, "New potfile is: %s ", potfile_ctx->filename); event_log_warning (hashcat_ctx, NULL); } hcfree (potfile_old); } return 0; } void potfile_destroy (hashcat_ctx_t *hashcat_ctx) { potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; if (potfile_ctx->enabled == false) return; hcfree (potfile_ctx->out_buf); hcfree (potfile_ctx->tmp_buf); memset (potfile_ctx, 0, sizeof (potfile_ctx_t)); } int potfile_read_open (hashcat_ctx_t *hashcat_ctx) { potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; if (potfile_ctx->enabled == false) return 0; potfile_ctx->fp = fopen (potfile_ctx->filename, "rb"); if (potfile_ctx->fp == NULL) { event_log_error (hashcat_ctx, "%s: %s", potfile_ctx->filename, strerror (errno)); return -1; } return 0; } void potfile_read_close (hashcat_ctx_t *hashcat_ctx) { potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; if (potfile_ctx->enabled == false) return; if (potfile_ctx->fp == NULL) return; fclose (potfile_ctx->fp); } int potfile_write_open (hashcat_ctx_t *hashcat_ctx) { potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; if (potfile_ctx->enabled == false) return 0; FILE *fp = fopen (potfile_ctx->filename, "ab"); if (fp == NULL) { event_log_error (hashcat_ctx, "%s: %s", potfile_ctx->filename, strerror (errno)); return -1; } potfile_ctx->fp = fp; return 0; } void potfile_write_close (hashcat_ctx_t *hashcat_ctx) { potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; if (potfile_ctx->enabled == false) return; fclose (potfile_ctx->fp); } void potfile_write_append (hashcat_ctx_t *hashcat_ctx, const char *out_buf, u8 *plain_ptr, unsigned int plain_len) { const hashconfig_t *hashconfig = hashcat_ctx->hashconfig; const potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; const user_options_t *user_options = hashcat_ctx->user_options; if (potfile_ctx->enabled == false) return; u8 *tmp_buf = potfile_ctx->tmp_buf; int tmp_len = 0; if (1) { const size_t out_len = strlen (out_buf); memcpy (tmp_buf + tmp_len, out_buf, out_len); tmp_len += out_len; tmp_buf[tmp_len] = hashconfig->separator; tmp_len += 1; } if (1) { const bool always_ascii = (hashconfig->hash_type & OPTS_TYPE_PT_ALWAYS_ASCII) ? true : false; if ((user_options->outfile_autohex == true) && (need_hexify (plain_ptr, plain_len, hashconfig->separator, always_ascii) == true)) { tmp_buf[tmp_len++] = '$'; tmp_buf[tmp_len++] = 'H'; tmp_buf[tmp_len++] = 'E'; tmp_buf[tmp_len++] = 'X'; tmp_buf[tmp_len++] = '['; exec_hexify ((const u8 *) plain_ptr, plain_len, tmp_buf + tmp_len); tmp_len += plain_len * 2; tmp_buf[tmp_len++] = ']'; } else { memcpy (tmp_buf + tmp_len, plain_ptr, plain_len); tmp_len += plain_len; } } tmp_buf[tmp_len] = 0; lock_file (potfile_ctx->fp); fprintf (potfile_ctx->fp, "%s" EOL, tmp_buf); fflush (potfile_ctx->fp); if (unlock_file (potfile_ctx->fp)) { event_log_error (hashcat_ctx, "%s: Failed to unlock file.", potfile_ctx->filename); } } void potfile_update_hash (hashcat_ctx_t *hashcat_ctx, hash_t *found, char *line_pw_buf, int line_pw_len) { const loopback_ctx_t *loopback_ctx = hashcat_ctx->loopback_ctx; if (found == NULL) return; char *pw_buf = line_pw_buf; int pw_len = line_pw_len; found->pw_buf = (char *) hcmalloc (pw_len + 1); found->pw_len = pw_len; memcpy (found->pw_buf, pw_buf, pw_len); found->pw_buf[found->pw_len] = 0; found->cracked = 1; // if enabled, update also the loopback file if (loopback_ctx->fp != NULL) { loopback_write_append (hashcat_ctx, (u8 *) pw_buf, (unsigned int) pw_len); } } void potfile_update_hashes (hashcat_ctx_t *hashcat_ctx, hash_t *hash_buf, char *line_pw_buf, int line_pw_len, pot_tree_entry_t *tree) { hashconfig_t *hashconfig = hashcat_ctx->hashconfig; // the linked list node: pot_hash_node_t search_node; search_node.hash_buf = hash_buf; search_node.next = NULL; // the search entry: pot_tree_entry_t search_entry; search_entry.nodes = &search_node; search_entry.hashconfig = hashconfig; // the main search function is this: void **found = tfind (&search_entry, (void **) &tree, sort_pot_tree_by_hash); if (found) { pot_tree_entry_t *found_entry = (pot_tree_entry_t *) *found; pot_hash_node_t *node = found_entry->nodes; while (node) { potfile_update_hash (hashcat_ctx, node->hash_buf, line_pw_buf, line_pw_len); node = node->next; } } } int potfile_remove_parse (hashcat_ctx_t *hashcat_ctx) { const hashconfig_t *hashconfig = hashcat_ctx->hashconfig; const hashes_t *hashes = hashcat_ctx->hashes; const potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; if (potfile_ctx->enabled == false) return 0; // if no potfile exists yet we don't need to do anything here if (hc_path_exist (potfile_ctx->filename) == false) return 0; hash_t *hashes_buf = hashes->hashes_buf; u32 hashes_cnt = hashes->hashes_cnt; // no solution for these special hash types (for instane because they use hashfile in output etc) if (hashconfig->hash_mode == 5200) return 0; if ((hashconfig->hash_mode >= 6200) && (hashconfig->hash_mode <= 6299)) return 0; if (hashconfig->hash_mode == 9000) return 0; if ((hashconfig->hash_mode >= 13700) && (hashconfig->hash_mode <= 13799)) return 0; if (hashconfig->hash_mode == 14600) return 0; hash_t hash_buf; hash_buf.digest = hcmalloc (hashconfig->dgst_size); hash_buf.salt = NULL; hash_buf.esalt = NULL; hash_buf.hook_salt = NULL; hash_buf.hash_info = NULL; hash_buf.cracked = 0; if (hashconfig->is_salted == true) { hash_buf.salt = (salt_t *) hcmalloc (sizeof (salt_t)); } if (hashconfig->esalt_size > 0) { hash_buf.esalt = hcmalloc (hashconfig->esalt_size); } if (hashconfig->hook_salt_size > 0) { hash_buf.hook_salt = hcmalloc (hashconfig->hook_salt_size); } // we only need this variable in a very specific situation: // whenever we use --username and --show together we want to keep all hashes sorted within a nice structure pot_tree_entry_t *all_hashes_tree = NULL; pot_tree_entry_t *tree_entry_cache = NULL; pot_hash_node_t *tree_nodes_cache = NULL; if (potfile_ctx->keep_all_hashes == true) { // we need *at most* one entry for every hash // (if there are no hashes with the same keys (hash + salt), a counter example would be: same hash but different user name) tree_entry_cache = (pot_tree_entry_t *) hccalloc (hashes_cnt, sizeof (pot_tree_entry_t)); // we need *always exactly* one linked list for every hash tree_nodes_cache = (pot_hash_node_t *) hccalloc (hashes_cnt, sizeof (pot_hash_node_t)); for (u32 hash_pos = 0; hash_pos < hashes_cnt; hash_pos++) { // initialize the linked list node: // we always need to create a new one and add it, because we want to keep and later update all hashes: pot_hash_node_t *new_node = &tree_nodes_cache[hash_pos]; new_node->hash_buf = &hashes_buf[hash_pos]; new_node->next = NULL; // initialize the entry: pot_tree_entry_t *new_entry = &tree_entry_cache[hash_pos]; // note: the "key" (hash + salt) is indirectly accessible via the first nodes "hash_buf" new_entry->nodes = new_node; // the hashconfig is needed here because we need to be able to check within the sort function if we also need // to sort by salt and we also need to have the correct order of dgst_pos0...dgst_pos3: new_entry->hashconfig = (hashconfig_t *) hashconfig; // "const hashconfig_t" gives a warning // the following function searches if the "key" is already present and if not inserts the new entry: void **found = tsearch (new_entry, (void **) &all_hashes_tree, sort_pot_tree_by_hash); pot_tree_entry_t *found_entry = (pot_tree_entry_t *) *found; // we now need to check these cases; tsearch () could return: // 1. NULL : if we have a memory allocation problem (not enough memory for the tree structure) // 2. found_entry == new_entry: if we successfully insert a new key (which was not present yet) // 3. found_entry != new_entry: if the key was already present // case 1: memory allocation error if (found_entry == NULL) { fprintf (stderr, "Error while allocating memory for the potfile search: %s\n", MSG_ENOMEM); return -1; } // case 2: this means it was a new insert (and the insert was successful) if (found_entry == new_entry) { // no updates to the linked list required (since it is the first one!) } // case 3: if we have found an already existing entry else { new_node->next = found_entry->nodes; } // we always insert the new node at the very beginning // (or in other words: the head of the linked list always points to *this* new inserted node) found_entry->nodes = new_node; } } // special case for a split hash if (hashconfig->hash_mode == 3000) { int parser_status = hashconfig->parse_func ((u8 *) LM_ZERO_HASH, 16, &hash_buf, hashconfig); if (parser_status == PARSER_OK) { if (potfile_ctx->keep_all_hashes == true) { potfile_update_hashes (hashcat_ctx, &hash_buf, NULL, 0, all_hashes_tree); } else { hash_t *found = (hash_t *) hc_bsearch_r (&hash_buf, hashes_buf, hashes_cnt, sizeof (hash_t), sort_by_hash_no_salt, (void *) hashconfig); potfile_update_hash (hashcat_ctx, found, NULL, 0); } } } const int rc = potfile_read_open (hashcat_ctx); if (rc == -1) return -1; char *line_buf = (char *) hcmalloc (HCBUFSIZ_LARGE); while (!feof (potfile_ctx->fp)) { int line_len = fgetl (potfile_ctx->fp, line_buf); if (line_len == 0) continue; char *last_separator = strrchr (line_buf, hashconfig->separator); if (last_separator == NULL) continue; // ?? char *line_pw_buf = last_separator + 1; int line_pw_len = line_buf + line_len - line_pw_buf; char *line_hash_buf = line_buf; int line_hash_len = last_separator - line_buf; line_hash_buf[line_hash_len] = 0; if (line_hash_len == 0) continue; if (hashconfig->is_salted == true) { memset (hash_buf.salt, 0, sizeof (salt_t)); } if (hashconfig->esalt_size > 0) { memset (hash_buf.esalt, 0, hashconfig->esalt_size); } if (hashconfig->hook_salt_size > 0) { memset (hash_buf.hook_salt, 0, hashconfig->hook_salt_size); } hash_t *found = NULL; if (hashconfig->hash_mode == 6800) { if (line_hash_len < 256) // 64 = 64 * u32 in salt_buf[] { // manipulate salt_buf memcpy (hash_buf.salt->salt_buf, line_hash_buf, line_hash_len); hash_buf.salt->salt_len = line_hash_len; found = (hash_t *) bsearch (&hash_buf, hashes_buf, hashes_cnt, sizeof (hash_t), sort_by_hash_t_salt); } } else if ((hashconfig->hash_mode == 2500) || (hashconfig->hash_mode == 2501)) { // here we have in line_hash_buf: hash:macap:macsta:essid:password char *sep_pos = strrchr (line_hash_buf, ':'); if (sep_pos == NULL) continue; sep_pos[0] = 0; char *hash_pos = line_hash_buf; const size_t hash_len = strlen (hash_pos); if (hash_len != 32 + 1 + 12 + 1 + 12) continue; char *essid_pos = sep_pos + 1; int essid_len = (int) strlen (essid_pos); if (is_hexify ((const u8 *) essid_pos, (const int) essid_len) == true) { essid_len = exec_unhexify ((const u8 *) essid_pos, essid_len, (u8 *) essid_pos, essid_len); } if (essid_len > 32) continue; if (hashconfig->is_salted == true) { // this should be always true, but we need it to make scan-build happy memcpy (hash_buf.salt->salt_buf, essid_pos, essid_len); hash_buf.salt->salt_len = essid_len; hash_buf.salt->salt_iter = ROUNDS_WPA - 1; u32 hash[4]; hash[0] = hex_to_u32 ((const u8 *) &hash_pos[ 0]); hash[1] = hex_to_u32 ((const u8 *) &hash_pos[ 8]); hash[2] = hex_to_u32 ((const u8 *) &hash_pos[16]); hash[3] = hex_to_u32 ((const u8 *) &hash_pos[24]); hash[0] = byte_swap_32 (hash[0]); hash[1] = byte_swap_32 (hash[1]); hash[2] = byte_swap_32 (hash[2]); hash[3] = byte_swap_32 (hash[3]); u32 *digest = (u32 *) hash_buf.digest; digest[0] = hash[0]; digest[1] = hash[1]; digest[2] = hash[2]; digest[3] = hash[3]; } found = (hash_t *) hc_bsearch_r (&hash_buf, hashes_buf, hashes_cnt, sizeof (hash_t), sort_by_hash, (void *) hashconfig); } else { int parser_status = hashconfig->parse_func ((u8 *) line_hash_buf, line_hash_len, &hash_buf, hashconfig); if (parser_status != PARSER_OK) continue; if (potfile_ctx->keep_all_hashes == true) { potfile_update_hashes (hashcat_ctx, &hash_buf, line_pw_buf, line_pw_len, all_hashes_tree); continue; } found = (hash_t *) hc_bsearch_r (&hash_buf, hashes_buf, hashes_cnt, sizeof (hash_t), sort_by_hash, (void *) hashconfig); } potfile_update_hash (hashcat_ctx, found, line_pw_buf, line_pw_len); } hcfree (line_buf); potfile_read_close (hashcat_ctx); if (potfile_ctx->keep_all_hashes == true) { pot_tree_destroy (all_hashes_tree); // this could be slow (should we just skip it?) hcfree (tree_nodes_cache); hcfree (tree_entry_cache); } if (hashconfig->esalt_size > 0) { hcfree (hash_buf.esalt); } if (hashconfig->hook_salt_size > 0) { hcfree (hash_buf.hook_salt); } if (hashconfig->is_salted == true) { hcfree (hash_buf.salt); } hcfree (hash_buf.digest); return 0; } int potfile_handle_show (hashcat_ctx_t *hashcat_ctx) { hashconfig_t *hashconfig = hashcat_ctx->hashconfig; hashes_t *hashes = hashcat_ctx->hashes; potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; hash_t *hashes_buf = hashes->hashes_buf; u32 salts_cnt = hashes->salts_cnt; salt_t *salts_buf = hashes->salts_buf; if (hashconfig->hash_mode == 3000) { for (u32 salt_idx = 0; salt_idx < salts_cnt; salt_idx++) { salt_t *salt_buf = salts_buf + salt_idx; u32 digests_cnt = salt_buf->digests_cnt; for (u32 digest_idx = 0; digest_idx < digests_cnt; digest_idx++) { const u32 hashes_idx = salt_buf->digests_offset + digest_idx; u32 *digests_shown = hashes->digests_shown; hash_t *hash1 = &hashes_buf[hashes_idx]; hash_t *hash2 = NULL; int split_neighbor = -1; // find out if at least one of the parts has been cracked if (hash1->hash_info->split->split_origin == SPLIT_ORIGIN_LEFT) { split_neighbor = hash1->hash_info->split->split_neighbor; hash2 = &hashes_buf[split_neighbor]; if ((digests_shown[hashes_idx] == 0) && (digests_shown[split_neighbor] == 0)) continue; } else if (hash1->hash_info->split->split_origin == SPLIT_ORIGIN_NONE) { if (digests_shown[hashes_idx] == 0) continue; } else { // SPLIT_ORIGIN_RIGHT are not handled this way continue; } u8 *out_buf = potfile_ctx->out_buf; out_buf[0] = 0; ascii_digest (hashcat_ctx, (char *) out_buf + 0, HCBUFSIZ_LARGE - 0, salt_idx, digest_idx); if (hash2) { ascii_digest (hashcat_ctx, (char *) out_buf + 16, HCBUFSIZ_LARGE - 16, salt_idx, split_neighbor); } // user unsigned char *username = NULL; u32 user_len = 0; user_t *user = hash1->hash_info->user; if (user) { username = (unsigned char *) (user->user_name); user_len = user->user_len; username[user_len] = 0; } u8 *tmp_buf = potfile_ctx->tmp_buf; tmp_buf[0] = 0; u8 mixed_buf[20] = { 0 }; u8 mixed_len = 0; if (digests_shown[hashes_idx] == 1) { memcpy (mixed_buf + mixed_len, hash1->pw_buf, hash1->pw_len); mixed_len += hash1->pw_len; } else { memcpy (mixed_buf + mixed_len, LM_MASKED_PLAIN, strlen (LM_MASKED_PLAIN)); mixed_len += strlen (LM_MASKED_PLAIN); } if (hash2) { if (digests_shown[split_neighbor] == 1) { memcpy (mixed_buf + mixed_len, hash2->pw_buf, hash2->pw_len); mixed_len += hash2->pw_len; } else { memcpy (mixed_buf + mixed_len, LM_MASKED_PLAIN, strlen (LM_MASKED_PLAIN)); mixed_len += strlen (LM_MASKED_PLAIN); } } const int tmp_len = outfile_write (hashcat_ctx, (char *) out_buf, (u8 *) mixed_buf, mixed_len, 0, username, user_len, (char *) tmp_buf); EVENT_DATA (EVENT_POTFILE_HASH_SHOW, tmp_buf, tmp_len); } } } else { for (u32 salt_idx = 0; salt_idx < salts_cnt; salt_idx++) { salt_t *salt_buf = salts_buf + salt_idx; u32 digests_cnt = salt_buf->digests_cnt; for (u32 digest_idx = 0; digest_idx < digests_cnt; digest_idx++) { const u32 hashes_idx = salt_buf->digests_offset + digest_idx; u32 *digests_shown = hashes->digests_shown; if (digests_shown[hashes_idx] == 0) continue; hash_t *hash = &hashes_buf[hashes_idx]; u8 *out_buf = potfile_ctx->out_buf; out_buf[0] = 0; ascii_digest (hashcat_ctx, (char *) out_buf, HCBUFSIZ_LARGE, salt_idx, digest_idx); // user unsigned char *username = NULL; u32 user_len = 0; if (hash->hash_info != NULL) { user_t *user = hash->hash_info->user; if (user) { username = (unsigned char *) (user->user_name); user_len = user->user_len; username[user_len] = 0; } } u8 *tmp_buf = potfile_ctx->tmp_buf; tmp_buf[0] = 0; // special case for collider modes: we do not use the $HEX[] format within the hash itself // therefore we need to convert the $HEX[] password into hexadecimal (without "$HEX[" and "]") bool is_collider_hex_password = false; if ((hashconfig->hash_mode == 9710) || (hashconfig->hash_mode == 9810) || (hashconfig->hash_mode == 10410)) { if (is_hexify ((u8 *) hash->pw_buf, hash->pw_len) == true) { is_collider_hex_password = true; } } int tmp_len = 0; if (is_collider_hex_password == true) { u8 pass_unhexified[HCBUFSIZ_TINY] = { 0 }; u32 pass_unhexified_len = 0; pass_unhexified_len = exec_unhexify ((u8 *) hash->pw_buf, hash->pw_len, pass_unhexified, sizeof (pass_unhexified)); tmp_len = outfile_write (hashcat_ctx, (char *) out_buf, pass_unhexified, pass_unhexified_len, 0, username, user_len, (char *) tmp_buf); } else { tmp_len = outfile_write (hashcat_ctx, (char *) out_buf, (u8 *) hash->pw_buf, hash->pw_len, 0, username, user_len, (char *) tmp_buf); } EVENT_DATA (EVENT_POTFILE_HASH_SHOW, tmp_buf, tmp_len); } } } return 0; } int potfile_handle_left (hashcat_ctx_t *hashcat_ctx) { hashconfig_t *hashconfig = hashcat_ctx->hashconfig; hashes_t *hashes = hashcat_ctx->hashes; potfile_ctx_t *potfile_ctx = hashcat_ctx->potfile_ctx; hash_t *hashes_buf = hashes->hashes_buf; u32 salts_cnt = hashes->salts_cnt; salt_t *salts_buf = hashes->salts_buf; if (hashconfig->hash_mode == 3000) { for (u32 salt_idx = 0; salt_idx < salts_cnt; salt_idx++) { salt_t *salt_buf = salts_buf + salt_idx; u32 digests_cnt = salt_buf->digests_cnt; for (u32 digest_idx = 0; digest_idx < digests_cnt; digest_idx++) { const u32 hashes_idx = salt_buf->digests_offset + digest_idx; u32 *digests_shown = hashes->digests_shown; hash_t *hash1 = &hashes_buf[hashes_idx]; hash_t *hash2 = NULL; int split_neighbor = -1; // find out if at least one of the parts has been cracked if (hash1->hash_info->split->split_origin == SPLIT_ORIGIN_LEFT) { split_neighbor = hash1->hash_info->split->split_neighbor; hash2 = &hashes_buf[split_neighbor]; if ((digests_shown[hashes_idx] == 1) && (digests_shown[split_neighbor] == 1)) continue; } else if (hash1->hash_info->split->split_origin == SPLIT_ORIGIN_NONE) { if (digests_shown[hashes_idx] == 1) continue; } else { // SPLIT_ORIGIN_RIGHT are not handled this way continue; } u8 *out_buf = potfile_ctx->out_buf; out_buf[0] = 0; ascii_digest (hashcat_ctx, (char *) out_buf + 0, HCBUFSIZ_LARGE - 0, salt_idx, digest_idx); if (hash2) { ascii_digest (hashcat_ctx, (char *) out_buf + 16, HCBUFSIZ_LARGE - 16, salt_idx, split_neighbor); } // user unsigned char *username = NULL; u32 user_len = 0; user_t *user = hash1->hash_info->user; if (user) { username = (unsigned char *) (user->user_name); user_len = user->user_len; username[user_len] = 0; } u8 *tmp_buf = potfile_ctx->tmp_buf; tmp_buf[0] = 0; const int tmp_len = outfile_write (hashcat_ctx, (char *) out_buf, NULL, 0, 0, username, user_len, (char *) tmp_buf); EVENT_DATA (EVENT_POTFILE_HASH_LEFT, tmp_buf, tmp_len); } } } else { for (u32 salt_idx = 0; salt_idx < salts_cnt; salt_idx++) { salt_t *salt_buf = salts_buf + salt_idx; u32 digests_cnt = salt_buf->digests_cnt; for (u32 digest_idx = 0; digest_idx < digests_cnt; digest_idx++) { const u32 hashes_idx = salt_buf->digests_offset + digest_idx; u32 *digests_shown = hashes->digests_shown; if (digests_shown[hashes_idx] == 1) continue; u8 *out_buf = potfile_ctx->out_buf; out_buf[0] = 0; ascii_digest (hashcat_ctx, (char *) out_buf, HCBUFSIZ_LARGE, salt_idx, digest_idx); hash_t *hash = &hashes_buf[hashes_idx]; // user unsigned char *username = NULL; u32 user_len = 0; if (hash->hash_info != NULL) { user_t *user = hash->hash_info->user; if (user) { username = (unsigned char *) (user->user_name); user_len = user->user_len; username[user_len] = 0; } } u8 *tmp_buf = potfile_ctx->tmp_buf; tmp_buf[0] = 0; const int tmp_len = outfile_write (hashcat_ctx, (char *) out_buf, NULL, 0, 0, username, user_len, (char *) tmp_buf); EVENT_DATA (EVENT_POTFILE_HASH_LEFT, tmp_buf, tmp_len); } } } return 0; }