08 February 2010

Ettercap & Authenticated Proxies

If ever you find yourself on a penetration test and the scope allows for it, man-in-the-middle attacks are a fantastic way to gain further access.  For instance, if the organization uses an authenticated proxy server, a man-in-the-middle attack can usually recover some authentication credentials.

Clearly, you need to be certain that these attacks are in-scope for your testing.  But, if things converge just right, you'll be sniffing credentials right off the wire, with no password guessing needed - not even a failed login record on a server.  Forcing the disclosure of plaintext passwords, man-in-the-middle attacks, and targetted user attacks are all items that may be disallowed in a penetration test.

Now, if all things converge just right, this can be a great way to gain more access into an environment.  For this attack, you need a desktop network which requires users to use an authenticated proxy server and that network must allow some form of man-in-the-middle attacks.

Most proxy servers that support authentication will support NTLM authentication, but many also come configured by default to support Basic authentication as well.  Most websites that make use of Basic authentication must use SSL in order to prevent the credentials from passing in plain text.  For proxy servers, however, SSL is not an option.  I don't know of a single proxy software package that secures communication between the proxy and end-user.  They all support SSL to the final destination, but when authenticating to the proxy server, there is no encryption.  This makes Basic authentication with proxy servers very dangerous.

For this experiment, we'll be using ettercap, dsniff, and a custom ettercap filter.  We use dsniff to capture the authentication credentials and ettercap to launch the man-in-the-middle attack.  The beauty of ettercap is the filters you can create to take action on packets.  The filter we'll be using does two things.

First, we'll stomp on requests to authenticate to the proxy.  When a browser sends a request to a proxy server, the proxy server will deny the request, telling the browser it must authenticate, and headers in the reply indicate the methods of authentication the proxy server supports.  Using the ettercap filter below, you can stomp on the methods that the proxy server supports and replace them with Basic authentication:

if (ip.proto == TCP) {
   if (tcp.src == 8080) {
      if (search(DATA.data, "Proxy-Authenticate: NTLM")) {
         replace("Proxy-Authenticate: NTLM", "Proxy-Authenticate: BASIC realm=\"Company\"");
         msg("Proxy NTLM killed");
      }
   }
}
This will replace the proxy response saying it supports NTLM with a response saying it supports Basic.  The user will be prompted to type in credentials by their browser.  If the user authenticates, then the credentials will pass in plain text.

Next, we'll do something so that the browser requests don't travel beyond the system performing the man-in-the-middle attack.

if (ip.proto == TCP) {
   if (tcp.dst == 8080) {
      if (search(DATA.data,"Proxy-Authorization: Basic")) {
          kill();
      }
   }
}
 
Just remember, this will prevent a user from accessing the proxy server while the filter is loaded, so be sure to stop the filter when you have some credentials to prevent causing a sustained problem for the user.

14 December 2009

John the Ripper - LM and NTLM

In the last post, I mentioned that I used a purchased wordlist that was 400MB.  A good wordlist is the bread and butter for people trying to break passwords offline, and the wordlist rules engine is one of the prime reasons to use JtR.  No matter which wordlist you prefer, you should become familiar with the rules engine that JtR has.  Using the rules, you can expand each entry of a wordlist to check for different variations of the word.  For instance, if your wordlist only contains a single word, "sled", the rules engine might expand that and also check sleds, sled1, sled2, sled!, Sled, and so on.  I'll be making one soon that does substitutions with numbers, such as sl1de or sl!de (I would've thought that would be included, but it doesn't seem to be).  The rules engine seems to be pretty powerful, but not very well documented, so you may have to play around with it a bit.  The rules engine lets you have a relatively small wordlist that expands into a massive one.


When trying to break a Windows password file, there are some weaknesses that you can use to make breaking these passwords much faster if the system stored lanman hashes as well as NTLM hashes.  Lanman hashes have a pretty big flaw in them, and by default they're stored in all but the newest versions of Windows.  The method used in the lanman hash can only support passwords of up to 14 characters, but the LM hash is actually two hashes.  One hash is of the first 7 characters of the password, and the other hash is of the last 7 characters of the password.


When it comes to passwords, longer is better.  In fact, every time you add a character to the length of a password, the number of possible passwords grows exponentially.  Let's do some math on this.  Suppose a password can only contain lowercase letters.  Also suppose it can only be three characters long.  That means there are 17,576 possible passwords ( 26^3).  If we have only four letter passwords, that number grows to 456,976 possible passwords (26^4).  Along these same lines, at a password guessing rate of 1,000,000 (very conservative estimate - my parallelized system hits over 100 million easily) passwords guessed per second, it would take a little over two hours to run through every possible password that was seven lowercase characters.  If you have two passwords that are seven lowercase characters, even breaking them consecutively would take a little over 4 hours before you would be guaranteed to find the password. 


