« October 2010 | Main | December 2010 »

4 posts from November 2010

11/25/2010

GlassFish Community vs JBoss Community: Patches

A recent post on The Aquarium highlighted one fairly compelling difference for enterprises to take into consideration between the community versions of glassfish and jboss:  GlassFish provides security and bug fix updates to customers using either GlassFish Open Source Edition or Oracle Glassfish Server.  JBoss typically does not.  

JBoss has responded to this post explaining the JBoss Product Lifecycle and highlighting the benefits of using EAP vs Community Editions and does make the point that Community versions of JBoss are meant for cutting-edge apps.  The problem with cutting-edge apps, however, is that, presumably, designers of these applications probably want to make money off of them, too.  Today, the most common method for accepting payments on the web is still the credit card and if you are accepting credit card payments, you must comply with PCI Compliance guidelines (in addition to any of the other compliancy frameworks we have to follow).

This is unfortunate for JBoss because it would not be uncommon at some point during a quarterly PCI compliance scan to be tagged with vulnerabilities like "JBoss Enterprise Application Platform Status Servlet Request Remote Information Disclosure", where you are directed to the installation of a hotfix or fixpack, which simply isn't available if you are using the community version of the product.  Yes, even though the vulnerability lists JBoss Enterprise Application Platform 4.2 and 4.3 as being vulnerable, the community version of JBoss 4.2 is just as vulnerable.  The difference being that one does not have the ability to patch the community version at all but to simply wait for the next release of the community version that may include a fix for the problem, come up with some workaround, or get EAP.  

Consider the following issue with JBoss 5.0.1.  JBoss 5.0.1 has a vulnerability that leaves the server subject to not only an information disclosure issue but a particularly nasty denial-of-service vulnerability inherited from JBoss's use of Apache Tomcat. If you are a JBoss EAP 5.0.1 user, you have a patch available.  If you are a community edition user, you're in a bit of a pickle.  JBoss 5.0.1 Community Edition was released in February 2009 and version 5.1.0 was released about three months later.  Has the fix been included in 5.1.0?  It's tough to tell based on the release notes. (If anyone knows, let me know!)

One of things that open source software is famous for over closed source equivalents is the rapid release of updates and patches but to have a major project not doing this (and actually charging for updates) feels extremely strange.

So, the moral of the story here for infrastructure, operations, and security teams is that going live with a community version of JBoss is probably not a really good idea whereas going live with that same cutting edge application using GlassFish community edition is a little safer.  You may still have concerns with commercial support vs. community support but access to security updates does not appear to be an issue with GlassFish Open Source Edition.  


Update: The first comment below is a response to this post from JBoss's Lead Security Architect, in which he appears to be agreeing with me that JBoss Community is not suitable for deployments if your organization has compliance requirements that must be adhered to. This should probably not be read as an official position from Red Hat/JBoss, however, as personal blogs do not reflect the opinions of the employer.

11/13/2010

CryptoNark v0.4 Released

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

The last release was back in September and the changes that I've made to cryptonark seemed like it was enough to warrant a new version number update.  This release of CryptoNark changes the default behavior of the tool so that when run, only the SSL-specific tests are run.   A new option, -xl (or --kitchen-sink) will execute all the tests in full betrayal mode.

Another addition to the tool is that certificate validation is now enabled by default.  There are now two files bundled in the downloadable archives, cnark.pl and ca-bundle.crt.  OpenSSL does not provide any root certificates in a standard install but in order to enable certificate verification, root CA certificates were required.  Thanks to the mod_ssl team, who, in turn, create their certificate bundle based off of the work provided by the Mozilla team, for providing a fairly comprehensive root certificate bundle.  Now, cryptonark should exit gracefully in the event of an incomplete ssl certificate chain, an expired cert, a self-signed certificate, etc.  If it does but you really, really want to run the tests anyway, a new option (--insecure) will disable certificate verification.

Finally, cryptonark now supports both short and long options.  Use -h or --host for the hostname to be scanned, -p or --port for the port number, -i or --insecure to disable certificate verification, and -xl or --kitchen-sink to run the full set of tests.  Downloads are on the Techstacks Downloads page.  Thanks for checking it out!

