Monday, April 9, 2012

Brute forcing a 802.11 WPA/WPA2-PSK

I was asked recently if there was a way to brute force a WPA/WPA2 key with aircrack-ng. Aside from the MASSIVE amount of time this would take to actually crack a real password, it was a good exercise and demo.

Aircrack-ng is a tool in the Aircrack-ng suite of tools (http://www.aircrack-ng.org/) that can be used to crack 802.11 WEP, and WPA/WPA2-PSK keys. The only method that is provided by aircrack for cracking WPA/WPA2-PSK is a dictionary attack. This is normally accomplished with the following aircrack-ng command:

aircrack-ng -e <essid> -w <wordlist file> <wpa/wpa2 pcap>

Now, lets say for instance that you wanted to brute force the key instead of supplying a wordlist for a dictionary attack. How do I do this with aircrack-ng when it only accepts a wordlist? To do this, we need to essentially create our own wordlist and then pass that wordlist to aircrack-ng.

To create a "brute force" wordlist, we can use a password generation utility such as crunch (http://sourceforge.net/projects/crunch-wordlist/). With crunch, you can specify a character set, min/max length of characters, etc. and it will generate a list of all the combinations and permutations. From here, we can pass this wordlist to aircrack-ng and start cracking.

Here is an example of how you can use crunch with aircrack-ng using the sample WPA2 packet capture included with the aircrack-ng suite. The WPA2-PSK in the sample is an eight digit number, "12345678". Both of these tools are included in the BackTrack 5 distribution (http://www.backtrack-linux.org/). This command will work on BackTrack 5, but if you are running on a different distro, then you will need to adjust the folder path as appropriate.


/pentest/passwords/crunch/crunch 8 8 0123456789 | aircrack-ng -e "Harkonen" -w - /pentest/wireless/aircrack-ng/test/wpa2.eapol.cap 

Lets break this down... The first command runs crunch and specifies a min-length of 8 characters, a max-length of 8 characters, and the character set that includes all numbers. This will generate all the different combinations of numbers from 00000000 to 99999999. If you wanted to output this to a file for later use, you can use the "-o <output file>" flag. For more info on the different options available with crunch, you can use the command: man crunch.

crunch 8 8 0123456789
crunch <min-length> <max-length> <char set>

Now that we have our "brute force", we need to pass that into aircrack-ng. We could just use crunch and the "-o" flag to output it to a file and then supply that file to aircrack-ng. But I'm lazy... :) Why do that when we could just pipe the results directly into aircrack-ng? The next part of command runs aircrack-ng and specifies the ESSID (Wireless network name or SSID), the wordlist, and the packet capture to crack from. You will notice that instead of specifying a wordlist filename for the "-w" flag, we instead use "-" (hyphen). This indicates to get the input from stdin instead of a file.

aircrack-ng -e "Harkonen" -w - /pentest/wireless/aircrack-ng/test/wpa2.eapol.cap

Then you put it all together with the "|" (pipe) character to direct the stdout from the crunch command to the stdin of the aircrack-ng command.

/pentest/passwords/crunch/crunch 8 8 0123456789 | aircrack-ng -e "Harkonen" -w - /pentest/wireless/aircrack-ng/test/wpa2.eapol.cap 

Again, keep in mind that even with a simple example such as this, it will still take a few hours to crack the key of "12345678". As you can see, brute forcing a WPA/WPA2 key really isn't practical as the amount of time required to crack a key grows exponentially as the length of the key and character set increases. But in any case, if you did want to give it a shot, you now know how. Enjoy! :)

Saturday, March 17, 2012

Nmap Open Ports Comparison Script

Since I was writing my other Nmap script, I thought that it would be beneficial to have a script that would compare two Nmap scans and report the differences in open ports. This would be handy for a few reasons, compliance, baseline scan comparisons, change control, etc.

This script takes the XML output file from your baseline Nmap scan and will compare it with the XML output from your current scan. For each host in the scan, the script will show you the open ports in the baseline and current scans, any new open ports that it found in the current scan, and any open ports in the baseline scan that are no longer open. It supports TCP and UDP ports.

This Perl script will use the same Nmap Parser module that I mentioned in my previous post. (http://search.cpan.org/~apersaud/Nmap-Parser/).

We need to ensure we take care of a couple of dependencies first:
  1. The first step is obviously to install Perl 5+ if you haven't already. 
  2. Then you need to install the Nmap Parser module. You can do this with the following command: perl -MCPAN -e 'install Nmap::Parser'
  3. Done!
Here is the actual perl script. Just copy/paste it and run. It takes two arguments. The first is the name of your baseline Nmap XML file and the second is the name of your current Nmap XML file.

#!/usr/bin/perl

# Author: Travis Lee
# Date Modified: 3-16-12
# Description: Script to compare results from two Nmap XML output files
#              and display the differences in open ports.
#
# Usage: NmapScanCompare.pl <baseline nmap scan.xml> <current nmap scan.xml>
#

use Nmap::Parser;
$base = new Nmap::Parser;
$curr = new Nmap::Parser;

if (!$ARGV[0] || !$ARGV[1])
{
print "Usage: NmapScanCompare.pl <baseline nmap scan.xml> <current nmap scan.xml>\n\n";
exit;
}

$base_file = $ARGV[0]; #baseline scan filename from command line
$curr_file = $ARGV[1]; #current scan filename from command line

$base->parsefile($base_file); #load baseline scan file
$curr->parsefile($curr_file); #load current scan file

$base_session = $base->get_session;
$curr_session = $curr->get_session;

print "\n\nBaseline Scan Parameters: ".$base_session->scan_args." -- Scan finished on: ".$base_session->time_str."\n";
print "Current Scan Parameters: ".$curr_session->scan_args." -- Scan finished on: ".$curr_session->time_str."\n";

#loop through all the IPs in the current scan file
for my $ip ($curr->get_ips) 
{
        #assume that IPs in current scan == IPs in base scan
        my $ip_base = $base->get_host($ip);
        my $ip_curr = $curr->get_host($ip);

#populate arrays with baseline and current tcp/udp open ports
my @base_tcpports = $ip_base->tcp_open_ports;
my @base_udpports = $ip_base->udp_open_ports;
my @curr_tcpports = $ip_curr->tcp_open_ports;
my @curr_udpports = $ip_curr->udp_open_ports;

#find tcp ports that exist in the current scan and not in the baseline scan
@curr_tcpdiff = &portdiff(\@base_tcpports, \@curr_tcpports);

#find tcp ports that existed in the baseline scan that do NOT exist in the current scan
@base_tcpdiff = &portdiff(\@curr_tcpports, \@base_tcpports);

#find udp ports that exist in the current scan and not in the baseline scan
@curr_udpdiff = &portdiff(\@base_udpports, \@curr_udpports);

#find tcp ports that existed in the baseline scan that do NOT exist in the current scan
@base_udpdiff = &portdiff(\@curr_udpports, \@base_udpports);

#give the open port arrays a value of "none" if no open ports are found
if (!@base_tcpports) { @base_tcpports = ("none"); }
if (!@curr_tcpports) { @curr_tcpports = ("none"); }
if (!@base_udpports) { @base_udpports = ("none"); }
if (!@curr_udpports) { @curr_udpports = ("none"); }

#give the diff arrays a value of "none" if no port diffs are found
if (!@base_tcpdiff) { @base_tcpdiff = ("none"); }
if (!@curr_tcpdiff) { @curr_tcpdiff = ("none"); }
if (!@base_udpdiff) { @base_udpdiff = ("none"); }
if (!@curr_udpdiff) { @curr_udpdiff = ("none"); }

print "\nReport for $ip:\n\n";
#print "Baseline scan had these TCP ports open: ".join(',',@base_tcpports)."\n";
#print "Current scan has these TCP ports open: ".join(',',@curr_tcpports)."\n\n";
        print "  New TCP ports open: ".join(',',@curr_tcpdiff)."\n";
        print "  TCP ports that are not open anymore: ".join(',',@base_tcpdiff)."\n\n";

#print "Baseline scan had these UDP ports open: ".join(',',@base_udpports)."\n";
#print "Current scan has these UDP ports open: ".join(',',@curr_udpports)."\n\n";
        print "  New UDP ports open: ".join(',',@curr_udpdiff)."\n";
        print "  UDP ports that are not open anymore: ".join(',',@base_udpdiff)."\n\n";
        
} #end for loop

#find ports that exists in $_[0], but not in $_[1]
sub portdiff
{
        my %port = ();
        my @result = ();
my @a = @{$_[0]}; #first parameter from sub call
my @b = @{$_[1]}; #second parameter from sub call

#build the lookup table
foreach $item (@a) { $port{$item} = 1; }

#find only elements in @b and not in @a
foreach $item (@b)
{
unless ($port{$item}) 
{
push(@result, $item); #it's not seen so add to @result
}
}

return @result;

} #end sub

Again, I am not a Perl ninja so it may not be the most efficient, but it works. If you have any suggestions on improvements to the script, please let me know! I would love to make this better and more helpful for anyone that needs it.

And of course there is also the obligatory disclaimer to use this at your own risk. :) Enjoy!

Monday, March 5, 2012

Converting Nmap XML output to CSV (Excel) Script

Ever ran a Nmap scan and wished that there was a way to easily get the data into Excel? You could want the data in Excel for a number of reasons... I personally like to have it in Excel sometimes so it is easier to track information about the host, OS, ports, services, vulnerabilities, etc.

The closest output that Nmap has is its built in XML format (-oX flag). Using this XML output I have created a perl script that easily converts the XML output into a CSV file for use in Excel. Luckily, a guy named Anthony Persaud created an Nmap Parser module for perl that we can use (http://search.cpan.org/~apersaud/Nmap-Parser/).

We need to ensure we take care of a couple of dependencies first:

  1. The first step is obviously to install Perl 5+ if you haven't already. 
  2. Then you need to install the Nmap Parser module. You can do this with the following command: perl -MCPAN -e 'install Nmap::Parser'
  3. That's it! Not too shabby.

Here is the actual perl script. Just copy/paste it and run. It takes two arguments. The first is the name of the Nmap XML file and the second is the name of your output file. 

#!/usr/bin/perl

# Author: Travis Lee
# Date Modified: 3-5-12
# Description: Script to convert a Nmap scan XML file to CSV
#
# Usage: NmapXMLtoCSV.pl <nmap xml file.xml> <output file.csv>
#

use Nmap::Parser;
$base = new Nmap::Parser;

if (!$ARGV[0] || !$ARGV[1])
{
print "Usage: NmapXMLtoCSV.pl <nmap xml file.xml> <output file.csv>\n\n";
exit;
}

$base_file = $ARGV[0]; #baseline scan filename from command line
$out_file = $ARGV[1]; #output filename from command line

$base->parsefile($base_file); #load baseline scan file

open (OUTFILE, ">$out_file");

$session = $base->get_session;
print OUTFILE $session->scan_args."  --  Scan finished on: ".$session->time_str;

print OUTFILE "\n\nIP,Hostname,MAC,OS,Port,Proto,State,Service,Version\n";

#loop through all the IPs in the current scan file
for my $ip ($base->get_ips) 
{
        #get host object for the current IP
        $ip_base = $base->get_host($ip);

#populate arrays with tcp/udp ports
my @tcpports = $ip_base->tcp_ports;
my @udpports = $ip_base->udp_ports;

print OUTFILE $ip_base->ipv4_addr.",";
print OUTFILE $ip_base->hostname.",";
print OUTFILE $ip_base->mac_addr.",";

#get os object for the current IP
my $os = $ip_base->os_sig;

#if smb-os-discrovery script was run, use this value for os. more accurate
if ($ip_base->hostscripts("smb-os-discovery"))
{
my @os_split1 = split(/\n/, $ip_base->hostscripts("smb-os-discovery"));
my @os_split2 = split("OS: ", $os_split1[1]);
print OUTFILE $os_split2[1].",";
}
else { print OUTFILE $os->name.","; } #else use what was discovered with os fingerprint

$first = 1;

&portout(\@tcpports, "tcp");
&portout(\@udpports, "udp");

print OUTFILE "\n";
        
} #end for loop

close (OUTFILE);
print "\n\nConversion complete!\n\n";

sub portout
{
my @ports = @{$_[0]};
my $proto = $_[1];

for my $port (@ports)
{
#get service object for the given port
if ($proto eq "tcp")
{
$svc = $ip_base->tcp_service($port);
}
elsif ($proto eq "udp")
{
$svc = $ip_base->udp_service($port);
}

if ($first == 1) { $first = 0; }
else { print OUTFILE ",,,,"; }

print OUTFILE $port.",";
print OUTFILE $proto.",";

if ($proto eq "tcp")
{
print OUTFILE $ip_base->tcp_port_state($port).",";
}
elsif ($proto eq "udp")
{
print OUTFILE $ip_base->udp_port_state($port).",";
}

print OUTFILE $svc->name.",";
print OUTFILE $svc->product."\n";

} #end for loop

} #end sub



I am not a professional perl ninja so it may not be the most efficient, but it works. If you have any suggestions on improvements to the script, please let me know! I would love to make this better and more helpful for anyone that needs it.

And of course there is also the obligatory disclaimer to use this at your own risk. :) Enjoy!