Archive for the ‘web security’ Category

Python script to check for vulnerable printers

Thursday, June 17th, 2010

People often overlook printers when it comes to information security. Truth is that a ton of useful information can be found in printers. Employees will often scan sensitive documents such as social security cards, loan information, birth certificates, etc. I’ve also seen important organizational information on printers such as internal memos between higher up executives. The documents I’ve seen in the past were never meant to be shared but a default printer will more than happily share your sensitive information. Almost any new commercial printer will come with a ton of features to store and retrieve any documentation that flows through the printer (copy, scan, and print jobs). Almost all of these new printers also give you a web interface to retrieve that documentation, an example of a printer’s web interface can be seen here. When I’m performing a penetration test I always go for the web interface of a printer, the web interface is where I can grab all the sensitive information. These printers usually get unboxed and plugged into the network without much configuration from the default state, this means that the web interface is wide open with default usernames and passwords. Usually admin access to these printers will give you more access and it’s this admin access that I check for.

When you’ve only got a limited amount of time during a penetration test you want to get the best bang for your buck so I created a python script that will go and check for default usernames and passwords on certain models of printers. Below is the python script.

import urllib2
import sys

target = open(sys.argv[1])
eachIPinList = target.readlines(); target.close()
output = open(sys.argv[2], 'w')

for string in eachIPinList:
  try:
    print 'Trying ' + string.rstrip()

    theurl = 'http://' + string.rstrip() + '/index.html'
    username = 'root'
    password = ''

    passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
    passman.add_password(None, theurl, username, password)
    authhandler =  urllib2.HTTPBasicAuthHandler(passman)
    opener = urllib2.build_opener(authhandler)
    urllib2.install_opener(opener)
    pagehandle =  urllib2.urlopen(theurl)
    if pagehandle.getcode() == 200:
      output.write(string)
  except:
    pass

Usage:  at the command line type the following

python nameOfScript.py IPlist.txt output.txt

So this script takes two arguments, 1) A list of IP’s you’ll want to test against, 2) Name of an output file where successful attempts are logged. If you’re having troubles running the script read my other post about running a python script. The output.txt will contain a list of IP’s that the script was able to log into. There are three variables that you’ll have to modify for your particular printer model that you are trying to scan for on your network, they are listed below.

theurl = 'http://' + string.rstrip()  + '/index.html'
username = 'root'
password = ''

Username and password variables should be obvious, simply put in the default username and password of the printer on your network. The only thing you’ll have to change in ‘theurl’ variable is the last quoted string. In my case it was ‘/index.html’, in your case it could be ‘/auth/login.html’. Variable ‘theurl’ builds the http request used to log into your printer’s web interface. A full example is below.

http://192.168.1.5/index.html

This script is doing nothing more than trying to log into the web interface of a printer, that’s it. So the script is not limited to printers, it can be used against any web application that takes a username and password. Although this script can be used against any web application there is a limitation.  This script authenticates to the printer using Basic Access Authentication. There are three main ways to authenticate to a web application.

  1. HTTP Basic Access Authentication
  2. HTTP Digest Access Authentication
  3. HTML Form-based Authentication

So this script will not work if your web application (printer in this case) is using the second or third option. How would you know which one your printer or web application is using? Turns out OWASP has a nice write up on how to test which type of authentication your web application is using. Turns out that no one really uses one and two because they are not as secure as HTML Form-based Authentication wrapped inside SSL. Of course some printers use Basic Authentication because they are poorly built. Basic Authentication actually passes your username and password essentially in plaintext, the only way it tries to hide your username and password is by base64 encoding them which is easily transformed back into plaintext. I don’t want to get lost in the weeds to much but just knowing that your printer is using Basic Authentication is bad enough. Even if you set a strong username and password anyone sniffing network traffic would be able to determine your credentials.

I kicked this script over to Dave Huggins who has tons of experience developing Python applications and he quickly improved upon it by adding the functionality of IP ranges instead of a file. His enhancements can be seen below.

