Hacking

Hacking Tools with Python: Part 2

Shubham Mittal
March 8, 2016 by
Shubham Mittal

I know it has been very long since I wrote the first one. This is the second part of writing hacking tools with Python, and before kicking off this one let's quickly revise what we did in the last one.

Starting from very basics of Python, we headed into loops, if else conditions, lists, concepts of pip and easy_install, taking arguments from the user, reading and writing into files, handling exceptions and sending basic requests to web servers.

Earn two pentesting certifications at once!

Earn two pentesting certifications at once!

Enroll in one boot camp to earn both your Certified Ethical Hacker (CEH) and CompTIA PenTest+ certifications — backed with an Exam Pass Guarantee.

Fine, so in this tutorial we will cover:

  1. Taking input from the user in a more managed way.
  2. Sending POST requests and handling the session.
  3. Running basic test for Click-Jacking.

Let's start. For taking the argument from the user, there are two options. Either we write down our code using sys.argv[] and handle all exceptions and edge cases. Or else, we have libraries like optparse and argparse already available, which handles this for us and saves us some time. These libraries allow you to take multiple arguments from a user with the help of switches. The best part is, even if no argument is passed, you manually don't have to handle the same.

For now, we will be using optparse. Here is a sample code snippet to use Optparse.

import optparse

parser = optparse.OptionParser()

parser.add_option('-a', '--firsttest', action="store", dest="first", help="Checks for first argument", default="spam")

parser.add_option('-b', '--secondtest', action="store", dest="second", help="Checks for second argument", default="spam")

parser.add_option('-c', '--thirdtest', action="store", dest="third", help="Checks for third argument", default="spam")

options, args = parser.parse_args()

print "Hi, %s is out first argument" % (options.first)

print "Hi, %s is out second argument" % (options.second)

print "Hi, %s is out third argument" % (options.third)

First we imported the library; then we added multiple switches through which we would like to receive the inputs from the user. Since there are different attributes which we have used in defining these switches, let's discuss them all.

The first argument, i.e. "-a" can be accessed either by passing '-a' after python filename, or could be accessed by saying '- -firsttest.' Another important bit here is the dest attribute. The value passed in this attribute holds the value passed by the user and later we can access the same in our program. Help contains text which you would like to show to your users to understand what all things needs to be passed. This text will appear when user will use –help or –h option after the filename.

Another important thing here is the default value. So what if the user doesn't pass anything. Should program terminate? Well, obviously no. Otparse keeps this in mind and provides you this default value option. You define a value which will be treated as passed value if the user has not passed anything. By using if else stuff, you can handle the same in the program.

Once done, pass all this to a variable called options. Not options.XXX will hold the value of your arguments where XXX is the value you passed in for dest attribute in parser.add_option.

For example, if you want to read value passed in –an argument, options.first will give you the same.

Here is the output of using –h:

Figure 1: Arguments which are accepted by the program

Let's run the program with switches. I am going to pass values to switch a and switch c and here is the output.


Figure 2: Sample run for OptParse

If you would have observed, since I haven't passed value of b, this automatically picked up "spam" from default attribute and printed the same.

Using if else conditions, we can further check this default behavior before printing the same.

import optparse

parser = optparse.OptionParser()

parser.add_option('-a', '--firsttest', action="store", dest="first", help="Checks for first argument", default="spam")

parser.add_option('-b', '--secondtest', action="store", dest="second", help="Checks for second argument", default="spam")

parser.add_option('-c', '--thirdtest', action="store", dest="third", help="Checks for third argument", default="spam")

options, args = parser.parse_args()

#checking for first param

if (options.first != "spam"):

    print "Hi, %s is out first argument" % (options.first)

else:

    print "Please pass something in First Test"

#checking for second param

if (options.second != "spam"):

    print "Hi, %s is out second argument" % (options.second)

else:

    print "Please pass something in Second Test"

#checking for third param

if (options.third != "spam"):

    print "Hi, %s is out third argument" % (options.third)

