Skip to content

Instantly share code, notes, and snippets.

@vdudouyt
Created June 3, 2014 03:17
Show Gist options
  • Save vdudouyt/7ecc130a6cc6464bb133 to your computer and use it in GitHub Desktop.
Save vdudouyt/7ecc130a6cc6464bb133 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl
=pod
Ensures that the password matches against NTLM challenge & response.
Synopsis:
./src/curl --ntlm -uAdministrator:atomic http://192.168.56.101:/WebDav/ -v
WWW-Authenticate: NTLM TlRMTVNTUAACAAAABAAEADgAAAAGgokCv9L+7WR398wAAAAAAAAAAIYAhgA8AAAABQLODgAAAA9ETlMxAgAIAEQATgBTADEAAQAIAEQARQBMAEwABAAcAGQAbgBzADEALgBsAG8AYwBhAGwAaABvAHMAdAADACYAZABlAGwAbAAuAGQAbgBzADEALgBsAG8AYwBhAGwAaABvAHMAdAAFABwAZABuAHMAMQAuAGwAbwBjAGEAbABoAG8AcwB0AAAAAAA=
Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAABwAAAADQANAHAAAAAEAAQAfQAAAAAAAAAAAAAABoKJAtF4FmQok6yvAAAAAAAAAAAAAAAAAAAAAD9xuQoSt6XlCNB3NXHcuv3CQLGP6YgYQUFkbWluaXN0cmF0b3Job21l
perl ntlm_check_passwd.pl TlRMTVNTUAACAAAABAAEADgAAAAGgokCv9L+7WR398wAAAAAAAAAAIYAhgA8AAAABQLODgAAAA9ETlMxAgAIAEQATgBTADEAAQAIAEQARQBMAEwABAAcAGQAbgBzADEALgBsAG8AYwBhAGwAaABvAHMAdAADACYAZABlAGwAbAAuAGQAbgBzADEALgBsAG8AYwBhAGwAaABvAHMAdAAFABwAZABuAHMAMQAuAGwAbwBjAGEAbABoAG8AcwB0AAAAAAA= TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAABwAAAADQANAHAAAAAEAAQAfQAAAAAAAAAAAAAABoKJAtF4FmQok6yvAAAAAAAAAAAAAAAAAAAAAD9xuQoSt6XlCNB3NXHcuv3CQLGP6YgYQUFkbWluaXN0cmF0b3Job21l atomic
1
=cut
use strict;
use Crypt::DES;
use MIME::Base64;
use Authen::NTLM::HTTP;
use Digest::MD4 qw(md4 md4_hex);
use Digest::MD5 qw(md5 md5_hex);
use Encode qw(from_to decode encode);
use Data::Dumper;
sub base16 {
join('', map { sprintf('%02x', ord($_)) } split('', $_[0]));
}
sub unbase16 {
my ($hex) = @_;
my @out;
for(my $i = 0; $i < length($hex); $i+=2) {
$out[$i/2] = chr(hex(substr($hex, $i, 2)));
}
return join('', @out);
}
sub des_encrypt { Crypt::DES->new($_[0])->encrypt($_[1]) }
sub des_decrypt { Crypt::DES->new($_[0])->decrypt($_[1]) }
sub key_56_to_64 {
my @in = map { ord($_) } split('', $_[0]);
my @out;
$out[0] = $in[0];
$out[1] = ((($in[0] << 7) & 0xFF) | ($in[1] >> 1));
$out[2] = ((($in[1] << 6) & 0xFF) | ($in[2] >> 2));
$out[3] = ((($in[2] << 5) & 0xFF) | ($in[3] >> 3));
$out[4] = ((($in[3] << 4) & 0xFF) | ($in[4] >> 4));
$out[5] = ((($in[4] << 3) & 0xFF) | ($in[5] >> 5));
$out[6] = ((($in[5] << 2) & 0xFF) | ($in[6] >> 6));
$out[7] = (($in[6] << 1) & 0xFF);
return join('', map { chr($_) } @out);
}
sub zip_to_hash {
my ($keys, @values) = @_;
my $ret;
$ret->{$_} = shift(@values) for @$keys;
return $ret;
}
sub get_server {
return new_server Authen::NTLM::HTTP('NTLMSSP_HTTP_WWW', 'localhost');
}
sub parse_challenge {
zip_to_hash([qw(domain flags nonce ctx_upper ctx_lower)], get_server->http_parse_challenge($_[0]));
}
sub parse_auth {
zip_to_hash([qw(flags lm_resp nt_resp user_domain username machine)], get_server->http_parse_auth($_[0]));
}
sub build_md5sum {
my ($challenge, $auth) = @_;
md5($challenge->{nonce}, substr($auth->{lm_resp}, 0, 8));
}
sub decode_md5sum {
my ($pass, $auth) = @_;
my $nthash = md4($pass);
my $keys = substr($nthash, 0, 8);
my $resp = substr($auth->{nt_resp}, 0, 8);
des_decrypt(key_56_to_64($keys), $resp);
}
sub check_pass {
my ($pass, $challenge, $auth) = @_;
my $pass_utf16 = encode('UTF-16le', decode('UTF-8', $pass));
my $md5sum = build_md5sum($challenge, $auth);
my $answer = decode_md5sum($pass_utf16, $auth);
substr($md5sum, 0, 8) eq $answer;
}
sub print_help_and_exit {
print STDERR "Usage: $0 <challenge_base64> <auth_base64> <password>\n";
exit(-1);
}
&print_help_and_exit() if @ARGV != 3;
my ($challenge, $auth, $pass) = (parse_challenge($ARGV[0]),
parse_auth($ARGV[1]),
$ARGV[2]);
print check_pass($pass, $challenge, $auth);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment