mirror of
https://github.com/hashcat/hashcat.git
synced 2024-11-25 17:38:23 +00:00
Add module_preprocess_hashlist hook for tests
Some algorithms have ambiguous hashes (e.g. case-insensetive usernames in Net-NTLMv2 hashes). This optional function allows test modules to unify the hashlist before the verification process starts. Also update readme and minor code formatting.
This commit is contained in:
parent
a81a566121
commit
6365672c34
@ -24,7 +24,6 @@ is_in_array ($TYPE, $TYPES) or usage_exit ();
|
||||
|
||||
is_whole ($MODE) or die "Mode must be a number\n";
|
||||
|
||||
my $module = sprintf ("m%05d.pm", $MODE);
|
||||
my $MODULE_FILE = sprintf ("m%05d.pm", $MODE);
|
||||
|
||||
eval { require $MODULE_FILE } or die "Could not load test module: $MODULE_FILE\n$@";
|
||||
@ -98,18 +97,24 @@ sub verify
|
||||
|
||||
open (IN, '<', $hashes_file) or die "$hashes_file: $!\n";
|
||||
|
||||
my $hashlist;
|
||||
my @hashlist;
|
||||
|
||||
while (my $line = <IN>)
|
||||
{
|
||||
$line =~ s/\n$//;
|
||||
$line =~ s/\r$//;
|
||||
|
||||
push (@{$hashlist}, $line);
|
||||
push (@hashlist, $line);
|
||||
}
|
||||
|
||||
close (IN);
|
||||
|
||||
# resolve hash ambiguity if necessary
|
||||
if (exists &{module_preprocess_hashlist})
|
||||
{
|
||||
module_preprocess_hashlist (\@hashlist);
|
||||
}
|
||||
|
||||
open (IN, '<', $cracks_file) or die "$cracks_file: $!\n";
|
||||
open (OUT, '>', $out_file ) or die "$out_file: $!\n";
|
||||
|
||||
@ -124,7 +129,7 @@ sub verify
|
||||
next unless defined $hash;
|
||||
|
||||
# possible if the hash is in cracksfile, but not in hashfile
|
||||
next unless is_in_array ($hash, $hashlist);
|
||||
next unless is_in_array ($hash, \@hashlist);
|
||||
|
||||
print OUT "$line\n";
|
||||
}
|
||||
@ -256,9 +261,11 @@ sub random_numeric_string
|
||||
|
||||
return if ! is_count ($count);
|
||||
|
||||
my @chars = ('0'..'9');
|
||||
|
||||
my $string;
|
||||
|
||||
$string .= sprintf ("%d", rand 10) for (1 .. $count);
|
||||
$string .= $chars[rand @chars] for (1 .. $count);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
@ -8,9 +8,11 @@ During `verify` tests the `module_verify_hash` function must parse the hash:pass
|
||||
|
||||
**Important**: You have to call `pack_if_HEX_notation` as soon as you have parsed the password, or your tests will fail on passwords in the `$HEX[...]` format.
|
||||
|
||||
If the algorithm has ambiguous hashes (e.g. partial case-insensetivity), the test module can provide an optional function `module_preprocess_hashlist`. It recieves a reference to the hashlist array and can unify the hashes in a way that guarantees the match with the output of `module_verify_hash`.
|
||||
|
||||
#### Examples ####
|
||||
|
||||
* For the most basic test modules, see [m00000.pm](m00000.pm) and [m00100.pm](m00100.pm)
|
||||
* For the basic salted hash tests, see [m00110.pm](m00110.pm) and [m00120.pm](m00120.pm)
|
||||
* For some sligthly more complex modules with PBKDF2 and encryption, see [m18400.pm](m18400.pm) and [m18600.pm](m18600.pm)
|
||||
* For a test module with a custom salt generation algorithm, see [m05600.pm](m05600.pm)
|
||||
* For a test module with hashlist preprocessing and a custom salt generation algorithm, see [m05600.pm](m05600.pm)
|
||||
|
@ -17,7 +17,7 @@ sub module_generate_hash
|
||||
|
||||
return if length $word > 27;
|
||||
|
||||
my $hash = md4_hex (encode ("UTF-16LE", $word));
|
||||
my $hash = md4_hex (encode ('UTF-16LE', $word));
|
||||
|
||||
return $hash;
|
||||
}
|
||||
@ -26,7 +26,7 @@ sub module_verify_hash
|
||||
{
|
||||
my $line = shift;
|
||||
|
||||
my ($hash, $word) = split ":", $line;
|
||||
my ($hash, $word) = split (':', $line);
|
||||
|
||||
return unless defined $hash;
|
||||
return unless defined $word;
|
||||
|
@ -24,7 +24,7 @@ sub module_verify_hash
|
||||
{
|
||||
my $line = shift;
|
||||
|
||||
my ($hash, $word) = split ":", $line;
|
||||
my ($hash, $word) = split (':', $line);
|
||||
|
||||
return unless defined $hash;
|
||||
return unless defined $word;
|
||||
|
@ -24,11 +24,11 @@ sub module_generate_hash
|
||||
my $srv_ch = shift // random_hex_string (2*8);
|
||||
my $cli_ch = shift // random_client_challenge ();
|
||||
|
||||
my $b_srv_ch = pack ("H*", $srv_ch);
|
||||
my $b_cli_ch = pack ("H*", $cli_ch);
|
||||
my $b_srv_ch = pack ('H*', $srv_ch);
|
||||
my $b_cli_ch = pack ('H*', $cli_ch);
|
||||
|
||||
my $nthash = Authen::Passphrase::NTHash->new (passphrase => $word)->hash;
|
||||
my $identity = encode ("UTF-16LE", uc ($user) . $domain);
|
||||
my $identity = encode ('UTF-16LE', uc ($user) . $domain);
|
||||
my $hash_buf = hmac_hex ($b_srv_ch . $b_cli_ch, hmac ($identity, $nthash, \&md5, 64), \&md5, 64);
|
||||
|
||||
my $hash = sprintf ("%s::%s:%s:%s:%s", $user, $domain, $srv_ch, $hash_buf, $cli_ch);
|
||||
@ -48,9 +48,9 @@ sub module_verify_hash
|
||||
|
||||
my $hash;
|
||||
|
||||
my $index1 = index ($line, "::");
|
||||
my $index2 = index ($line, ":", $index1 + 2);
|
||||
my $index3 = index ($line, ":", $index2 + 3 + 16 + 32);
|
||||
my $index1 = index ($line, '::');
|
||||
my $index2 = index ($line, ':', $index1 + 2);
|
||||
my $index3 = index ($line, ':', $index2 + 3 + 16 + 32);
|
||||
|
||||
return if $index1 eq -1;
|
||||
return if $index2 eq -1;
|
||||
@ -68,11 +68,28 @@ sub module_verify_hash
|
||||
|
||||
my $new_hash = module_generate_hash ($word, $user, $domain, $srv_ch, $cli_ch);
|
||||
|
||||
return unless lc $new_hash eq lc $hash;
|
||||
# resolve lowercase/uppercase ambiguity in the username
|
||||
# this will also guarantee a match with the preprocessed hashlist
|
||||
$hash = lc $hash;
|
||||
$new_hash = lc $new_hash;
|
||||
|
||||
return unless $new_hash eq $hash;
|
||||
|
||||
return $new_hash;
|
||||
}
|
||||
|
||||
# algorithm is case-insensitive in regard to usernames
|
||||
# hashcat output always is uppercase, while real world hashes are not
|
||||
sub module_preprocess_hashlist
|
||||
{
|
||||
my $hashlist = shift;
|
||||
|
||||
for my $hash (@{$hashlist})
|
||||
{
|
||||
$hash = lc $hash;
|
||||
}
|
||||
}
|
||||
|
||||
sub random_client_challenge
|
||||
{
|
||||
my $ch;
|
||||
|
@ -20,9 +20,9 @@ sub module_generate_hash
|
||||
my $iv = shift // random_hex_string (2*16);
|
||||
my $plain = shift // random_hex_string (2*1024);
|
||||
|
||||
my $b_iv = pack ("H*", $iv);
|
||||
my $b_salt = pack ("H*", $salt);
|
||||
my $b_plain = pack ("H*", $plain);
|
||||
my $b_iv = pack ('H*', $iv);
|
||||
my $b_salt = pack ('H*', $salt);
|
||||
my $b_plain = pack ('H*', $plain);
|
||||
|
||||
my $kdf = Crypt::PBKDF2->new
|
||||
(
|
||||
@ -35,7 +35,7 @@ sub module_generate_hash
|
||||
my $key = $kdf->PBKDF2 ($b_salt, $pass_hash);
|
||||
my $cbc = Crypt::Mode::CBC->new ('AES', 0);
|
||||
my $b_cipher = $cbc->encrypt ($b_plain, $key, $b_iv);
|
||||
my $cipher = unpack ("H*", $b_cipher);
|
||||
my $cipher = unpack ('H*', $b_cipher);
|
||||
my $checksum = sha256_hex ($b_plain);
|
||||
|
||||
my $hash = '$odf$'."*1*1*$iter*32*$checksum*16*$iv*16*$salt*0*$cipher";
|
||||
@ -83,9 +83,9 @@ sub module_verify_hash
|
||||
return unless defined $cipher;
|
||||
|
||||
# decrypt
|
||||
my $b_iv = pack ("H*", $iv);
|
||||
my $b_salt = pack ("H*", $salt);
|
||||
my $b_cipher = pack ("H*", $cipher);
|
||||
my $b_iv = pack ('H*', $iv);
|
||||
my $b_salt = pack ('H*', $salt);
|
||||
my $b_cipher = pack ('H*', $cipher);
|
||||
|
||||
my $kdf = Crypt::PBKDF2->new
|
||||
(
|
||||
@ -98,7 +98,7 @@ sub module_verify_hash
|
||||
my $key = $kdf->PBKDF2 ($b_salt, $pass_hash);
|
||||
my $cbc = Crypt::Mode::CBC->new ('AES', 0);
|
||||
my $b_plain = $cbc->decrypt ($b_cipher, $key, $b_iv);
|
||||
my $plain = unpack ("H*", $b_plain);
|
||||
my $plain = unpack ('H*', $b_plain);
|
||||
|
||||
my $new_hash = module_generate_hash ($word, $salt, $iter, $iv, $plain);
|
||||
|
||||
|
@ -20,9 +20,9 @@ sub module_generate_hash
|
||||
my $iv = shift // random_hex_string (2*8);
|
||||
my $plain = shift // random_hex_string (2*1024);
|
||||
|
||||
my $b_iv = pack ("H*", $iv);
|
||||
my $b_salt = pack ("H*", $salt);
|
||||
my $b_plain = pack ("H*", $plain);
|
||||
my $b_iv = pack ('H*', $iv);
|
||||
my $b_salt = pack ('H*', $salt);
|
||||
my $b_plain = pack ('H*', $plain);
|
||||
|
||||
my $kdf = Crypt::PBKDF2->new
|
||||
(
|
||||
@ -48,7 +48,7 @@ sub module_generate_hash
|
||||
|
||||
$cfb->finish ();
|
||||
|
||||
my $cipher = unpack ("H*", $b_cipher);
|
||||
my $cipher = unpack ('H*', $b_cipher);
|
||||
my $checksum = sha1_hex ($b_plain);
|
||||
|
||||
my $hash = '$odf$'."*0*0*$iter*16*$checksum*8*$iv*16*$salt*0*$cipher";
|
||||
@ -96,9 +96,9 @@ sub module_verify_hash
|
||||
return unless defined $cipher;
|
||||
|
||||
# decrypt
|
||||
my $b_iv = pack ("H*", $iv);
|
||||
my $b_salt = pack ("H*", $salt);
|
||||
my $b_cipher = pack ("H*", $cipher);
|
||||
my $b_iv = pack ('H*', $iv);
|
||||
my $b_salt = pack ('H*', $salt);
|
||||
my $b_cipher = pack ('H*', $cipher);
|
||||
|
||||
my $kdf = Crypt::PBKDF2->new
|
||||
(
|
||||
@ -124,7 +124,7 @@ sub module_verify_hash
|
||||
|
||||
$cfb->finish ();
|
||||
|
||||
my $plain = unpack ("H*", $b_plain);
|
||||
my $plain = unpack ('H*', $b_plain);
|
||||
|
||||
my $new_hash = module_generate_hash ($word, $salt, $iter, $iv, $plain);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user