« Another Bling Release: v0.4.1 - So Long, Technorati | Main | New HOWTO: Disable HTTP Methods in Tomcat »

11/21/2009

New Release: CryptoNark v0.3 - Less Crypto, More Nark!

CryptoNark 0.4.1 is the most recent version. See the Release Announcement for more details.

OK, not really with less crypto but this is the first release where cryptonark becomes a little something more than a script that will tell you what SSL ciphers are enabled on a site.  Some common vulnerabilities that innocent web masters like myself get hit with contain the rather ominous titles like "SSL Server Allows Anonymous Authentication Vulnerability", "SSL Server Has SSLv2 Enabled Vulnerability" or "SSL Sever Supports Weak Encryption Vulnerability".  CryptoNark has been reporting cipher strength levels allowable on a site for some time now, which has allowed administrators to verify that PCI remediation changes have been effectively implemented.  

Another popular vulnerability that crops up from time to time is "Web Server HTTP Trace/Track Method Support Cross-Site Tracing Vulnerability".  I have written several HOWTO documents on disabling TRACE and TRACK on various platforms so I will not rehash what needs to be done to address this particular item here but cryptonark now tests a site to see if TRACE and/or TRACK are enabled on a site.  

Other changes to the script is use of Perl 5.10-specific functions, so Perl 5.10 or higher is now required. 

CryptoNark now uses command line arguments, taking advantage of the built in core module, Getopt::Long.  Right now, there are only two (--host and --port) and both are required.  SSL Cipher scanning will only occur if the port is set to 443.  Future changes might include a --notrace or --nocipher option to disable certain checks. 

Finally, and much to my surprise, I learned recently that some admins disable HEAD requests on their sites.  Therefore, I've modified the script to error out a little more gracefully in the even this condition is met. 

In future versions I will be expanding the types of tests performed.  I may also be including additional ciphers since more TLS-specific ciphers have been included in later openssl distributions, (which means the SSL3 tests may be coming back).  Grab the latest version from the download page!

#!/usr/bin/env perl
use strict;
use warnings;
use feature ':5.10';

use Term::ANSIColor qw(:constants);
use Tie::Hash::Indexed;
use IO::Socket::SSL;
# The following three modules provide support for 
# displaying server type and TRACE and TRACK requests.
use LWP::UserAgent;
use HTTP::Headers;
use HTTP::Request;
# Core Module introducing command line options
use Getopt::Long; 

my $host;
my $port;
my $scheme;
my $help;

sub usage{
    print "Usage: cnark.pl [--host HOSTNAME --port PORT]\n";
    exit;
  }

usage() if ( ! GetOptions("host=s" => \$host, "port=s" => \$port,) or ( ! defined $host) or ( ! defined $port) );

my $key;
my $value;
my $ssl2client;
my $ssl3client;

if ( $port eq 443) {
  $scheme = 'https';
  }
else {
  $scheme = 'http';
  }

# Populate hash with OpenSSL ciphers
# Note:  TLSv1 ciphers and SSLv3 ciphers are 
# identical in OpenSSL

tie my %ssl2_ciphers, 'Tie::Hash::Indexed';
tie my %tls1_ciphers, 'Tie::Hash::Indexed';

%ssl2_ciphers = (
  'DES-CBC3-MD5' => '168 bits, High Encryption',
  'RC2-CBC-MD5' => '128 bits, Medium Encryption',
  'RC4-MD5' => '128 bits, Medium Encryption',
  'DES-CBC-MD5' => '56 bits, Low Encryption',
  'EXP-RC2-CBC-MD5' => '40 bits, Export-Grade Encryption',
  'EXP-RC4-MD5' => '40 bits, Export-Grade Encryption'
);

%tls1_ciphers = (
  'ADH-AES256-SHA' => '256 bits, High Encryption, Anonymous Auth',
  'DHE-RSA-AES256-SHA' => '256 bits, High Encryption',
  'DHE-DSS-AES256-SHA' => '256 bits, High Encryption',
  'AES256-SHA' => '256 bits, High Encryption',
  'ADH-DES-CBC3-SHA' => '168 bits, High Encryption, Anonymous Auth',
  'EDH-RSA-DES-CBC3-SHA' => '168 bits, High Encryption',
  'EDH-DSS-DES-CBC3-SHA' => '168 bits, High Encryption',
  'DES-CBC3-SHA' => '168 bits, High Encryption',
  'ADH-AES128-SHA' => '128 bits, High Encryption, Anonymous Auth',
  'DHE-RSA-AES128-SHA' => '128 bits, High Encryption',
  'DHE-DSS-AES128-SHA' => '128 bits, High Encryption',
  'AES128-SHA' => '128 bits, High Encryption',
  'RC4-SHA' => '128 bits, Medium Encryption',
  'RC4-MD5' => '128 bits, Medium Encryption',
  'ADH-RC4-MD5' => '128 bits, Medium Encryption, Anonymous Auth',
  'EDH-RSA-DES-CBC-SHA' => '56 bits, Low Encryption',
  'EDH-DSS-DES-CBC-SHA' => '56 bits, Low Encryption',
  'DES-CBC-SHA' => '56 bits, Low Encryption',
  'ADH-DES-CBC-SHA' => '56 bits, Low Encryption, Anonymous Auth',
  'EXP-ADH-DES-CBC-SHA' => '40 bits, Export-Grade Encryption',
  'EXP-ADH-RC4-MD5' => '40 bits, Export-Grade Encryption',
  'EXP-EDH-RSA-DES-CBC-SHA' => '40 bits, Export-Grade Encryption',
  'EXP-EDH-DSS-DES-CBC-SHA' => '40 bits, Export-Grade Encryption',
  'EXP-DES-CBC-SHA' => '40 bits, Export-Grade Encryption',
  'EXP-RC2-CBC-MD5' => '40 bits, Export-Grade Encryption',
  'EXP-RC4-MD5' => '40 bits, Export-Grade Encryption',
  'NULL-SHA' => 'Null cipher, No Encryption',
  'NULL-MD5' => 'Null cipher, No Encryption'
);