Contrast the four hours it takes to break two seven-character lowercase passwords with the time it will take to break a single fourteen character password at the same guessing rate: 2,051 millenia.  So by splitting the fourteen-character password into two seven-character passwords, the time it takes to break is reduced by several orders of magnitude.  To make LM hashing even worse, it converts all lowercase letters to uppercase, cutting the potential password alphabet size by 26.

Realistically, to break a lanman hash using one core of my home system using all possible keyboard characters at a length of seven characters would take about two weeks to break, averaging 6,500,000 guesses per second).  If you parallelize, you can cut that time down even more.  Using all 16 cores on my system, all possible lanman passwords can be tried in one day.


NTLM, on the other hand, hashes the password in it's entirety and will take much longer to break than an LM hash would.  However, even if you get the LM hash, this won't let you log in - you still have to find the proper case to match the NTLM hash.  For example, suppose the LM password you recover is ICHOOSEPOORLY! for account Administrator.  You won't be able to take this use it to log in with Administrator.  You'll need to find the correct case somehow.  Breaking the NTLM hash may tell you the actual password is IChoosePoorLy!, but as I mentioned, it takes much longer to break NTLM than it does LM.

But, while it does take much longer to break NTLM, it takes very little time to break LM, even in incremental mode.  So, what if we broke the LM hash first, giving us the all uppercase password, then used a wordlist with all of the possible upper/lower case combinations.  This way you get the password much faster than resorting to incremental mode on the NTLM hash. 

Making a list of all of the possible case combinations manually will be very time consuming.  You could probably write a script to do it for you, but you don't need to do that.  It's already built into JtR.  When you specify "--rules" on the john command line, that tells john to look at the section in the john.conf file labeled List.Rules:Wordlist.  In the default john.conf file, immediately following that section is another named List.Rules:NT.  There are only two rules in this section and they serve only one purpose:  For every word in the wordlist, they expand it into every possible combination of upper and lower case.

First, rename the original List.Rules:Wordlist to something else, say List.Rules:Wordlist-original, and then rename List.Rules:NT to be List.Rules:Wordlist (or do as I do and just make a separate john.conf with this already configured).  Next, you'll need to create a new wordlist file which will have only one entry - the LM password you broke that is all uppercase.  Now if you run john with that wordlist and explicitly tell john to break the NTLM hash using the "--format" option, john will expand the wordlist into all possible case combinations and recover the actual password very quickly.

07 December 2009

John the Ripper - Parallel

With all of this processing power, how could I not think of using it to crack passwords?  With 16 cores, over two weeks worth of work can be done in less than a day!  JtR is widely regarded as the best of the password cracking tools for good reason - I don't know of any tool that can beat it in breaking salted hashes. 

But!  John is not written for parallel processing.  In order to make it parallelized and efficient, some reconfiguration must be done.  And some patching is advisable.  I chose to compile from source so that A) the binary is optimized for my architecture, and B) so I can apply the patches.  I chose to apply the jumbo2 patch, which contains new hash types to break that far exceed the default algorithms.  The post-jumbo2 patch available from the wiki adds some optimizations as well.

After it's compiled with patches, the configuration needs to be modified to support multiple processors.  With JtR comes a filter in the default john.conf that "tricks" JtR into being parallelized, you just need to make a few changes to use it (JtR wiki information).  Be sure to set the correct 'node' and 'total' values for each section.  In my case, I just appended '-X' to the name, with X being the processor number.  For example:


[List.External:Parallel-15]
int node, total;                        // This node's number, and node count
int number;                             // Current word number

void init()
{
        node = 15; total = 16;          // Node 15 of 16, change as appropriate
        number = node - 1;              // Speedup the filter a bit
}

void filter()
{
        if (number++ % total)           // Word for a different node?
                word = 0;               // Yes, skip it
}


