-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Here's the patch adding NTLM proxy authorization.
This patch requires:
Authen:perl::NTLM (http://cpan.uwinnipeg.ca/dist/Authen-Perl-NTLM)
Crypt::DES
Digest::MD4

It should work, but elements of it are quite ugly.  I'm currently just
using the crypto from the NTLM module, and actually crafting the packets
in my code. I suspect I might be able to use more of the NTLM perl module.

This patch is based off of revision 166 of the perl version of fwknop.
It works to the best of my knowledge, but IMHO, It's not ready for prime
time. Over the next few days, I will work to clean it up, and work out
any bugs.

Any thoughts, corrections, etc. are welcome.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAksR3LsACgkQhFXk1UR7Wbd7WQCgklitSAyXeVZnMNpuY3W/Hkgn
19YAni/jxMa43mdQKeEYdXpgtShx6Rkr
=s/ci
-----END PGP SIGNATURE-----
--- fwknop      2009-11-19 23:15:44.000000000 -0600
+++ fwknop.new  2009-11-28 20:16:35.400536399 -0600
@@ -48,6 +48,7 @@
 use IO::Socket;
 use IO::Handle;
 use MIME::Base64;
+use Authen::Perl::NTLM qw(nt_hash lm_hash calc_resp);
 use Data::Dumper;
 use POSIX;
 use Getopt::Long;
@@ -1364,7 +1365,6 @@
     ### send the SPA packet to.
     my $http_host    = $knock_dst_pre_resolve;
     my $http_host_ip = $knock_dst;
-    my $http_proxy_auth_string = '';
     if ($http_proxy_host) {
 
         ### if we are sending the SPA packet through a proxy, set the
@@ -1392,10 +1392,6 @@
                 or die "[*] Could not resolve $http_host_ip to an IP.";
             $http_host_ip = $addr;
         }
-        if ($http_proxy_user) {
-            my $proxy_auth = encode_base64($http_proxy_user . ':' . 
$http_proxy_pass);
-            $http_proxy_auth_string = 'Proxy-Authorization: Basic ' .  
$proxy_auth . "\r\n";
-        }
     }
 
     print "\n[+] Sending SPA packet over HTTP to ",
@@ -1407,9 +1403,7 @@
     my $http_request = "GET $msg HTTP/1.0\r\n" .
         "User-Agent: $ext_resolve_user_agent\r\n" .
         "Accept: */*\r\n" .
-        "Host: $http_host\r\n" .  ### FIXME?
         "Connection: Keep-Alive\r\n" .
-        "$http_proxy_auth_string" .
         "\r\n";
 
     print "[+] Sending SPA HTTP request:\n\n$http_request" if $debug;