#!/usr/bin/env perl
# Usage:  ./cryptonark.pl host port
# based on sslthing.sh by blh [at] blh.se
# ported to perl by Chris Mahns - techstacks.com
#
# cryptonark: 
# version 0.1 - Initial Version
#
# almost a direct port, this version also tests
# null and anonymous ssl ciphers and reports 
# accordingly.  A little more information is provided
# in the output. Works best if used to validate PCI-DSS
# compliance--to check that null, anonymous and weak ciphers
# are disabled.  
#
# It probably will not run right "out of the box"--it requires
# IO::Socket::SSL.  Tie::Hash::Indexed, although not strictly required
# is nice to have in order to order the hash lists from strongest to 
# weakest. Otherwise, the order could be random making the results a
# bit harder to read.
#
# version 0.2 - 
#   + Added Color Coded output. Good ciphers are green, bad ones are red.
# 
# version 0.2.1 - 
#   + Removed the SSLv3 Tests.  (Actually, just commented
#     them out for now.)  SSLv3 and TLSv1 utilize the same ciphers so
#     the tests are redundant.
#   + Added a message after the display of cipher levels providing links to
#     my site so that you can get information on disabling ciphers
#
# version 0.2.5 -
#   + Added a HEAD request to display web server type.  Uses some addition
#     modules:  LWP::UserAgent and HTTP::Headers
#   
# version 0.3 - 
#     + "Upgraded" cnark to use perl 5.10 features.  Perl 5.10
#       is now required.
#
#     + Modified script so that it uses command line options
#       using Core Module Getopt::Long.  --host and --port
#       should now be used.
#
#     + Removed exception catch on check_server_type() function.
#       I don't think HEAD requests should ever fail but some
#       sites restrict that method too for some reason.
#     
#     + cnark now tests for existence of HTTP Methods: 
#       TRACE and TRACK.
#
#     + cnark will skip ssl scans if a non ssl port 
#       is used.
#
# version 0.3.1 - 
#     + Clean up
#     
#     + Switched to use Modern::Perl
#
# version 0.3.5
#     + Now scans for commonly used "unsafe" URLs.
#       More to come.
#
# version 0.3.6
#     
#     + Moved some stuff around.
#
#     + Added SSLv3 tests back in.  This functionality was
#       useful to some folks who were looking for output
#       from specific protocols.
#     
#     + Added ColdFusion Administrator to unsafe URL
#       check
#     
#     + Added Tomcat Status URL to unsafe URL Check
#
#     + Tweaked the output for the unsafe URL Check
#       to reduce some redundancy and add a 
#       false positive disclaimer
#
#       Should be able to get rid of the disclaimer
#       when better false positive checks are added
#
#     + Added some basic certificate parsing
#
# version 0.4
#     + Added option -xl|--kitchen-sink  By default, cnark.pl
#       now performs ssl-only tests.  The -xl|kitchen-sink will
#       put cryptonark in full betrayal mode.
#
#     + Added Certificate Peer Verification (enabled by default)
#       This causes cryptonark to fail on expired certs, missing
#       root certificates, self-signed certs, and (I hope)
#       invalid certificate chains.
#
#
#       Certificate Validation is due to the inclusion of 
#       the ca-bundle.crt CA certificate bundle from mod_ssl.
#
#     + Added --insecure option to disable peer verification
#     + Removed shamesless plug
#
use Modern::Perl;
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 $version = "v0.4";

my ( $host, $port, $scheme );
my $insecure = '';
my $xl = '';
my $verifymode = 1;
my $useragent = "cryptonark-pci-auditor/" . $version;

sub usage{
    say "Usage: cnark.pl -h|--host  -p|--port  \n\t\t[-i|--insecure] [-xl|--kitchen-sink]";
    exit;
  }

usage() if ( ! GetOptions("h|host=s" => \$host, "p|port=s" => \$port, "i|insecure" => \$insecure, "xl|kitchen-sink" => \$xl ) or ( ! defined $host) or ( ! defined $port) );

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

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

if ($insecure eq 1 ) {
  $verifymode = 0;
  }


# Populate arrays 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'
);

# Populate a hash of unsafe URLs
# i.e. URLs you would not want exposed
# to the Internet

tie my %bad_urls, 'Tie::Hash::Indexed';