If you haven't been exposed to modulo arithmetic before, you may not see what's going on here.  Most programmers have used modulo at some point, but being a programmer isn't a prerequisite for using JtR.  If you haven't used modulo before, here's a brief explanation of the math behind it (don't worry, no math above a 3rd grade level).  "Modulo" is a fancy word for what most of us learned in grade school as "remainder".  The programming operator for modulo is the percent sign, just like the plus sign is the operator for addition.  For example, 5 % 3 = 2.  3 will go into 5 only 1 time, with a remainder of 2.  Another example, 10 % 3 = 1.  3 will go into 10 three times, with a remainder of 1.  See, very simple.  Now, notice that the remainder is never larger than the denominator (in our examples 3).  The only possible values for the remainder are from 0 up to (but not including) the denominator.  In our example, the remainder can be 0, 1, or 2, but will never be 3 or more.  Another interesting property of modulo arithmetic is that every time the numerator (in our examples, 5 and 10) increases by one, the remainder also increases by one, until it reaches the limit, then it resets to zero.  Behold:
  • 2 % 4 = 2 (4 goes into 2 zero times, with remainder=2)
  • 3 % 4 = 3 (4 goes into 3 zero times, with remainder=3)
  • 4 % 4 = 0 (4 goes into 4 one time, with no remainder)
  • 5 % 4 = 1 (4 goes into 5 one time, with remainder=1)
  • 6 % 4 = 2 (4 goes into 6 one time, with remainder=2)
  • 7 % 4 = 3 (4 goes into 7 one time, with remainder=3)
  • 8 % 4 = 0 (4 goes into 8 two times, with no remainder)
  • 9 % 4 = 1 (4 goes into 9 two times, with remainder=1)
  • ...
So if we put all of that together, we have a easy system of counting that is evenly distributed and never exceeds a specific value.  To apply this to JtR, consider this:  JtR generates a lot of passwords, but how can we make it split those passwords up evenly across multiple CPUs?  Well, what that john.conf section is doing is simply numbering each password guess.  For each password, it checks to see if the number is the correct remainder for that CPU.  If it's not, JtR discards the password and gets the next one.  If the remainder is correct for that CPU, then JtR will begin hashing that password as normal.

Once the john.conf file is set up, you'll have to start a separate john process for each core.  I chose to use a bash script to do this, using the schedutil 'taskset' to assign each john process to a CPU.  My inline documentation leaves something to be desired, but it should be easy enough to follow.

#!/bin/sh

MAXCPU=8 # Physical cores per node
WORDLIST_FILE="mangled.lst"


