Friday, February 24, 2012

Kismet .CSV Log Report Generator

Kismet is an 802.11 layer2 wireless network detector, sniffer, and intrusion detection system. Kismet will not work with all wireless cards, more information can be found here.
Depending on the area you are running kismet, you may find zero networks or hundreds. As more people set up networks, especially in their business areas, it is absolutely necessary to ensure strong encryption is used. It is always a good idea to go warwalking in your area to see which networks are running in your environment.
Kismet outputs 6 log files in the following formats: .xml, .csv, .dump, .network, .weak, and .cisco. Most of the output files are hard to interpret and give a lot of unneeded information for a basic warwalk. I wrote a python script to parse through the .csv log file and generate an .html report. The script ignores all networks with strong encryption or networks with no ssid. The report includes all networks that have WEP or no encryption, with identifying information about each one. This report is only for seeing which found networks are vulnerable.
Feel free to give this python script a try. The only thing needed is a .csv Kismet log file. Changes to the code can be easily made to change what information is included in the report.
Must be logged in to Google Docs:

import csv
import os, string, sys
from optparse import OptionParser

usage = "Usage: %s -i [inputfile] -o [outputfile]" % os.path.basename(sys.argv[0])
parser = OptionParser(usage=usage)
parser.add_option("-i", "--inputfile", dest="inputfile", help="Source file you want to parse. Should be a .csv file. Ex: kismet-output.csv")
parser.add_option("-o", "--outputfile", dest="outputfile", help="Name of the output file you want to create.  Should be a .html file. Ex: csv-parse-output.html")

(options, args) = parser.parse_args()

if ((not (options.inputfile)) or (not os.path.isfile(options.inputfile))) or not (options.outputfile):

outfile = open(options.outputfile, "w+")