else:

    print "Please pass something in Third Test"

Quite simple, huh? Just checked if the default value is spam or not, if default value is spam, this means nothing has been passed and lets ask user to pass something. Please make sure that you have understood this part well, because we will be using this optparse thing in most of outr further programs (wherever user input is required).

Moving forward, lets ask user for a hostname and port number and then using regex lets validate the arguments passed. If everything goes fine, we run a basic ClickJacking check on the url, and if something goes bad, let the program freak out and show a custom error message.

Breaking the whole challenge into sub-challenges:

Take hostname and port number from user and validate hostname.

import optparse

import re

parser = optparse.OptionParser()

parser.add_option('-t', '--target', action="store", dest="hostname", help="Host where you want to check for common files.", default="spam")

parser.add_option('-p', '--port', action="store", dest="port", help="Port number to be used while hitting the host", default="80")

#parser.add_option('-', '--search', action="store", dest="search", help="Define any search pattern, string / regex to be highlighted in the response pages.", default="spam")

options, args = parser.parse_args()

hostregex = re.compile("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$")

ipregex = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")

host = options.hostname

port = options.port

if hostregex.match(host):

    print "n[+] Valid host - %sn" % (host)

elif ipregex.match(options.hostname):

    print "n[+] Valid host - %sn" % (host)

else:

    print "n[-] Invalid Hostname / IP Addressn"

Here, we have got the hostname from the user using the switch '-t' and port number using the switch '–p'. Later we have passed these values to variables host and port respectively.

Since we have already imported library re, we can use re.match function to check if the string matches the given regex or not. So we picked two variables, hostregex and ipregex, and passed respective regexes to both of them. Note that these regexes are converted into patterns by using the function re.compile, these patterns will help us validate whether the given value is as per the pattern or not.

Regexes I have used might not be the perfect one, but there are a bunch of websites available to create and validate regexes (we are not getting too comprehensive with that). If you are too lazy, use this link: http://lmgtfy.com/?q=online+regex+generator. Feel free to use other, more valid and more precise regex patterns.

Once we have these regexes ready, we used regexpattern.match function and passed our string to this. If this matches, it returns True, and if not, it returns false. We are then using an if else condition, checked if True was returned on matching with host pattern. If not, we tried the same thing with ipregex, wherein we checked for a valid IP address. If this also didn't match, probably our user has entered some junk value, so let's show him an error message in the Else block.

Here is the output for this program:


Figure 3: Sample run for Hostname / IP Regex Check

As you can see, while we passed www.facebook.com, which is a valid domain name, it matched the regex and hence valid host is printed. Same happens in the case of facebook.com (without www) and 10.0.1.2. All of these values matched regex patterns and worked fluently.

However, faceboo/34.com obviously was not a valid domain name and hence didn't matched the pattern which resulted in the error message.

So this brings us to end of the first sub-challenge. Now since we can differentiate between a valid and invalid host, let's check for ClickJacking vulnerability whenever we have a valid host. But before that let's quickly understand what ClickJacking is.

Imagine a website, say target.com, which can be loaded in an iframe. If the website has a page, say sendmoney.php, which holds a Send money button, and hypothetically let's suppose that clicking on this button sends 1000 rupees to the email id mentioned in the text box next to it. (Now forget Hype of this statement, while pen testing apps, we have seen this stupid thing happening in a bunch of websites)

Now since this website could be loaded in an iframe, as an attacker, we can host a page on our malicious site, say playtestgames.com. This page loaded the URL http://target.com/sendmoney.php in an iframe. Now we make this iframe transparent, and create another layer of a div tag with fascinating objects (say Play Now and Click Here buttons / images), and we position this exactly over the 'Send money' button. Now when a normal user (already logged in the same browser) will come to our site, he might think that this is a game, and indeed, click on the 'play now" button, which ultimately will click the 'Send money' button in the backend. If the user were already logged into his own account, this would result in a debit of 1000 rupees from his account.

ClickJacking is very popular and has affected a huge number of websites, including big internet giants by making them vulnerable to such malicious activities.