@@ -1425,7 +1419,39 @@
         if (defined($sock)) {
 
             print $sock $http_request;
-            recv($sock, my $web_data, $max_resolve_http_recv, 0);
+            ### We have to get the entire message. This means waiting for the 
whole header,
+            ### grabbing the message length, and then waiting for the rest of 
the page
+            ### Note: This might be best in it's own subroutine
+            my $web_counter = 0;
+            my $web_data = '';
+            my $web_data_buffer ='';
+            until ($web_data =~ m/\r\n\r\n/) {  ### This finds the end of the 
header. 
+                recv($sock, $web_data_buffer, $max_resolve_http_recv, 0);
+                $web_counter++;
+                die if $web_counter >= 50;
+                $web_data .= $web_data_buffer;
+            }
+
+            if ($web_data =~ m/Content-Length: (\d+)/) {
+                my $web_length = $1 + 4 + index($web_data,"\r\n\r\n");
+                until (length($web_data) == $web_length) {
+                    recv($sock, $web_data_buffer, $max_resolve_http_recv, 0);
+                    $web_counter++;
+                    die if $web_counter >= 50;
+                    $web_data .= $web_data_buffer;
+                }
+            }
+            ###check for proxy auth
+            if ($web_data =~ m/407 Proxy Authentication Required/) {
+                print "Proxy Authentication required.\n";
+                for (&proxy_auth($web_data, $msg, $sock)) {
+                    if (/0/) { print "Authentication successful." }
+                    elsif (/1/) { print "socket timed out\n" }
+                    elsif (/2/) { print "NTLM Authentication failure\n" }
+                    elsif (/3/) { print "potential failure: 404 not 
received\n" }
+                }
+            }
+                    
             close $sock;
 
             print "\n[+] Closing connection...\n";
@@ -1436,6 +1462,166 @@
     return;
 }
 
+sub proxy_auth {
+    ### I know, some of this is ugly. We have MS to thank for a bit of it.
+    ### My main source was http://www.innovation.ch/personal/ronald/ntlm.html
+
+    my ($web_data, $msg, $sock) = @_;
+    my $http_proxy_auth_string = '';
+    
+    if ($web_data =~ m/Proxy-Authenticate: NTLM/) {
+        print "Attempting NTLM authentication\n";
+        print "Please provide your host name: ";
+        my $hostname = ReadLine(0);
+        chomp $hostname;
+        print "\nPlease provide your domain name: ";
+        my $domainname = ReadLine(0);
+        print "\n";
+        chomp $domainname;
+        my $dom_len = length($domainname);
+        my $host_len = length($hostname);
+
+
+        ###craft the first message:
+        my $NTLM1 = pack('A8 H16 S S S H4 S S S H4 A*
+          A*',
+        "NTLMSSP\0",'0100000003b20000',$dom_len,$dom_len,32 + $host_len 
,'0000',$host_len,$host_len,32,'0000',$hostname,
+          $domainname);
+        $http_proxy_auth_string = "Proxy-Authorization: NTLM " . 
encode_base64($NTLM1,'');
+
+        my $http_request = "GET $msg HTTP/1.0\r\n" .
+            "$http_proxy_auth_string\r\n" .
+            "User-Agent: $ext_resolve_user_agent\r\n" .
+            "Accept: */*\r\n" .
+            "Connection: Keep-Alive\r\n" .
+            "\r\n";
+        print $sock $http_request;
+        ### Make sure we get it all!
+        
+        my $web_counter = 0;
+        $web_data = '';
+        my $web_data_buffer ='';
+        until ($web_data =~ m/\r\n\r\n/) {
+            recv($sock, $web_data_buffer, $max_resolve_http_recv, 0);
+            $web_counter++;
+            return 1 if $web_counter >= 50;
+            $web_data .= $web_data_buffer;
+        }
+        if ($web_data =~ m/Content-Length: (\d+)/) {
+            my $web_length = $1 + 4 + index($web_data,"\r\n\r\n");
+            until (length($web_data) == $web_length) {
+                recv($sock, $web_data_buffer, $max_resolve_http_recv, 0);
+                $web_counter++;
+                return 1 if $web_counter >= 50;
+                $web_data .= $web_data_buffer;
+            }
+        }
+
+
+        return 2 unless ($web_data =~ m/Proxy-Authenticate: NTLM (.+)/);
+        my $NTLM2_clear = decode_base64($1);
+        my @NTLM2_parsed = unpack('Z* H32 a8',$NTLM2_clear);
+        my $nonce = $NTLM2_parsed[2];
+
+        ### calculate the response message
+  
+        my $UTF_domainname =  pack "S*", unpack( "C*", $domainname );
+        my $UTF_proxy_user =  pack "S*", unpack( "C*", $http_proxy_user );
+        my $UTF_hostname =  pack "S*", unpack( "C*", $hostname );
+        my $UTF_dom_len = length($UTF_domainname);
+        my $UTF_host_len = length($UTF_hostname);
+        my $UTF_user_len = length($UTF_proxy_user);
+
+        my $domain_offset = 64;
+        my $user_offset = $domain_offset + $UTF_dom_len;
+        my $host_offset = $user_offset + $UTF_user_len;
+        my $LM_resp_offset = $host_offset + $UTF_host_len;
+        my $NT_resp_offset = $LM_resp_offset + oct("0x18");
+        my $msg_len = $NT_resp_offset + oct("0x18");
+
+        my $NTLM3 = pack ("A8 H8 S S S H4 S S
+          S H4 S S S H4 S S
+          S H4 S S S H12 S H4 H4
+          H4 A* A* A* A* A*",
+        "NTLMSSP\0","03000000",oct("0x18"),oct("0x18"), $LM_resp_offset, 
"0000", oct("0x18"),oct("0x18"),
+          $NT_resp_offset, "0000", $dom_len * 2, $dom_len * 2, 
$domain_offset,"0000", $UTF_user_len, $UTF_user_len,
+          $user_offset, "0000", $host_len * 2, $host_len * 2, $host_offset, 
"000000000000", $msg_len, "0000", "0182",
+          "0000", $UTF_domainname, $UTF_proxy_user, $UTF_hostname, 
calc_resp(lm_hash($http_proxy_pass),$nonce),
+          calc_resp(nt_hash($http_proxy_pass),$nonce));
+        my $NTLM3_base64 = encode_base64($NTLM3,'');
+        $http_proxy_auth_string = "Proxy-Authorization: NTLM $NTLM3_base64";
+
+        $http_request = "GET $msg HTTP/1.0\r\n" .
+            "$http_proxy_auth_string\r\n" .
+            "User-Agent: $ext_resolve_user_agent\r\n" .
+            "Accept: */*\r\n" .
+            "Connection: Keep-Alive\r\n" .
+            "\r\n";
+        print $sock $http_request;
+
+        $web_counter = 0;
+        $web_data = '';
+        $web_data_buffer ='';
+        until ($web_data =~ m/\r\n\r\n/) {
+            recv($sock, $web_data_buffer, $max_resolve_http_recv, 0);
+            $web_counter++;
+            return 1 if $web_counter >= 50;
+            $web_data .= $web_data_buffer;
+        }
+
+        if ($web_data =~ m/Content-Length: (\d+)/) {
+            my $web_length = $1 + 4 + index($web_data,"\r\n\r\n");
+            until (length($web_data) == $web_length) {
+                recv($sock, $web_data_buffer, $max_resolve_http_recv, 0);
+                $web_counter++;
+                return 1 if $web_counter >= 50;
+                $web_data .= $web_data_buffer;
+            }
+        }
+        return 0 if $web_data =~ m/404/;
+        return 3;
+    }
+
+    if ($web_data =~ m/Proxy-Authenticate: Basic/) {
+        print "Attempting Basic Authentication. \n";
+        my $proxy_auth = encode_base64($http_proxy_user . ':' . 
$http_proxy_pass);
+        $http_proxy_auth_string = 'Proxy-Authorization: Basic ' .  $proxy_auth 
. "\r\n";
+    
+        my $http_request = "GET $msg HTTP/1.0\r\n" .
+            "User-Agent: $ext_resolve_user_agent\r\n" .
+            "Accept: */*\r\n" .
+            "Connection: Keep-Alive\r\n" .
+            "$http_proxy_auth_string" .
+            "\r\n";
+        print $sock $http_request;
+
+        my $web_counter = 0;
+        $web_data = '';
+        my $web_data_buffer ='';
+        until ($web_data =~ m/\r\n\r\n/) {
+            recv($sock, $web_data_buffer, $max_resolve_http_recv, 0);
+            $web_counter++;
+            return 1 if $web_counter >= 50;
+            $web_data .= $web_data_buffer;
+        }
+
+        if ($web_data =~ m/Content-Length: (\d+)/) {
+            my $web_length = $1 + 4 + index($web_data,"\r\n\r\n");
+            until (length($web_data) == $web_length) {
+                recv($sock, $web_data_buffer, $max_resolve_http_recv, 0);
+                $web_counter++;
+                return 1 if $web_counter >= 50;
+                $web_data .= $web_data_buffer;
+            }
+        }
+        return 0 if $web_data =~ m/404/;       
+    }
+
+
+    return;
+}
+
+
 sub send_spa_packet_over_tcp() {
     my ($msg, $msg_len) = @_;
 
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Fwknop-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/fwknop-discuss

Reply via email to