def IPRange(octets, func=""):
  if func == "":
    def func():
      pass

  octets = (octets.split('.'))
  ranges = []
  loop = 0
  for octet in octets:
    if octet.find('-') != -1:
      spot = octet.find('-') + 1
      octets[loop] = int(octet[:octet.find('-')])
      ranges.append(int(octet[spot:]) + 1)
    else:
      octets[loop] = int(octet)
      ranges.append(int(octet) + 1)
      loop += 1
  CurrentAddress = ""
  loop = 0
  output = []
  for one in range(octets[0], ranges[0]):
    for two in range(octets[1], ranges[1]):
      for three in range(octets[2], ranges[2]):
        for four in range(octets[3], ranges[3]):
          for item in (one, two, three, four):
            CurrentAddress += str \
                ((one, two, three, four)[loop]) + "."
              loop += 1
          CurrentAddress = CurrentAddress[:-1]
          output.append(func(CurrentAddress))
          CurrentAddress = ""
          loop = 0
  return output

if __name__ == '__main__':
  import os, sys, urllib2

  def defaultPrinter(ipAddress):
    try:
      print 'Trying ' + ipAddress
      theurl = 'http://' + ipAddress + '/indexConf.html'
      username = 'root'
      password = ''

      passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
      passman.add_password(None, theurl, username, password)
      authhandler =  urllib2.HTTPBasicAuthHandler(passman)
      opener = urllib2.build_opener(authhandler)
      urllib2.install_opener(opener)
      pagehandle =  urllib2.urlopen(theurl)
      if pagehandle.getcode() == 200:
        output.write(ipAddress)
    except:
      pass

  output = open(sys.argv[2], 'w')
  IPRange(sys.argv[1], defaultPrinter)

Happy printer hunting.

fingerprinting SSL tutorial

Tuesday, December 16th, 2008

My tool of choice when it comes to fingerprinting SSL is OpenSSL. There are other tools out there such as thcsslcheck and ssl digger but in my experience these tools tie your hands when you want granular detail. It’s best to get it straight from the horse’s mouth >> OpenSSL. This tutorial focuses on fingerprinting the ciphers and protocols supported by a SSL server, you can obtain tons of information from OpenSSL but this tutorial will not dig into all those aspects. Also this tutorial won’t go into the installation of OpenSSL on your OS just the usage thereof. The first step/command is to determine what kind of ciphers a SSL server may use. This is done by issuing the command

openssl ciphers -v

Output of this command can be seen below.

OpenSSL ciphers command

I use this command on a consistent basis because it lists ciphers from strongest to weakest. So when looking at output from the OpenSSL command you can refer to this list to see how strong or weak the cipher support may be. The “openssl ciphers -v” command has nothing to do with what cipher the web server you are trying to fingerprint supports, “openssl ciphers -v” simply lists the ciphers that OpenSSL can check. I repeat the “openssl ciphers -v” command has nothing to do with the web server you are fingerprinting. You can also check out the man page for additional options when it comes to listing ssl ciphers.

The command you’ll use the most is

openssl s_client

but always with options. The “s_client” argument emulates a SSL client that can connect to a remote device running a SSL service. Another helpful option is “-connect“. You’ll need to supply a name/IP and a port (default port is 4433). Enough talking about the commands lets take a look at some examples.

openssl s_client connect template

The command above is the basic template you’ll use to fingerprint a web server that supports SSL. Instead of IP address you could also use the domain name (e.g. travisaltman.com). See the example below.

openssl s_client -connect error

You’ll notice that an error message is generated in the example above, that’s because no SSL service is listening on port 80 at travisaltman.com. This is a typical error message you will see if openssl fails to connect with a SSL service. Now lets see what a successful connection would look like.

openssl successful connection

The connection may seem to hang but you can kill it with a “Q” or “Cntrl C”, the connection will also eventually timeout. You’ll first notice how much information you get back from the server via the openssl command, initially it can be overwhelming. When it comes to fingerprinting I tend to focus on the “SSL-Session” section because it tells you what protocol and cipher is being used for the communication. In the “SSL-section” above you see that travisaltman.com supports the TLSv1 protocol and the cipher is DHE-RSA-AES256-SHA. This is great that it gives us this information but when it comes to fingerprinting we’ll want to know what other protocols and ciphers the web server supports. Let’s say we wanted to know if a web server supports SSLv2 instead of SSLv3 or TLSv1. The command below tells openssl to only connect using SSLv2, this is done with the “-ssl2” option.