function usage
{
    echo "$0 [algorithm] [charset file]"
    echo "     is the beginning CPU number"
    echo
    echo "     is the file containing passwords to crack"
    echo
    echo "     [algorithm] specifies how john should break them.  If this is not specified, john will guess"
    echo
    echo "     [incremental] is the charset file to use in the incremental phase.  If no value is specified, "all" is assumed."
    echo
    exit
}
if [ ${#1} -eq 0 ]; then
    usage
fi
if [ ${#2} -eq 0 ]; then
    usage
fi

# Set --format Flag
if [ ${#3} -gt 0 ]; then
    FORMAT="--format=$3"
else
    FORMAT=""
fi

# Set --incremental Flag
if [ ${#4} -gt 0 ]; then
    INCREMENTAL="--incremental=$4"
else
    INCREMENTAL="--incremental=all"
fi


STARTCPU=$1
ENDCPU=$(($STARTCPU+$MAXCPU-1))
rm -f session-*.rec
rm -f session-*.log
rm -f session-*.pot
cp -f john.conf.16 john.conf

for i in $(seq $(($STARTCPU)) $(($ENDCPU))); do
    CPU=$i
    while [ $(($CPU)) -gt $(($MAXCPU)) ]; do CPU=$(($CPU-$MAXCPU)); done
    EXTERNAL="--external=Parallel-$CPU"
    W_SESSION="--session=session-$CPU.wlist"
    I_SESSION="--session=session-$CPU.incr"
    W_POT="--pot=session-$CPU.wlist.pot"
    I_POT="--pot=session-$CPU.incr.pot"
    WORDLIST="--wordlist=$WORDLIST_FILE --rules"
    W_PARAMS=" $EXTERNAL $FORMAT $W_SESSION $W_POT $WORDLIST $2"
    I_PARAMS=" $EXTERNAL $FORMAT $I_SESSION $I_POT $INCREMENTAL $2"

    taskset -c $(($CPU-1)) ./john $W_PARAMS && taskset -c $(($CPU-1)) ./john $I_PARAMS &
done


The basic setup is to run parallelized guessing using a wordlist file first, and once those complete, then run incremental mode.  So that taskset line is actually two commands embedded into one that causes the incremental mode to wait until the wordlist file is finished.

Since each node of my setup has 8 cores (note the MAXCPU setting above), I can run on node 1:
./john16.sh  1 pwdfile lm lanman
And on node 2:
./john16.sh 9 pwdfile lm lanman
and have JtR running on 16 cores!

Also note that the script copies john.conf.16 to john.conf when the script starts.  I have multiple john.conf files for different situations, so I keep them in a john.conf.funtion naming format.


Also note that I used mangled.lst rather than the password.lst that comes with JtR.  Mangled.lst is a 400MB wordlist that can be purchased from the JtR author.  If you haven't purchased the wordlists, then modify the script to reflect the default password.lst or your own custom wordlist.

    02 December 2009

    Xen and OpenBSD

    "The best laid schemes of mice and men often go askew."   When I had been planning all of the things I could do with the Xen servers, there were a number of services I wanted available to other virtual machines, such as a firewall, IDS, internal DNS, DHCP, and so forth.  My plans had been to use OpenBSD for all of this, as I've recently become enamored with it.

    For those not aware of OpenBSD, it's a BSD-style system that focuses primarily on security.  It's not user-friendly in any respect, but I must give it kudos in both documentation and security.  The OpenBSD team is adamant about providing well-documented man pages, which is a welcome relief from Linux, where your chances of getting good man page documentation is rather spotty.  I've yet to run across a command that hasn't had a man page. 

    Those of you who dread the second Tuesday of each month should take note - there's only been two remotely exploitable holes in OpenBSD's default install in over 10 years (not to really pick on Windows, Linux doesn't fare well either).  I don't know of any other usable OS that can match that record for security.  In fact, chances are when you hear about a new security feature in the latest version of another OS, there will be someone that says "That's not new, OpenBSD did that two years ago!"  The applications that come with it have been reviewed by the OpenBSD team for security, and a number of security issues in the OpenBSD versions are corrected even before the mainstream editions are.  But enough cheerleading for OpenBSD. 

    Unfortunately, Xen doesn't play well with OpenBSD.  While a usable system can be made, that system can't be a reliable one.  I started by trying to build a web server to hold a yum repo, but that didn't go well.  Xen has a feature that will allow the administrator to mount an iso image in the virtual machine just as if it were a physical CD-ROM drive.  When trying to copy files from a CentOS DVD to the drive, it would copy about twenty files before it would hang.  No indications of a read error, no error messages of any kind.  Just a dead system.

    But there are other ways to skin this cat, so I mounted the iso as a loopback on the Dom0 and brought up an ftp server.  That way, I could just ftp the files from the Dom0 to the OpenBSD DomU.  This is when I discovered networking issues with Xen and OpenBSD.  The drivers for the virtual network cards provided by Xen do not work well with OpenBSD.  The only one that reliably works is the ne2k_pci driver, which is limited to 10Mb.  Not a great speed, but I could live with it.  But, it turns out there's a couple of other issues, which make OpenBSD unsuitable as a persistent DomU that provides a network service. 

    First, an OpenBSD DomU cannot be "paused." When shutting down the Dom0, the shutdown scripts pause all of the running DomUs, and will restart them when the system comes back up.  This means that if you don't shut down the DomU manually prior to shutting down the Dom0, the service running on the OpenBSD  DomU will not be available when the Dom0 is restarted.  If you're using a DomU as a firewall for connectivity and you'll be remotely connecting to this system, that's particularly bad.

    Second, if the system is set up with a ne2k_pci virtual network device, when the system is rebooted, the device becomes a Realtek virtual network device, which doesn't work with OpenBSD.  To restore the ne2k_pci, you must use Xen to shut the DomU off, then restart the DomU. 

    I'm sure this could be worked around by modifying some default scripts, but at this point, I'm not willing to go to the trouble.  Of all the things I wanted to build, the only one that doesn't require a persistent network connection is the certificate authority, so that may end up being the only one that runs OpenBSD.  And that's a real shame, because the pf firewall has some great features I'd planned on using.  I'll now be using CentOS to provide all of those network features, but it's going to be much more of a hassle to lock those systems down than it would the OpenBSD ones. :(

    10 November 2009

    To begin with..

    In the beginning, much of what I'll be writing about may not concern security specifically.  Once a few preparatory things are out of the way, that should change.  For some time now, my skills in security have stagnated.  The systems at home have aged little-by-little, and what once was my lab is now a few Frankenstein-ed systems that don't really work well for a lab.  In addition to that, I've changed jobs over the years, and my current position doesn't afford me the time or equipment at work to do any kind of research.

    Hoping to get myself back on track, I've purchased a 1u Supermicro Twin.  The goal here will be to set up a series of virtual machines and virtual networks that will allow me to do experiments and tinker with things I haven't had the opportunity to do previously.  This blog will primarily serve as a catalog of the interesting things that come up as I get the system configured and begin experimenting.

    I've started by laying down CentOS with Xen to handle it all.  Once it's built up and I'm happy with it, I'll host it in a colo facility.  Until then, I'll be working on it at home.  While the system is a 1u chassis, it's actually two distinct systems, each with 8 intel cores, 16 GB of ram, and two 1.5 TB SATA drives.  So that little 1u system could provide me with 16 cores, 32 GB of ram, and 6 TB of storage (actually 3 - I'll be mirroring).  I've opted to use LVM, with one volume group of 200GB for the OS, and the remaining 1TB as a seperate volume group for the virtual machines, each of which will have their own volume.