mirror of
https://github.com/hashcat/hashcat.git
synced 2025-07-14 10:38:18 +00:00

I tried to keep much of the hash extraction code the same. The main changes are it detects the file encoding to deal with ASCII vs. UTF16-LE, it strips out any header info in the registry dump, and then it breaks up the registry for each radmin3 user so that it can then loop through them to generate the hash.
342 lines
9.6 KiB
Perl
Executable File
342 lines
9.6 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
|
|
##
|
|
## Author......: See docs/credits.txt
|
|
## License.....: MIT
|
|
##
|
|
|
|
# for this hashcat extraction tool the input should be a export/dump of the registry key
|
|
# [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Radmin\v3.0\Server\Parameters\Radmin Security\1]
|
|
#
|
|
# "reg export" cmd command can be used for this:
|
|
# reg export "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Radmin\v3.0\Server\Parameters\Radmin Security\1" radmin3_export.reg
|
|
#
|
|
# Note: this tool is intentionally not designed to do an automatic registry key read
|
|
# but this could be done easily also in software/perl:
|
|
# use Win32::TieRegistry (Delimiter => '/');
|
|
# my $reg_key = $Registry->{'HKEY_LOCAL_MACHINE/SOFTWARE/WOW6432Node/Radmin/v3.0/Server/Parameters/Radmin Security'};
|
|
# my $file_content = $reg_key->{'/1'};
|
|
#
|
|
# An example input file (first command line parameter):
|
|
#
|
|
# [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Radmin\v3.0\Server\Parameters\Radmin Security\1]
|
|
# "1"=hex:10,00,00,0a,72,00,6f,00,67,00,65,00,72,00,30,00,01,00,98,47,fc,7e,0f,\
|
|
# 89,1d,fd,5d,02,f1,9d,58,7d,8f,77,ae,c0,b9,80,d4,30,4b,01,13,b4,06,f2,3e,2c,\
|
|
# ec,58,ca,fc,a0,4a,53,e3,6f,b6,8e,0c,3b,ff,92,cf,33,57,86,b0,db,e6,0d,fe,41,\
|
|
# 78,ef,2f,cd,2a,4d,d0,99,47,ff,d8,df,96,fd,0f,9e,29,81,a3,2d,a9,55,03,34,2e,\
|
|
# ca,9f,08,06,2c,bd,d4,ac,2d,7c,df,81,0d,b4,db,96,db,70,10,22,66,26,1c,d3,f8,\
|
|
# bd,d5,6a,10,2f,c6,ce,ed,bb,a5,ea,e9,9e,61,27,bd,d9,52,f7,a0,d1,8a,79,02,1c,\
|
|
# 88,1a,e6,3e,c4,b3,59,03,87,f5,48,59,8f,2c,b8,f9,0d,ea,36,fc,4f,80,c5,47,3f,\
|
|
# db,6b,0c,6b,db,0f,db,af,46,01,f5,60,dd,14,91,67,ea,12,5d,b8,ad,34,fd,0f,d4,\
|
|
# 53,50,de,c7,2c,fb,3b,52,8b,a2,33,2d,60,91,ac,ea,89,df,d0,6c,9c,4d,18,f6,97,\
|
|
# 24,5b,d2,ac,92,78,b9,2b,fe,7d,ba,fa,a0,c4,3b,40,a7,1f,19,30,eb,c4,fd,24,c9,\
|
|
# e5,a2,e5,a4,cc,f5,d7,f5,15,44,d7,0b,2b,ca,4a,f5,b8,d3,7b,37,9f,d7,74,0a,68,\
|
|
# 2f,40,00,00,01,05,50,00,00,20,f9,89,48,2b,a8,3b,63,45,fd,1d,d7,e2,13,13,dc,\
|
|
# d5,55,22,ba,57,15,b5,79,ea,b8,74,d7,64,33,92,8d,72,60,00,01,00,01,2a,1b,fd,\
|
|
# 53,4a,88,d9,19,40,70,e6,1e,76,07,fd,69,90,94,ea,b6,3b,53,b2,76,6b,0c,f3,5e,\
|
|
# 73,fb,cc,21,41,ae,d3,28,1f,64,ca,62,0b,27,95,1c,f5,e2,c2,78,60,37,54,27,5f,\
|
|
# c1,63,51,ee,f0,8f,bb,e3,0c,f5,d9,27,be,c5,61,e5,ea,98,a6,df,a1,ee,e9,00,4b,\
|
|
# 00,83,4f,d9,ca,d5,ae,59,1e,ef,4f,c8,8b,f9,73,75,04,d2,9e,c5,93,34,6c,cd,1d,\
|
|
# 76,18,82,37,73,8e,0b,6e,8a,f8,47,ef,4a,74,a9,a4,d9,df,04,8d,5d,6b,f2,19,c7,\
|
|
# ab,f5,40,72,00,c3,5d,3c,dc,d5,e7,e2,c6,51,fe,0d,77,bc,60,41,e1,51,96,46,f5,\
|
|
# 8b,1c,cc,a2,11,1a,37,25,86,6b,be,2b,60,4f,9d,17,2f,28,53,9a,97,5d,1d,0f,99,\
|
|
# 7e,4c,d2,8c,49,7f,ad,62,a7,90,e7,35,2f,19,40,1e,fb,7d,7f,b6,ba,cb,85,e0,67,\
|
|
# 4e,ab,03,1d,78,2f,a0,e7,3d,8e,b4,b4,0a,c6,ee,cc,a8,d9,87,fd,b9,0c,c1,01,54,\
|
|
# a5,39,6a,26,7c,69,cb,47,68,c3,a6,43,59,12,bb,b6,0d,68,91,d2,1b,de,bc,da,0f,\
|
|
# 0a,b5,20,00,00,04,ff,01,00,00
|
|
|
|
use strict;
|
|
use warnings;
|
|
use utf8;
|
|
use Encode;
|
|
use Encode::Guess;
|
|
|
|
|
|
#
|
|
# Constants:
|
|
#
|
|
|
|
my $REGISTRY_PREFIX = "=hex:";
|
|
|
|
my $ENTRY_KEY_USER = 16;
|
|
my $ENTRY_KEY_MODULUS = 48;
|
|
my $ENTRY_KEY_GENERATOR = 64;
|
|
my $ENTRY_KEY_SALT = 80;
|
|
my $ENTRY_KEY_VERIFIER = 96;
|
|
|
|
my $HARD_CODED_GENERATOR = "05";
|
|
my $HARD_CODED_MODULUS = "9847fc7e0f891dfd5d02f19d587d8f77aec0b980d4304b0113b406f23e2cec58cafca04a53e36fb68e0c3bff92cf335786b0dbe60dfe4178ef2fcd2a4dd09947ffd8df96fd0f9e2981a32da95503342eca9f08062cbdd4ac2d7cdf810db4db96db70102266261cd3f8bdd56a102fc6ceedbba5eae99e6127bdd952f7a0d18a79021c881ae63ec4b3590387f548598f2cb8f90dea36fc4f80c5473fdb6b0c6bdb0fdbaf4601f560dd149167ea125db8ad34fd0fd45350dec72cfb3b528ba2332d6091acea89dfd06c9c4d18f697245bd2ac9278b92bfe7dbafaa0c43b40a71f1930ebc4fd24c9e5a2e5a4ccf5d7f51544d70b2bca4af5b8d37b379fd7740a682f";
|
|
|
|
|
|
#
|
|
# Start:
|
|
#
|
|
|
|
if (scalar (@ARGV) < 1)
|
|
{
|
|
print STDERR "Usage:\n" . $0 . " <radmin3.reg>\n\n";
|
|
print STDERR "Please specify the Radmin 3 registry export file as command line parameter\n\n";
|
|
print STDERR "The registry key is something like:\n";
|
|
print STDERR "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Radmin\\v3.0\\Server\\Parameters\\Radmin Security\\1\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
my $file_name = $ARGV[0];
|
|
|
|
my $fh;
|
|
|
|
if (! open ($fh, "<", $file_name))
|
|
{
|
|
print STDERR "ERROR: Could not open the registry dump file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
binmode ($fh);
|
|
|
|
# Strip out any leading info from the registry file or the registry dumping program
|
|
# Then break up the registry keys into an array so each one can be processed if there are multiple
|
|
# Radmin users
|
|
my @sections;
|
|
my $current_section = '';
|
|
|
|
{
|
|
local $/; # Enable slurp mode
|
|
my $file_info = <$fh>;
|
|
|
|
# Registry dumps are often UTF-16LE, but some programs might dump
|
|
# it as a different format
|
|
my $enc = guess_encoding($file_info, qw/ ascii cp1252 iso-8859-1 utf-8 UTF-16LE /);
|
|
|
|
# Decode using the encoding detected
|
|
$file_info = decode($enc->name, $file_info);
|
|
|
|
# Split lines, handling both Unix and Windows line endings
|
|
my @lines = split /\r?\n/, $file_info;
|
|
|
|
# Read the file line by line
|
|
foreach my $line (@lines) {
|
|
chomp $line;
|
|
|
|
# Check if the line is a section header
|
|
if ($line =~ /^\[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Radmin\\v3\.0\\Server\\Parameters\\Radmin Security\\/) {
|
|
# If we already have a section, push it to the array
|
|
if ($current_section) {
|
|
push @sections, $current_section;
|
|
}
|
|
|
|
# Start a new section with the header
|
|
$current_section = "$line\n";
|
|
}
|
|
elsif ($current_section) {
|
|
# If we are in a section, continue adding lines to it
|
|
if ($line =~ /^\[.*\]$/) {
|
|
# New section starts, save the current one
|
|
push @sections, $current_section;
|
|
$current_section = '';
|
|
} else {
|
|
# Add data to the current section
|
|
$current_section .= "$line\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Push the last section if there was one
|
|
if ($current_section) {
|
|
push @sections, $current_section;
|
|
}
|
|
close $fh;
|
|
|
|
if (!@sections) {
|
|
print STDERR "ERROR: Did not find any Radmin users in the file'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
# Loop over the data
|
|
my $file_content = '';
|
|
while($file_content=shift(@sections)) {
|
|
|
|
if (length ($file_content) < 5 + 0) # replace 0 with minimum expected length
|
|
{
|
|
print STDERR "ERROR: File size of file '$file_name' is invalid\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
$file_content =~ s/[\x00]//g; # this could be true if UTF16 + BOM are being used
|
|
|
|
my $prefix_idx = index ($file_content, $REGISTRY_PREFIX);
|
|
|
|
if ($prefix_idx < 0)
|
|
{
|
|
print STDERR "ERROR: Could not find the key '=hex:' within the file content\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
$file_content = substr ($file_content, $prefix_idx + length ($REGISTRY_PREFIX));
|
|
|
|
# $file_content =~ s/[ \r\n,\\]//g;
|
|
|
|
# we could also remove every character that is not an hexadecimal symbol:
|
|
$file_content =~ s/[^0-9a-fA-F]//g;
|
|
|
|
$file_content = pack ("H*", $file_content);
|
|
|
|
|
|
# final length check (needed ?):
|
|
|
|
my $file_content_len = length ($file_content);
|
|
|
|
if ($file_content_len < 2 + 1 + 2 + 1 + 2 + 32 + 2 + 256 + 2 + 256) # replace with min length
|
|
{
|
|
print STDERR "ERROR: File content of file '$file_name' is too short\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
my $user = "";
|
|
my $salt = "";
|
|
my $verifier = "";
|
|
|
|
my $found_user = 0;
|
|
my $found_modulus = 0;
|
|
my $found_generator = 0;
|
|
my $found_salt = 0;
|
|
my $found_verifier = 0;
|
|
|
|
for (my $i = 0; $i < $file_content_len; $i += 4)
|
|
{
|
|
if ($i + 4 > $file_content_len)
|
|
{
|
|
print STDERR "ERROR: Unexpected EOF (end of file) in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
my $type = ord (substr ($file_content, $i + 1, 1)) * 256 +
|
|
ord (substr ($file_content, $i + 0, 1));
|
|
my $len = ord (substr ($file_content, $i + 2, 1)) * 256 +
|
|
ord (substr ($file_content, $i + 3, 1));
|
|
|
|
my $pos = $i + 4;
|
|
|
|
$i += $len;
|
|
|
|
# we are not interested in other values than what we need:
|
|
|
|
if (($type != $ENTRY_KEY_USER) &&
|
|
($type != $ENTRY_KEY_MODULUS) &&
|
|
($type != $ENTRY_KEY_GENERATOR) &&
|
|
($type != $ENTRY_KEY_SALT) &&
|
|
($type != $ENTRY_KEY_VERIFIER))
|
|
{
|
|
next;
|
|
}
|
|
|
|
if ($i > $file_content_len)
|
|
{
|
|
print STDERR "ERROR: Unexpected EOF (end of file) in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
|
|
#
|
|
# get the data, finally:
|
|
#
|
|
|
|
my $value = substr ($file_content, $pos, $len);
|
|
|
|
$value = unpack ("H*", $value);
|
|
|
|
if ($type == $ENTRY_KEY_USER)
|
|
{
|
|
$user = $value;
|
|
|
|
$found_user = 1;
|
|
}
|
|
elsif ($type == $ENTRY_KEY_MODULUS)
|
|
{
|
|
if ($value ne $HARD_CODED_MODULUS)
|
|
{
|
|
print STDERR "ERROR: Non-default modulus found in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
$found_modulus = 1;
|
|
}
|
|
elsif ($type == $ENTRY_KEY_GENERATOR)
|
|
{
|
|
if ($value ne $HARD_CODED_GENERATOR)
|
|
{
|
|
print STDERR "ERROR: Non-default generator found in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
$found_generator = 1;
|
|
}
|
|
elsif ($type == $ENTRY_KEY_SALT)
|
|
{
|
|
$salt = $value;
|
|
|
|
$found_salt = 1;
|
|
}
|
|
elsif ($type == $ENTRY_KEY_VERIFIER)
|
|
{
|
|
$verifier = $value;
|
|
|
|
$found_verifier = 1;
|
|
}
|
|
}
|
|
|
|
if ($found_user == 0)
|
|
{
|
|
print STDERR "ERROR: No user name found in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
if ($found_modulus == 0)
|
|
{
|
|
print STDERR "ERROR: No modulus found in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
if ($found_generator == 0)
|
|
{
|
|
print STDERR "ERROR: No generator found in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
if ($found_salt == 0)
|
|
{
|
|
print STDERR "ERROR: No salt found in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
if ($found_verifier == 0)
|
|
{
|
|
print STDERR "ERROR: No verifier found in file '$file_name'\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
|
|
#
|
|
# Output:
|
|
#
|
|
|
|
print sprintf ("\$radmin3\$%s*%s*%s\n",
|
|
$user,
|
|
$salt,
|
|
$verifier);
|
|
} |