mirror of
https://github.com/hashcat/hashcat.git
synced 2024-11-23 00:28:11 +00:00
Merge pull request #1835 from Naufragous/test-modules
Add test modules and helper functions
This commit is contained in:
commit
8caffbe6d8
@ -8,7 +8,7 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Data::Types qw (is_count is_whole);
|
||||
use Data::Types qw (is_count is_int is_whole);
|
||||
use File::Basename;
|
||||
use FindBin;
|
||||
|
||||
@ -25,8 +25,9 @@ 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; } or die "Could not load test module: $module\n$@";
|
||||
eval { require $MODULE_FILE } or die "Could not load test module: $MODULE_FILE\n$@";
|
||||
|
||||
exists &{module_generate_hash} or die "Module function 'module_generate_hash' not found\n";
|
||||
exists &{module_verify_hash} or die "Module function 'module_verify_hash' not found\n";
|
||||
@ -54,18 +55,21 @@ sub single
|
||||
{
|
||||
my $len = shift;
|
||||
|
||||
# fallback to incrementing length
|
||||
undef $len unless is_count ($len);
|
||||
|
||||
my $format = "echo -n %-32s | ./hashcat \${OPTS} -a 0 -m %d '%s'\n";
|
||||
|
||||
for (my $i = 1; $i <= 32; $i++)
|
||||
{
|
||||
# requested or incrementing length
|
||||
my $cur_len = $len // $i;
|
||||
|
||||
my $word = random_numeric_string ($cur_len);
|
||||
|
||||
my $hash = module_generate_hash ($word);
|
||||
|
||||
# possible if the requested length is not supported by algorithm
|
||||
next unless defined $hash;
|
||||
|
||||
print sprintf ($format, $word, $MODE, $hash);
|
||||
@ -116,8 +120,10 @@ sub verify
|
||||
|
||||
my $hash = module_verify_hash ($line);
|
||||
|
||||
# possible if the hash:password pair does not match
|
||||
next unless defined $hash;
|
||||
|
||||
# possible if the hash is in cracksfile, but not in hashfile
|
||||
next unless is_in_array ($hash, $hashlist);
|
||||
|
||||
print OUT "$line\n";
|
||||
@ -138,6 +144,7 @@ sub is_in_array
|
||||
return grep { $_ eq $value } @{$array};
|
||||
}
|
||||
|
||||
# detect hashcat $HEX[...] notation and pack as binary
|
||||
sub pack_if_HEX_notation
|
||||
{
|
||||
my $string = shift;
|
||||
@ -152,8 +159,33 @@ sub pack_if_HEX_notation
|
||||
return $string;
|
||||
}
|
||||
|
||||
# random_count (max)
|
||||
# returns integer from 1 to max
|
||||
sub random_count
|
||||
{
|
||||
my $max = shift;
|
||||
|
||||
return unless is_count $max;
|
||||
|
||||
return int ((rand ($max - 1)) + 1);
|
||||
}
|
||||
|
||||
# random_number (min, max)
|
||||
sub random_number
|
||||
{
|
||||
my $min = shift;
|
||||
my $max = shift;
|
||||
|
||||
return unless is_int ($min);
|
||||
return unless is_int ($max);
|
||||
return unless $min lt $max;
|
||||
|
||||
return int ((rand ($max - $min)) + $min);
|
||||
}
|
||||
|
||||
sub random_bytes
|
||||
{
|
||||
# length in bytes
|
||||
my $count = shift;
|
||||
|
||||
return pack ("H*", random_hex_string (2 * $count));
|
||||
@ -161,6 +193,7 @@ sub random_bytes
|
||||
|
||||
sub random_hex_string
|
||||
{
|
||||
# length in characters
|
||||
my $count = shift;
|
||||
|
||||
return if ! is_count ($count);
|
||||
@ -172,6 +205,51 @@ sub random_hex_string
|
||||
return $string;
|
||||
}
|
||||
|
||||
sub random_lowercase_string
|
||||
{
|
||||
my $count = shift;
|
||||
|
||||
return if ! is_count ($count);
|
||||
|
||||
my @chars = ('a'..'z');
|
||||
|
||||
my $string;
|
||||
|
||||
$string .= $chars[rand @chars] for (1 .. $count);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
sub random_uppercase_string
|
||||
{
|
||||
my $count = shift;
|
||||
|
||||
return if ! is_count ($count);
|
||||
|
||||
my @chars = ('A'..'Z');
|
||||
|
||||
my $string;
|
||||
|
||||
$string .= $chars[rand @chars] for (1 .. $count);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
sub random_mixedcase_string
|
||||
{
|
||||
my $count = shift;
|
||||
|
||||
return if ! is_count ($count);
|
||||
|
||||
my @chars = ('A'..'Z', 'a'..'z');
|
||||
|
||||
my $string;
|
||||
|
||||
$string .= $chars[rand @chars] for (1 .. $count);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
sub random_numeric_string
|
||||
{
|
||||
my $count = shift;
|
||||
@ -185,6 +263,21 @@ sub random_numeric_string
|
||||
return $string;
|
||||
}
|
||||
|
||||
sub random_string
|
||||
{
|
||||
my $count = shift;
|
||||
|
||||
return if ! is_count ($count);
|
||||
|
||||
my @chars = ('A'..'Z', 'a'..'z', '0'..'9');
|
||||
|
||||
my $string;
|
||||
|
||||
$string .= $chars[rand @chars] for (1 .. $count);
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
sub usage_exit
|
||||
{
|
||||
my $f = basename ($0);
|
||||
|
@ -1,15 +1,16 @@
|
||||
### Hashcat test modules ###
|
||||
|
||||
Each module provides the two functions `module_generate_hash` and `module_verify_hash`. The first parameter to `module_generate_hash` is the password, which can be either in ASCII or binary (packed) form. The `module_verify_hash` function accepts a line from the cracks file, without the newline characters.
|
||||
Each module provides the functions `module_generate_hash` and `module_verify_hash`. The first parameter to `module_generate_hash` is the password, which can be either in ASCII or binary (packed) form. The `module_verify_hash` function accepts a line from the cracks file, without the newline characters.
|
||||
|
||||
During `single` and `passthrough` tests the `module_generate_hash` function must provide random values (e.g. salt) for hash generation if necessary. The test.pl script offers a few handy functions like `random_hex_string`, `random_numeric_string` and `random_bytes`. You can implement your own salt generation functions, if your mode has specific requirements.
|
||||
|
||||
During `verify` tests the `module_verify_hash` function must parse the hash:password line and to calculate a hash by passing all necessary data to `module_generate_hash`. How you pass it is up to you, as long as the first parameter is the password.
|
||||
During `verify` tests the `module_verify_hash` function must parse the hash:password line and calculate a hash by passing all necessary data to `module_generate_hash`. How you pass it is up to you, as long as the first parameter is the password.
|
||||
|
||||
**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.
|
||||
|
||||
#### Examples ####
|
||||
|
||||
* For the most basic test modules, see [m0.pm](m0.pm) and [m100.pm](m100.pm)
|
||||
* For the basic salted hash tests, see [m110.pm](m110.pm) and [m120.pm](m120.pm)
|
||||
* 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)
|
||||
|
@ -23,7 +23,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;
|
||||
|
@ -23,7 +23,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;
|
||||
|
@ -13,7 +13,7 @@ use Digest::SHA qw (sha1_hex);
|
||||
sub module_generate_hash
|
||||
{
|
||||
my $word = shift;
|
||||
my $salt = shift // random_numeric_string (int (rand 16));
|
||||
my $salt = shift // random_numeric_string (random_count (15));
|
||||
|
||||
my $hash = sha1_hex ($word . $salt) . ":$salt";
|
||||
|
||||
@ -24,7 +24,7 @@ sub module_verify_hash
|
||||
{
|
||||
my $line = shift;
|
||||
|
||||
my ($hash, $salt, $word) = split (":", $line);
|
||||
my ($hash, $salt, $word) = split (':', $line);
|
||||
|
||||
return unless defined $hash;
|
||||
return unless defined $salt;
|
||||
|
@ -13,7 +13,7 @@ use Digest::SHA qw (sha1_hex);
|
||||
sub module_generate_hash
|
||||
{
|
||||
my $word = shift;
|
||||
my $salt = shift // random_numeric_string (int (rand 16));
|
||||
my $salt = shift // random_numeric_string (random_count (15));
|
||||
|
||||
my $hash = sha1_hex ($salt . $word) . ":$salt";
|
||||
|
||||
@ -24,7 +24,7 @@ sub module_verify_hash
|
||||
{
|
||||
my $line = shift;
|
||||
|
||||
my ($hash, $salt, $word) = split (":", $line);
|
||||
my ($hash, $salt, $word) = split (':', $line);
|
||||
|
||||
return unless defined $hash;
|
||||
return unless defined $salt;
|
||||
|
89
tools/test_modules/m05600.pm
Normal file
89
tools/test_modules/m05600.pm
Normal file
@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
##
|
||||
## Author......: See docs/credits.txt
|
||||
## License.....: MIT
|
||||
##
|
||||
|
||||
use strict;
|
||||
|
||||
use Authen::Passphrase::NTHash;
|
||||
use Digest::HMAC qw (hmac hmac_hex);
|
||||
use Digest::MD5 qw (md5);
|
||||
use Encode qw (encode);
|
||||
|
||||
sub module_generate_hash
|
||||
{
|
||||
my $word = shift;
|
||||
|
||||
my $user_len = random_number (0, 27);
|
||||
my $domain_len = 27 - $user_len;
|
||||
|
||||
my $user = shift // random_string ($user_len);
|
||||
my $domain = shift // random_string ($domain_len);
|
||||
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 $nthash = Authen::Passphrase::NTHash->new (passphrase => $word)->hash;
|
||||
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);
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
sub module_verify_hash
|
||||
{
|
||||
my $line = shift;
|
||||
|
||||
my $user;
|
||||
my $domain;
|
||||
my $srv_ch;
|
||||
my $cli_ch;
|
||||
my $word;
|
||||
|
||||
my $hash;
|
||||
|
||||
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;
|
||||
return if $index3 eq -1;
|
||||
|
||||
$hash = substr ($line, 0, $index3);
|
||||
|
||||
$user = substr ($line, 0, $index1);
|
||||
$domain = substr ($line, $index1 + 2, $index2 - $index1 - 2);
|
||||
$srv_ch = substr ($line, $index2 + 1, 16);
|
||||
$cli_ch = substr ($line, $index2 + 3 + 16 + 32, $index3 - $index2 - 3 - 16 - 32);
|
||||
$word = substr ($line, $index3 + 1);
|
||||
|
||||
$word = pack_if_HEX_notation ($word);
|
||||
|
||||
my $new_hash = module_generate_hash ($word, $user, $domain, $srv_ch, $cli_ch);
|
||||
|
||||
return unless lc $new_hash eq lc $hash;
|
||||
|
||||
return $new_hash;
|
||||
}
|
||||
|
||||
sub random_client_challenge
|
||||
{
|
||||
my $ch;
|
||||
|
||||
$ch .= '0101000000000000';
|
||||
$ch .= random_hex_string (2*16);
|
||||
$ch .= '00000000';
|
||||
$ch .= random_hex_string(2 * random_count (20));
|
||||
$ch .= '00';
|
||||
|
||||
return $ch;
|
||||
}
|
||||
|
||||
1;
|
@ -47,7 +47,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;
|
||||
|
@ -60,7 +60,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;
|
||||
|
Loading…
Reference in New Issue
Block a user