openssl command with ssl2 option

A truncated version of successful output from this command can be seen below.

successful output from ssl2 option in openssl

So you see that my site supports both SSLv2 and SSLv3, in this case the default cipher for communicating over SSLv2 is the DES-CBC3-MD5 cipher. You’ll notice from the “openssl ciphers -v” command that this is the strongest SSLv2 cipher with a key size of 168. You may then be wondering if this SSL server would support weaker SSLv2 keys and also weaker SSLv3 keys. In order to get this granular you would have to specify within openssl which ciphers to check. This is the reason why I love fingerprinting with openssl as oppose to those tools I mentioned at the beginning of this article. So let’s say you wanted to know if a SSL server supported the weakest SSLv2 cipher, which according the output of “openssl ciphers -v” is EXP-RC4-MD5, you can issue the command below.

openssl s_client -ssl2 -cipher EXP-RC4-MD5 -connect travisaltman.com:443

A truncated version of successful output from this command can be seen below.

fingerprinting the weakest SSL2 cipher

So this proves that my SSL server supports the weakest SSL cipher (40 bit key) possible. Looking through the “openssl ciphers -v” output you’ll notice another SSLv2 cipher that supports 40 bit (EXP-RC2-CBC-MD5). If you wanted to figure out if the SSL server supports either one of these SSLv2 40 bit ciphers you could issue the command below.

openssl s_client -ssl2 -cipher EXP-RC4-MD5:EXP-RC2-CBC-MD5 -connect travisaltman.com:443

The -cipher option behaves like an OR, meaning if any cipher in that colon separated list is found supported by the SSL server the command will execute successfully. Taking a look at an example may clear things up a bit. Let’s fingerprint our buddies over at thepiratebay.org and see what ciphers they support.

openssl s_client -cipher AES256-SHA -connect thepiratebay.org:443

I won’t bore you with the output, thepiratebay.org does support this strong cipher, now let’s try the weakest cipher.

openssl s_client -cipher EXP-RC4-MD5 -connect thepiratebay.org:443

No dice, they do not support this weak encryption. Now if you combined these ciphers into one option (-cipher AES256-SHA:EXP-RC4-MD5) you would get successful output. So the point is to be careful when going through the fingerprinting process as you may think a SSL server supports a weak cipher when in fact they don’t. So after you have gone through this process and determined what ciphers and protocols the SSL sever supports what should you take away? This is a very good question and one that lots of people have opinions about. The real answer is it depends on what kind of risk you are willing to accept and how easily accessible you want your application to be. In most cases I would recommend only supporting a SSLv3/TLSv1 256 bit cipher because it’s so easy to implement. Only supporting 256 bit may mean limited access, especially to legacy applications but this is becoming less and less common. Most modern browsers and applications can now easily handle the higher key ciphers. I would also mention numerous vulnerabilites found within SSLv2 including the rollback vulnerability from three years ago. So applications that transmit sensitive information may not want to support SSLv2 at all. Keep in mind that most browsers will attempt to communicate with the highest possible cipher. So even if your SSL server supports SSLv2 for backwards compatibility odds are most users will communicate with the strongest SSLv3/TLSv1 cipher your server supports. You don’t have to solely rely on openssl, you could also test in Firefox if your SSL server allows communications on weaker ciphers. Simply type about:config in the address bar of Firefox, then in the filter type “security.ssl”. From there you can enable and disable various ciphers and see if your SSL sever allows the communication. A screen shot of this can be seen below.

about:config SSL settings within Firefox

That pretty much wraps up this tutorial on fingerprinting SSL. In my spare time I wrote a shell script that automated this process for me given a list of IP’s that were running a SSL sever. This shell script is not ready for prime time but I hope to release a “tools” section soon and place some of my other scripts in there as well. I’m no guru on this subject it’s just simply my experience. As always your feedback is welcome.

travis@hacktop:~$ more references

http://h71000.www7.hp.com/doc/83final/BA554_90007/rn01.html