Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 263 lines (223 sloc) 9.658 kb
#!/usr/bin/perl
#
#####################################################################
#
# Written by JoMo-Kun <jmk at foofus.net> in 2007
# and placed in the public domain.
#
# The purpose of this script is to aid with cracking a LM/NTLM
# challenge/response set, when part of the password is known. It
# was written with John's NetLM/NetNTLM formats and "halflmchall"
# Rainbow Tables in mind.
#
# Example Scenario:
# Let's assume you've captured LM/NTLM challenge/response set for
# the password Cricket88!. You may be able to crack the first part
# (i.e. CRICKET) using "Half LM" Rainbow Tables. This script will
# use that value as a seed and attempt to crack the second part
# (i.e. "88!") via an incremental brute. It'll then use the NetNTLM
# response hash to crack the case-sensitive version of the entire
# password.
#
#####################################################################
use Getopt::Long;
my $VERSION = "0.2";
my %opt;
my %data;
my $JOHN = "john";
GetOptions (
'seed=s' => \$opt{'seed'},
'file=s' => \$opt{'file'},
'help|h' => sub { ShowUsage(); },
);
sub showUsage {
print "john-netntlm.pl v$VERSION\n\n";
print "JoMo-Kun <jmk\@foofus.net>\n\n";
print "Usage: $0 [OPTIONS]\n";
print " $0\n";
print " --seed [RainbowCrack/HalfLM Response Password]\n";
print " --file [File Containing LM/NTLM challenge/responses (.lc format)]\n";
print " Ex: Domain\\User:::LM response:NTLM response:challenge";
print "\n";
print " Ex:\n";
print " $0 --file capture.lc\n";
print " $0 --seed \"GERGE!!\"--file capture.lc\n";
print "\n";
exit(1);
}
# Main
{
if ( !defined($opt{'file'}) ) { &showUsage; }
# Parse accounts to audit
open(HAND, $opt{'file'}) || die("Failed to open response file: $opt{'file'} -- $!");
@{ $data{'pairs'} } = <HAND>;
close(HAND);
# Load information for any accounts previous cracked
print STDERR "\n\n";
print STDERR "###########################################################################################\n";
open (HAND, "$JOHN -format:netlm -show $opt{'file'} |") || die("Failed to execute john: $!");
print STDERR "The following LM responses have been previously cracked:\n";
while(<HAND>) {
next if ( /\d+ password hashes cracked, \d+ left/ );
last if /^$/;
print "\t$_";
push @{ $data{'cracked-lm'} }, $_;
}
close(HAND);
print STDERR "\nThe following NTLM responses have been previously cracked:\n";
open (HAND, "$JOHN -format:netntlm -show $opt{'file'} |") || die("Failed to execute john: $!");
while(<HAND>) {
next if ( /\d+ password hashes cracked, \d+ left/ );
last if /^$/;
print "\t$_";
push @{ $data{'cracked-ntlm'} }, $_;
}
close(HAND);
mkdir("/tmp/john.$$") || die;
my $tmpconf = &createConf();
my $tmpsession = "/tmp/john.$$/john.session";
my $tmpsessionlog = "/tmp/john.$$/john.session.log";
my $tmplog = "/tmp/john.$$/john.log";
#print STDERR "Created temporary configuration file: $tmpconf\n";
# Crack case-sensitive version of password
my $tmpdict = "/tmp/john.$$/john.dict";
#print STDERR "Created temporary dictionary file: $tmpdict\n";
foreach $credential_set ( @{ $data{'cracked-lm'} } ) {
my ($account,$lmpass,$bar,$netlm,$netntlm,$chall) = split(/:/, $credential_set);
next if ( grep(/^$account:/i, @{ $data{'cracked-ntlm'} }) );
print STDERR "\n\n";
print STDERR "###########################################################################################\n";
print STDERR "Performing NTLM case-sensitive crack for account: $account.\n";
open(HAND, ">$tmpdict") || die("Failed to option file: $tmpdict -- $!");
print HAND "$lmpass";
close(HAND);
open (HAND, "$JOHN -format:netntlm -config:$tmpconf -wordlist:$tmpdict -rules -user:\"$account\" -session:$tmpsession $opt{'file'} |") || die("Failed to execute john: $!");
while(<HAND>) { print; }
close(HAND);
unlink $tmpdict || warn("Failed to unlink $tmpdict -- $!");
}
print STDERR "\n\n";
print STDERR "###########################################################################################\n";
print STDERR "Isolating accounts which have only had their LM response cracked.\n";
foreach $credential_set ( @{ $data{'pairs'} } ) {
$credential_set =~ s/\\/\\\\/g;
my ($account,$foo,$bar,$netlm,$netntlm,$chall) = split(/:/, $credential_set);
if (lc($netlm) eq lc($netntlm)) {
print STDERR "LM response is not unique from NTLM response (skipping):\n\t$credential_set\n";
push @{ $data{'pairs-ntlm'} }, $credential_set;
}
elsif ( @cracked = grep(/^$account:/i, @{ $data{'cracked-ntlm'} }) ) {
print STDERR "Account $account NTLM response previously cracked.\n";
#print "@cracked";
}
else {
print STDERR "Account $account LM response added to cracking list.\n";
push @{ $data{'pairs-lm'} }, $credential_set;
}
}
if ( defined($opt{'seed'}) ) {
print STDERR "\n\n";
print STDERR "###########################################################################################\n";
print STDERR "Testing seed password to determine whether it is the actual password.\n";
open(HAND, ">$tmpdict") || die("Failed to option file: $tmpdict -- $!");
print HAND $opt{'seed'};
close(HAND);
open (HAND, "$JOHN -format:netntlm -config:$tmpconf -wordlist:$tmpdict -rules -session:$tmpsession $opt{'file'} |") || die("Failed to execute john: $!");
while(<HAND>) {
print;
next if (/^guesses: .*time: / || (/^Loaded .* password hash /) || (/^No password hashes loaded/));
my ($account) = $_ =~ / \((.*)\)$/;
# Remove accounts which just cracked from list
my $i = 0;
foreach $credential_set ( @{ $data{'pairs-lm'} } ) {
$account =~ s/\\/_/g;
$credential_set =~ s/\\\\/_/g;
if ( $credential_set =~ /^$account:/ ) {
splice(@{ $data{'pairs-lm'} }, $i, 1);
}
$i++;
}
}
close(HAND);
unlink $tmpdict || warn("Failed to unlink $tmpdict -- $!");
my $tmppasswd = "/tmp/john.$$/john.passwd";
open(HAND, ">$tmppasswd") || die("Failed to open $tmppasswd: $!");
print HAND @{ $data{'pairs-lm'} };
close(HAND);
print STDERR "\n\n";
print STDERR "###########################################################################################\n";
print STDERR "The hashes contained within $tmppasswd have not been cracked.\n";
print STDERR "Executing the following (this could take a while...):\n\n";
print STDERR "john -format:netlm -config:$tmpconf -external:HalfLM -incremental:LM -session:$tmpsession $tmppasswd\n";
print STDERR "\n";
print STDERR " *If the passwords successfully crack, use this script again to crack the case-sensitive password\n";
print STDERR " without feeding a seed password\n";
print STDERR"\n\n";
system("$JOHN -format:netlm -config:$tmpconf -external:HalfLM -incremental:LM -session:$tmpsession $tmppasswd");
#exec("$JOHN -format:netlm -config:$tmpconf -external:HalfLM -incremental:LM -session:$tmpsession $tmppasswd");
unlink $tmppasswd || warn("Failed to unlink $tmppasswd -- $!");
}
else {
print STDERR "\nNo seed supplied for testing.\n";
}
#print STDERR "Removing temporary files and directory\n";
unlink $tmpconf, $tmplog, $tmpsession, $tmpsessionlog || warn("Failed to unlink temporary config files -- $!");
rmdir("/tmp/john.$$") || warn("Failed to delete temporary john directory -- $!");
}
exit(0);
sub createConf {
my $tmpconf = "/tmp/john.$$/john.conf";
open(CONF, ">$tmpconf") || die("Failed to open $tmpconf: $!");
# Define character keyspace
print CONF "[Incremental:LM]\n";
print CONF "File = \$JOHN/lanman.chr\n";
print CONF "MinLen = 1\n";
# John compiled for MaxLen <= 8
if (14 - length($opt{'seed'}) > 8) {
print CONF "MaxLen = 8\n";
} else {
print CONF "MaxLen = ", 14 - length($opt{'seed'}), "\n";
}
print CONF "CharCount = 69\n\n";
# Add external filter to handle uncracked characters
if ($opt{'seed'} ne "") {
my $i; $j;
my @seed = split(//, $opt{'seed'});
print CONF "[List.External:HalfLM]\n";
print CONF "void init()\n";
print CONF "{\n";
print CONF " word[14] = 0;\n";
print CONF "}\n\n";
print CONF "void filter()\n";
print CONF "{\n";
my $len = length($opt{'seed'});
for ($i = 13, $j = 13 - $len; $i>=0; $i--) {
if ($i >= $len) {
print CONF " word[$i] = word[$j];\n";
$j--;
} else {
print CONF " word[$i] = \'$seed[$i]\';\n";
}
}
print CONF "}\n\n";
}
# Add custom wordlist to utilize NTLM hash for character case cracking
print CONF "[List.Rules:Wordlist]\n";
print CONF ":\n";
print CONF "-c T0Q\n";
print CONF "-c T1QT[z0]\n";
print CONF "-c T2QT[z0]T[z1]\n";
print CONF "-c T3QT[z0]T[z1]T[z2]\n";
print CONF "-c T4QT[z0]T[z1]T[z2]T[z3]\n";
print CONF "-c T5QT[z0]T[z1]T[z2]T[z3]T[z4]\n";
print CONF "-c T6QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]\n";
print CONF "-c T7QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]\n";
print CONF "-c T8QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]\n";
print CONF "-c T9QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]\n";
print CONF "-c TAQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]\n";
print CONF "-c TBQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]\n";
print CONF "-c TCQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]T[zB]\n";
print CONF "-c TDQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]T[zB]T[zC]\n";
close(CONF);
return $tmpconf;
}
Jump to Line
Something went wrong with that request. Please try again.