# A Critical Flaw in Popular Password-Cracking Tool
Hashcat is widely used by security professionals to test password strength and recover lost passwords. A serious flaw has been discovered in how it handles certain password files, specifically those from the old PKZIP compression format.
Here's what's happening: When hashcat reads these password files, it converts hexadecimal data (a special number format) into binary code. But the software doesn't properly check that the data is the right size before processing it. Think of it like a mailbox that doesn't verify a package fits before trying to cram it inside — eventually something breaks.
An attacker could create a specially crafted password file and trick someone into running it through hashcat. Because of this flaw, the malformed data could overflow into other parts of the computer's memory. That overflow could let the attacker run their own code on the victim's machine.
The good news: there's no evidence this is being actively exploited yet, so you have time to respond.
Who's most at risk? Security professionals and IT administrators who regularly use hashcat to audit passwords or conduct penetration testing.
What should you do?
First, if you use hashcat, stop processing any PKZIP hash files from untrusted sources immediately. Second, check the developer's website for an updated version and install it once available. Third, only run hashcat on files you've created yourself or received directly from the organization you're testing — never from random sources online.
This isn't an end-of-the-world scenario, but it's a good reminder why security tools need regular updates just like everything else on your computer.
Want the full technical analysis? Click "Technical" above.
CVE-2026-42484 is a heap-based buffer overflow in hashcat v7.1.2 residing in hex_to_binary(), called from the PKZIP hash module parser. The bug surfaces when hashcat processes hash lines for modules 17200, 17210, 17220, 17225, and 17230. When the parsed data_type_enum field is ≤ 1, the parser decodes attacker-supplied hex data directly into a fixed-size stack or heap buffer without first validating that the hex string length is bounded by the destination capacity. A crafted hash file can overflow the buffer by an arbitrary number of bytes into adjacent heap metadata or heap objects.
CVSS 9.8 (Critical) is justified: the attack is unauthenticated, requires only a crafted hash file passed via the standard CLI or through an automated pipeline, and hashcat is commonly embedded in password-auditing services that accept remote hash submissions.
Affected Component
The vulnerable call chain lives inside hashcat's module dispatch layer:
src/modules/module_17200.c (and _17210, _17220, _17225, _17230)
└─ module_hash_decode()
└─ pkzip_parse_hash() // parses the *pkzip$ format
└─ hex_to_binary() // BUG: no length check on input
All five module files share an identical copy of the PKZIP hash parsing logic — a classic copy-paste vulnerability surface. The shared utility hex_to_binary() lives in src/convert.c and is also used by other modules, but only the PKZIP path reaches it with an unchecked length when data_type_enum ≤ 1.
Root Cause Analysis
The PKZIP hash format encodes file data as a hex string following a structured prefix. The parser extracts the hex portion, allocates a fixed-size destination buffer sized to the expected maximum, then calls hex_to_binary() passing the raw pointer to the hex string — without clamping the conversion length to the buffer capacity.
// src/modules/module_17200.c (reconstructed pseudocode)
#define PKZIP_MAX_DATA_LEN 1024 // 1 KB fixed ceiling for type<=1
typedef struct pkzip_file {
/* +0x000 */ u32 data_type_enum;
/* +0x004 */ u32 magic;
/* +0x008 */ u32 crc32;
/* +0x00c */ u32 compressed_len;
/* +0x010 */ u32 uncompressed_len;
/* +0x014 */ u8 data[PKZIP_MAX_DATA_LEN]; // fixed 1 KB
/* +0x414 */ u32 checksum;
} pkzip_file_t;
int pkzip_parse_hash(const char *input_line, pkzip_file_t *pf)
{
char *pos = strstr(input_line, "*pkzip$");
if (!pos) return PARSER_HASH_LENGTH;
// Parse metadata fields (abbreviated for clarity)
pf->data_type_enum = strtoul(/* field */, NULL, 10);
pf->compressed_len = strtoul(/* field */, NULL, 16);
pf->uncompressed_len = strtoul(/* field */, NULL, 16);
// Locate the hex payload pointer inside the input line
char *hex_payload = /* advance pos past metadata fields */;
size_t hex_len = strnlen(hex_payload, /* remaining line */);
if (pf->data_type_enum <= 1)
{
// BUG: hex_to_binary() converts hex_len/2 bytes into pf->data[].
// pf->data is PKZIP_MAX_DATA_LEN (0x400) bytes, but hex_len is
// derived from attacker-supplied input with no upper-bound clamp.
// A hex string longer than 0x800 hex chars overflows pf->data[].
hex_to_binary(hex_payload, hex_len, pf->data); // BUG: missing bounds check here
}
return PARSER_OK;
}
// src/convert.c (reconstructed pseudocode)
void hex_to_binary(const char *in, size_t in_len, u8 *out)
{
// Converts pairs of hex chars to bytes.
// Writes (in_len / 2) bytes to out — no capacity parameter.
for (size_t i = 0; i < in_len - 1; i += 2)
{
out[i / 2] = (hex_char_to_nibble(in[i]) << 4)
| hex_char_to_nibble(in[i + 1]);
// BUG: out[] capacity is never consulted; i/2 can exceed 0x3FF
}
}
Root cause:hex_to_binary() accepts no capacity parameter and writes in_len/2 bytes unconditionally, while the PKZIP parser passes an attacker-controlled in_len without clamping it to sizeof(pkzip_file_t.data) (0x400 bytes).
Memory Layout
hashcat allocates pkzip_file_t structures on the heap inside hashes_init_stage1(). In a typical 64-bit glibc run, the allocator places successive hash structures contiguously. The overflow walks from the end of pf->data[] through pf->checksum and into the next heap chunk.
Full exploitation requires bypassing glibc heap metadata integrity checks (safe-linking, tcache key validation). On targets without those mitigations — embedded toolchains shipping hashcat, older musl-libc builds, or Windows builds using hashcat's bundled allocator — exploitation is more direct.
EXPLOIT CHAIN:
1. Craft a malicious PKZIP hash file:
- Set data_type_enum = 0 or 1 (triggers the vulnerable branch)
- Set compressed_len to a plausible small value (evades early length checks)
- Supply a hex payload of 0x1000+ hex characters (→ 0x800+ decoded bytes)
overflowing 0x400 bytes past the end of pf->data[]
2. Feed the hash file to hashcat:
$ hashcat -m 17200 crafted.hash /dev/null
Parsing triggers pkzip_parse_hash() -> hex_to_binary() overflow.
3. Overflow glibc chunk header of pkzip_file_t #1:
- Write fake size field: satisfies IS_MMAPPED / PREV_INUSE constraints
- Write fake fd/bk pointers into tcache or unsorted-bin free list
4. Trigger heap consolidation:
- hashcat's hash deduplication frees duplicate pkzip_file_t entries.
- free() on the corrupted chunk walks the corrupted size field.
- On musl / no-tcache builds: unlink() writes fd into bk->fd,
pivoting a write-what-where primitive.
5. Overwrite a function pointer:
- Target: hashcat's OpenCL dispatch table (cl_function_table_t*),
allocated immediately after hash structures in the same arena.
- Corrupt clEnqueueNDRangeKernel pointer → shellcode / one-gadget.
6. Shellcode executes in the hashcat process context when the first
kernel dispatch is attempted after hash loading completes.
DENIAL-OF-SERVICE (reliable, no mitigations required):
- Any overflow of the glibc chunk size field triggers abort() via
malloc_printerr() in the next allocation after hash parsing:
*** glibc detected *** hashcat: corrupted size vs. prev_size
Patch Analysis
The correct fix requires two coordinated changes: adding a capacity parameter to hex_to_binary(), and clamping the decoded length inside pkzip_parse_hash() before the call.
// BEFORE (vulnerable) — src/convert.c:
void hex_to_binary(const char *in, size_t in_len, u8 *out)
{
for (size_t i = 0; i < in_len - 1; i += 2)
out[i / 2] = (hex_char_to_nibble(in[i]) << 4)
| hex_char_to_nibble(in[i + 1]);
}
// BEFORE (vulnerable) — src/modules/module_17200.c:
if (pf->data_type_enum <= 1)
hex_to_binary(hex_payload, hex_len, pf->data);
// AFTER (patched):
// src/convert.c — add out_capacity parameter:
int hex_to_binary_safe(const char *in, size_t in_len,
u8 *out, size_t out_capacity)
{
size_t out_len = in_len / 2;
if (out_len > out_capacity) return -1; // reject oversized input
for (size_t i = 0; i < in_len - 1; i += 2)
out[i / 2] = (hex_char_to_nibble(in[i]) << 4)
| hex_char_to_nibble(in[i + 1]);
return 0;
}
// src/modules/module_17200.c (and 17210/17220/17225/17230):
if (pf->data_type_enum <= 1)
{
// Clamp hex_len to what the fixed data[] buffer can hold
if (hex_len > PKZIP_MAX_DATA_LEN * 2) // 0x800 hex chars max
return PARSER_HASH_LENGTH; // reject malformed input early
if (hex_to_binary_safe(hex_payload, hex_len,
pf->data, sizeof(pf->data)) != 0)
return PARSER_HASH_LENGTH;
}
The secondary hardening is the early-rejection PARSER_HASH_LENGTH return before the allocation is even used, ensuring the parser never reaches hex_to_binary_safe() with a length that would require the capacity guard — defense in depth across both the caller and callee.
Detection and Indicators
Runtime crash signatures: A reliable DoS trigger produces one of the following on glibc systems:
- Mode 17200/17210/17220/17225/17230 hash lines where the hex data field
length (character count between colons) exceeds 0x800 characters
- data_type_enum field = 0 or 1 with anomalously long trailing hex segment
- Hex payload containing non-hex characters padded with 0x41 ('A') runs
(indicates fuzzer or PoC tooling)
Static detection rule (YARA):
rule CVE_2026_42484_pkzip_overflow {
strings:
// *pkzip$ followed by type<=1 field, then >2048 hex chars
$pkzip_long = /\*pkzip\$[0-9a-f]+\*[01]\*[0-9a-f]{2049,}/
condition:
$pkzip_long
}
Remediation
Immediate: Upgrade to a patched build of hashcat once a fixed release is published. Monitor the official hashcat GitHub repository for a tagged release addressing CVE-2026-42484.
Operational mitigations until patched:
Validate hash files with a pre-flight script that rejects any PKZIP hash line (-m 17200/17210/17220/17225/17230) where the hex data segment exceeds 2048 characters before passing to hashcat.
Run hashcat inside a sandboxed environment (seccomp-bpf, Bubblewrap, or firejail) that restricts exec and outbound network syscalls to contain post-exploitation impact.
If PKZIP cracking (modes 17200–17230) is not operationally required, block those modes via a wrapper script that rejects -m 172{0,1,2}* arguments.
On shared cracking infrastructure accepting user-submitted hash files, treat all submitted PKZIP hashes as untrusted and apply the YARA rule above at ingestion time.