%bad_urls = (
  'Apache mod_status page' => 'server-status',
  'Apache mod_info page' => 'server-info',
  'Apache mod_jk status page' => 'jk-status',
  'Apache mod_proxy_balancer' => 'balancer-manager',
  'ColdFusion Administrator' => 'CFIDE/administrator/index.cfm',
  'IIS Samples' => 'IISsamples',
  'IIS Scripts' => 'Scripts',
  'IIS MSADC Directory' => 'MSADC',
  'IIS Help' => 'IISHelp',
  'IIS Admin' => 'IISAdmin',
  'Tomcat Manager' => 'manager/html',
  'Tomcat Status Page' => 'manager/status',
  'Tomcat JSP Examples' => 'jsp-examples/index.html',
  'Tomcat Servlet Examples' => 'servlets-examples/index.html',
  'JBoss JMX Console' => 'jmx-console',
  'JBoss Tomcat Status Page' => 'status',
  'JBoss Web Console' => 'web-console',
  'JBoss 5.x Admin Console' => 'admin-console',
  );


sub get_server_type{
  my $url = "$scheme://$host/";
  my $ua = LWP::UserAgent->new;
    $ua->timeout(10);
    $ua->env_proxy;
    $ua->agent( $useragent );
      my $header = $ua->head( $url );
      print "\nWeb Server Type: " . $header->server . "\n\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( $useragent );
    
    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( $useragent );
    
    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 scan_for_unsafe_urls{
  print "\n";
  say "Scanning for 'Unsafe' URLs...";
  say "NOTE: This isn't perfect yet.\nSuccesses could be false positives\nMany are caused by redirection";
  sleep 2;
  my $response;
  my $request;
  
  while (($key,$value) = each(%bad_urls)) {
    my $url = "$scheme://$host/$value";
    my $ua = LWP::UserAgent->new;
      $ua->timeout(10);
      $ua->env_proxy;
      $ua->agent( $useragent );

    my $request = HTTP::Request->new( GET => $url );
    my $response = $ua->request($request);
  
  if ($response->code == '200') {
    print RED, "     " . $key . " -- /". $value . " url found" . "\n", RESET;
    }
    else {
      print GREEN, "     " . $key . " -- /" . $value . " url not found." . "\n", RESET;
      }
  }
}

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



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

# Basic certificate checking
sub cert_info{
print "\nSSL Certificate Information...\n";
sleep 2;

my $certclient = IO::Socket::SSL->new(
  SSL_ca_file => 'ca-bundle.crt',
  SSL_verify_mode => $verifymode,
  SSL_version => 'TLSv1',
  SSL_cipher_list => 'RC4-MD5',
  PeerAddr => $host,
  PeerPort => $port,
  Proto => 'tcp',
  Timeout => '5'
  ) || die("Certificate Peer Verification Failed.\nYou can try running with the --insecure switch\n\n");
  my $cn = $certclient->peer_certificate("cn");
  say "Certificate Commmon Name: " . $cn . "\n";
}


sub test_ssl2_ciphers{

print "\nTesting SSLv2 Ciphers...\n";
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_ssl3_ciphers{
print "\nTesting SSLv3 Ciphers...\n";
sleep 2;
while (($key,$value) = each(%tls1_ciphers)) {
  my $ssl3client = IO::Socket::SSL->new(
    SSL_verify_mode => 0,
    SSL_version => 'SSLv3',
    SSL_cipher_list => $key,
    PeerAddr => $host,
    PeerPort => $port,
    Proto => 'tcp',
    Timeout => '5'
    )
  && is_weak();
  }
}


sub test_tls_ciphers{
print "\nTesting TLSv1 Ciphers...\n";
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 ($xl eq 1 ) {
  # Run through the subroutines
get_server_type();

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

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

scan_for_unsafe_urls();

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

#shameless_plug();
  }
  else {
   cert_info();
   test_ssl2_ciphers();
   test_ssl3_ciphers();
   test_tls_ciphers();
}

11/01/2010

Tomcat Connectors v1.2.31 Released

The Apache Tomcat Connectors team has released v 1.2 31 today.  Tomcat Connectors are also commonly known as mod_jk (for the apache web server), isapi_redirect.dll (for IIS), and nsapi_redirector.so (for iplanet).  The changelog indicates a relatively small number of fixes and enhancements but the three that stood out for me are:

  • Apache 2.3/2.4 support was enabled in mod_jk.
  • IIS adds apache rotatelogs-style support to generated log files, (no more multi-gigabyte jk logs).
  • For those of us interested in this level of detail, we can now log local and remote ports.

Download it from a mirror near you!