print >>outfile, """
<title>Kismet Report</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15" />
<script type="text/javascript">

***END OF CODE SNIPPET - Download file for full code***
After running Kismet and receiving the output files, let's take a look at the .csv log file which contains all of the information found. In total there are 38 attributes that Kismet records when finding a single network.

Now let's run the Kismet Report Generator python script. This works cross platform and will print a nice report as long as the structure of the .csv file doesn't drastically change. If so, it is an easy fix inside the code by using the optparse module. The script takes in two arguments, the first is the .csv Kismet log input file, and the second is the .html output file. An example to run the script would be: -i kismet-log.csv -o kismet-report.html

After running our script we get a nice .html report that is easily readable. The Kismet information is printed into a template which can be changed within the python script. Columns can be sorted by clicking each one if Javascript is enabled.

Feel free to comment, question or criticize. Input is always welcome, thanks!

Friday, February 3, 2012

Attacking Basic Authentication with Burp Intruder

Burp is a platform for testing the security of web applications. Among other things, Burp has the capabilities of an intercepting proxy, vulnerability scanner, and attack tool. Burp's attack tool is called Intruder.

Update: Burp now has the ability to base64 encode two payload lists in a username:password combination by using the custom iterator. More information can be found on this blog.

Because Burp is not a dedicated password cracking tool, some work does need to be done before attacking basic authentication. You may be asking, why use Burp at all? Why not use THC-Hydra or John the Ripper? These are both great options, but Burp Intruder has great functionality with multiple options, an expansive user interface, and also allows you to view each request and response. By seeing each response you are able to quickly figure out if there is any enumeration possible and also separate which credentials actually worked.

One of the most effective ways to attack basic authentication is by using a dictionary wordlist of common usernames and passwords. If you have a small set of usernames or even just one, this attack is much quicker than if you have to guess both the username and password.

As of Burp v1.4, there is no way to directly run a dictionary attack with two wordlists and base64 encode the entire username:password string. Burp does not have the ability to combine a word from two separate wordlists and base64 encode the result. The most you can do is encode each string separately and combine them, however because of how base64 encoding works this does not produce an accurately encoded string. There are few ways around this shortcoming however:

  1. Precompile a username:password wordlist offline. this can either be base64 encoded or not. Burp has the ability to encode a single payload so you can just add a processing rule to the string before Burp sends the request.

  2. Write an extension using Burp Extender to Base64 encode the Auth header. In this scenario you just need to have Burp create the username:password combinations and the extension will do the encoding. I may do a specific post about this later.

In this post I will be focusing on #1, precompiling a username:password list offline and putting that into Burp Intruder. I created a python script to take a separate username and password wordlist and combine them into the username:password format for Basic Auth. There are also other useful options for creating wordlists.

Must be logged in to Google Docs:
Menu Options:
(1)Create user:pass list from ONE wordlist file- This creates every user:pass combination possible with all words
(2)Create user:pass list from TWO files - Each pass per each user (large output file)
(3)Create user:pass list from TWO files - Matches words on the same line from each file

    The first menu option takes one wordlist file with n words as input.  It will then create all possible combinations with the given words.  In total n^2
    username:password combinations are created.  This is best used with smaller wordlists that contain words that are used for both usernames and passwords.
    The output file will be good to test for any weak accounts behind basic authentication.
    The second menu option takes a username worldist with m words and a password wordlist with n words as input.  It will then create m*n username:password
    combinations.  This option is great if you have one or more valid usernames (through enumeration or other methods) or if you have separate wordlists for
    usernames and passwords.  Depending on the wordlists used, this may create a very large text file.

    The third menu option creates "mirrored" username:password combinations by combining the words from each respective file line.  This could be used when you
    have a list of usernames and passwords that may or may not be correct.

import os.path, sys, base64

#Show menu options to user.  Checks for bad input.
userChoice = 0
while userChoice < 1 or userChoice > 4:
    userChoice = raw_input("\n  (1)Create user:pass list from ONE wordlist.\n  (2)Create user:pass list from TWO wordlist files - Each pass per each user (large).\n  (3)Create user:pass list from TWO wordlist files - Matches words on the same line from each file.\n  (4)Quit\n\nSelection: ")
    if userChoice.isdigit() == False:
        userChoice = 0
        userChoice = int(userChoice)

if userChoice == 1:
    #Get input file name from user and check if it exists.
    while True:
        inFileName = raw_input("\nInput File: ")
        if os.path.isfile(inFileName):
            print 'File not found. Try again.'
    infile = open(inFileName)
    #Get output file name from user. Create output file if it doesn't exist.
    outFileName = raw_input("Output File: ")
    outFile = open(outFileName, "w")

    #Calculate number of combinations and estimate total size of the output file using 20bytes per line.
    lines = infile.readlines()
    linesLength = len(lines)
    combinations = linesLength * linesLength
    kilobyteTotal = (20 * combinations) / float(1024)
    megabyteTotal = (20 * combinations) / float(1048576)

    #Show output information.  User may want to limit running time, file size gives a basis to do this.
    print '\nNumber of created combinations: ' + str(combinations)
    print 'Output file size: ~' + str(float(kilobyteTotal)) + ' kilobytes or ~' + str(float(megabyteTotal)) + ' megabytes.\n'

***END OF CODE SNIPPET - Please download file for full code***

So now that we have a username:password wordlist it's time to fire up Burp and put it to use. After making sure that intercept is on, go to the site where the Basic Auth is located.

Fill in anything you want and press 'Ok'. You will now see the GET request with 'Authorization: Basic *Base64 Encoded String*'

Right click anywhere in the request and select 'send to intruder'. At this point you can either drop or forward the request since we already got what we wanted.

Go to intruder and under the positions tab put two payload markers around the Base64 encoded string.

Now go to the payloads tab and load our preset wordlist we created earlier. We still need to Base64 encode the username:password string, so add a payload processing rule to do this.

Almost done! Along the top go to 'intruder' to start the attack. Burp Intruder gives us a nice interface for each attack. We can now view each request and response which includes payload, status, and length. This makes it extremely easy for us to see which payloads work and which don't. We can also look at the status and length to see which pages differ and why.

These methods for attacking authentication can be slightly modified and used to attack other types of authentication.