An example being this small google search: https://www.google.co.in/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=hackerone%20clickjacking

To mitigate, there are two major options.

  1. X-Frame-Options: This is a server response header and checks for whether or not a browser should be allowed to render a page in a <frame>, <iframe> or <object>.
  2. Framebusting: This technique uses javascript to detect if the site is being loaded in an iframe. As soon as this is caught, it redirects the page to main website page and hence ClickJacking cannot be permformed on this.

Now since we have understanding of ClickJacking attack and its mitigations, lets write down a small utility which will check if the website is vulnerable to clickjacking or not. As of now, we will be focusing on the X-Frame-Header mitigation only.

Here is the small code snippet performing the same task.

import optparse

import requests

import re

parser = optparse.OptionParser()

parser.add_option('-t', '--target', action="store", dest="hostname", help="Host where you want to check for common files.", default="spam")

parser.add_option('-p', '--port', action="store", dest="port", help="Port number to be used while hitting the host", default="80")

#parser.add_option('-', '--search', action="store", dest="search", help="Define any search pattern, string / regex to be highlighted in the response pages.", default="spam")

options, args = parser.parse_args()

hostregex = re.compile("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$")

ipregex = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")

host = options.hostname

port = options.port

if hostregex.match(host):

    print "Checking clickjacking on %s:%s" % (host,port)

    if (port == 443):

        req = requests.get("https://" + host)

    else:

        req = requests.get("http://" + host + ":" + port)

    try:

        print "[-] Not vulnerable to ClickJnX-Frame-Options response header present, Contains value %sn" % (req.headers['X-Frame-Options'])

    except:

        print "[+] Vulnerable to ClickJacking, but check framebusting.n"

elif ipregex.match(host):

    print "Checking clickjacking on %s:%s" % (host,port)

    if (port == 443):

        req = requests.get("https://" + host)

    else:

        req = requests.get("http://" + host + ":" + port)

    try:

        print "[-] Not vulnerable to ClickJnX-Frame-Options response header present, Contains value %sn" % (req.headers['X-Frame-Options'])

    except:

        print "[+] Vulnerable to ClickJacking, but check framebusting.n"

else:

    print "Please enter valid Hostname / IP Address"

As you might have noticed, we have used the previous program to get hostname and port from user. Once we have the same, and checking if the hostname is valid, we will send a simple GET request to HTTP instance of the site, by default (since default is set to port 80 in optparse switch), or HTTPS, if the port is 443, or hostname:portnumber if none of the above conditions are true.

Once the response comes back, if X-Frame option is present in req.headers, display the value of the same X-Frame-Options, and mention the site is not vulnerable. If it is not present, mention the site is vulnerable to ClickJacking, subject to framebusting.

Note that we are checking this by using the variable req.headers['X-Frame-Options'].

With this, we have successfully made a small utility which checks for ClickJacking vulnerability for given host / IP. Here is how the output looks like while passing different hostnames as arguments.


Figure 4: Final Program checking for ClickJacking

I hope the tutorial was easy to understand, and you wrote the utility too. For some more fun, here are few things you can try:

  1. Once you have identified clickjacking vulnerability, create an HTML PoC for ClickJacking.
  2. Read a list of hostnames from a file (as mentioned in the last blog of this series) and then check clickjacking on all of them.
  3. Write a crawler.

In upcoming posts, we will cover a bit more on testing such vulnerabilities along with some cryptographic stuff and android pen-testing.

What should you learn next?

What should you learn next?

From SOC Analyst to Secure Coder to Security Manager — our team of experts has 12 free training plans to help you hit your goals. Get your free copy now.

Thanks a lot. As usual, comments and feedback are much appreciated.

Shubham Mittal
Shubham Mittal

Shubham Mittal is an information security professional with experience in web appsec, network vapt, mobile security testing, config audits and thick client application testing. In free time, he like to hunt for bugs, and study research papers. You can find his technical thoughts on http://3ncrypt0r.blogspot.com