sub is_weak{
  if ($key =~ /^EXP-|^NULL|^ADH-|DES-CBC-/) {
    print RED, "    " . $key . " -- " . $value . "\n", RESET;
  }
  else {
    print GREEN, "    " . $key . " -- " . $value . "\n", RESET;
  }
}

sub get_server_type{
  my $url = "$scheme://$host/";
  my $ua = LWP::UserAgent->new;
    $ua->timeout(10);
    $ua->env_proxy;
    $ua->agent('cryptonark-pci-auditor/v0.3');
      my $header = $ua->head( $url );
      say "\nWeb Server Type: " . $header->server . "\n";
  }

sub test_for_trace {
    my $url = "$scheme://$host/";

    my $method = "TRACE";
    my $ua     = LWP::UserAgent->new;
    $ua->timeout(10);
    $ua->env_proxy;
    $ua->agent('cryptonark-pci-auditor/v0.3');
    
    my $request = HTTP::Request->new( $method => $url );
    $request->header(Header0 => "TRACE");
    $request->header(Header1 => "Test");

    my $response = $ua->request($request);

    given ( $response->code ) {
        when (200) {
            say "======this is what you sent======";
            say $response->content;
            say "=================================";
            say $method, " is enabled and working.";
        }
        when (301) {
            say "Redirect present.  Retry request against ",
              $response->header('Location');
        }
        when (302) {
            say "Redirect present.  Retry request against ",
              $response->header('Location');
        }
        when (307) {
            say "Redirect present.  Retry request against ",
              $response->header('Location');
        }
        when (403) {
            say $response->status_line;
            say $method, " is forbidden.";
        }
        when (404) {
            say $response->status_line;
            say "This is an unexpected response.";
        }
        when (405) {
            say $response->status_line;
            say $method, " is not permitted.";
        }
        when (501) {
            say $response->status_line;
            say $method, " is not implemented.";
        }
        default {
            say $response->status_line;
        }
    }
}

sub test_for_track {
    my $test = 'This is an HTTP TRACE test.';
    my $url = "$scheme://$host/";

    my $method = "TRACK";
    my $ua     = LWP::UserAgent->new;
    $ua->timeout(10);
    $ua->env_proxy;
    $ua->agent('cryptonark-pci-auditor/v0.3');
    
    my $request = HTTP::Request->new( $method => $url );
    $request->header(Header0 => "TRACK");
    $request->header(Header1 => "Test");

    my $response = $ua->request($request);

    given ( $response->code ) {
        when (200) {
            say "======this is what you sent======";
            say $response->content;
            say "=================================";
            say $method, " is enabled and working.";
        }
        when (301) {
            say "Redirect present.  Retry request against ",
              $response->header('Location');
        }
        when (302) {
            say "Redirect present.  Retry request against ",
              $response->header('Location');
        }
        when (307) {
            say "Redirect present.  Retry request against ",
              $response->header('Location');
        }
        when (403) {
            say $response->status_line;
            say $method, " is forbidden.";
        }
        when (404) {
            say $response->status_line;
            say "This is an unexpected response";
        }
        when (405) {
            say $response->status_line;
            say $method, " is not permitted.";
        }
        when (501) {
            say $response->status_line;
            say $method, " is not implemented.";
        }
        default {
            say $response->status_line;
        }
    }
}

sub shameless_plug{
    say "\n---------------Shameless Plug---------------";
    say "For tips on PCI Remediation, visit my blog at:";
    say "   http://blog.techstacks.com/pci-compliance/";
    say "Thanks for using cnark!";
    say "---------------------------------------------";
  }

get_server_type();

say "Testing for HTTP TRACE...";
sleep 2;
test_for_trace();

say "\nTesting for HTTP TRACK...";
sleep 2;
test_for_track();

sub test_ssl2_ciphers{

say "\nTesting SSLv2 Ciphers...";
sleep 2;
while (($key,$value) = each(%ssl2_ciphers)) {
  my $ssl2client = IO::Socket::SSL->new(
    SSL_verify_mode => 0,
    SSL_version => 'SSLv2',
    SSL_cipher_list => $key,
    PeerAddr => $host,
    PeerPort => $port,
    Proto => 'tcp',
    Timeout => '5'
    )
  && is_weak();
  }
}

sub test_tls_ciphers{
say "Testing SSLv3/TLSv1 Ciphers...";
sleep 2;
while (($key,$value) = each(%tls1_ciphers)) {
  my $tls1client = IO::Socket::SSL->new(
    SSL_verify_mode => 0,
    SSL_version => 'TLSv1',
    SSL_cipher_list => $key,
    PeerAddr => $host,
    PeerPort => $port,
    Proto => 'tcp',
    Timeout => '5'
    )
  && is_weak(); 
  }
}

if ($port eq 443) {
 test_ssl2_ciphers();
 test_tls_ciphers();
 }
shameless_plug();

TrackBack

TrackBack URL for this entry:
https://www.typepad.com/services/trackback/6a01156fbc6fe6970c0120a6bf42a2970b

Listed below are links to weblogs that reference New Release: CryptoNark v0.3 - Less Crypto, More Nark!:

Comments