Hello GreenHackerz readers......
This article is about a technique which is used for hacking the websites and the technique is very popular among hackers. The technique is known as SQL Injections.
So, lets start reading ............
What
is SQL Injection
SQL injection is a code injection
technique that exploits a security vulnerability occurring in the database
layer of an application. The vulnerability is present when user input is either
incorrectly filtered for string literal escape characters embedded in SQL
statements or user input is not strongly typed and thereby unexpectedly
executed. It is an instance of a more general class of vulnerabilities that can
occur whenever one programming or scripting language is embedded inside
another.
0x00
- Intro
All the information contained in the
article is from personal experience, if I don't go over something that you
currently do or have seen in SQL injections, its because I do not use it; not
saying I'm right just that's how it is. As you should already know, extracting
database information from a server without administration approval is illegal
and I cannot be held accountable for any malicious actions executed after
reading this article.
0x01
- What is MySQL
"SQL" stands for
"Structured Query Language," which simply allows users to send queries
to the server database. There are different types of SQL such as MySQL, which
is Microsoft's version of the language and also has some different commands as
well as syntax.
0x02
- Finding SQL Injections
Before jumping into this topic I want to explain to you
about comments in MySQL. There are three variations to a comment in this
language:
As you should already know a comment just blocks out a section so it will not
be executed through the query. Typically, anytime you see a page from a website
that takes in a parameter such as:
(not saying injections are narrowed down to only id parameters but they are
quite common) you may want to test the page for a vulnerability. The simplest
way I know of to check for a vulnerability is to add:
to the end of the URL and see if the contents of the page change, even the
slightest bit, if they don't then add
(it doesn't have to be 1=1 or 1=0 just something that returns true for the first
statement and false for the second) and see if it changes after the second. If
the contents change after the second query then you have a vulnerability.
0x03
- Gathering Information
To make your job or life a little easier you should look
around the site some to gather information on what you are trying to retrieve.
For instance, if the site has a user registration look at the source code for
the page and take note of the field names they use (most developers are lazy
and use the same names for simplicity); you can also look around the site for
more vulnerabilities. Alright so once you have found some good information to
look forward to, its time to find out how many columns are being selected from
the database from the original query. This is an important step because if
number of columns you "select" and the number from the original are
not identical, the injection does not work! To find out the number of column
you simply add "order by x" on the end of your vulnerable URL
replacing "x" with a increasing number until you get an error
http://www.site.com/vulnerable.php?id=4
order by 9--
|
the number of columns being selected is the value of x before the error.
0x04
- The Injection
I
suppose this is where some people get confused. In MySQL
in order to combine two query statements you can use the keyword
"union", you can also include the keyword "all" which will display all
results (default property of union is to remove duplicate results
from display). After your "union all" you also need to include the
keyword "select" since we are going to want to select database
information and display it on the screen so far you should be looking at
something similar to:
http://www.site.com/vulnerable.php?id=4
union all select
|
Continuing the injection like the previous example will work fine, but
it will
also display all the original results as well as our new results,
typically to
bypass this I, as well as most of the other people exploiting SQL
injections, replace the id value, in the case of our example it would be
4, with one of the
following:
or any result that would not be in the database, this way the original select
query will not result anything but our new injected select query will display.
In SQL each column being selected must be separated by a comma(,) so if your
vulnerable site is selecting 4 columns with the original statement (which was
found earlier when we were gathering information using the "order
by") you would just concatenate those on your injection; I like to set
each column to a different numeric value that way i can keep track of which
columns are actually being displayed on the screen. So far, if everything has
been going good, you should have an injection URL looking something like:
http://www.site.com/vulnerable.php?id=-1
union all select 1,2,3,4--
|
If not then go back and keep reading it until you figure it out. The last part
of our injection setup is the telling the query which table to
"select" the information from; we do this with the keyword "from
table"...pretty self explanatory right? So for example, we have a
vulnerable site that has 4 columns being selected and we want to look at the
"users" table we can have a set up such as:
http://www.site.com/vulnerable.php?id=-1
union all select 1,2,3,4 from users--
|
Easy enough so far, now is where it gets a little more difficult, but not too
much.
0x05
- Tables and Columns
Depending on the version of MySQL the administrators are
running on the server, finding table and column names can be very easy or
somewhat irritating. There is an easy way to figure out what version is running
on the server, can you guess? If you did not guess version(), why the hell not,
its like one of the easiest and self explanatory things ever! Anyways, replace
one of the columns in your injection that displays on the screen with the
function call version() and this will tell you which typically its either 4.x.x
or 5.x.x. If they are running some form of version 4 then you're basically on
your own when it comes to figuring out table and column names (I'll post some
examples of common names later); though if version 5 is implemented then your
life is easy. As of version 5.1 of MySQL the developers began to automatically
include a master database on the server called INFORMATION_SCHEMA. Within
information_schema there are tables that give information about all the tables,
columns, users, etc on the entire SOL server (to find more about the structure
of information_schema and the table/column names visit http://dev.mysql.com/doc/refman/5.0/en/information-schema.html).
Once you figure out a table name and some column names within that table you
want to look at just place them into our injection setup from before; suppose
we have a site that has a "users" table and columns "user"
and "pass" and the second and third columns are displayed onto the
screen, we could view these by an injection such as:
http://www.site.com/vulnerable.php?id=-1
union all select 1,user, pass, 4 from users--
|
This example will display both the user and pass onto the screen in the given
positions, though what happens if only one column is selected or displayed? In
MySQL there is function called concat() which simply concatenates fields
together so to simplify our previous example we could have:
http://www.site.com/vulnerable.php?id=-1
union all select 1, concat(user,0x3a, pass), 3, 4 from users--
|
"0x3A" is just a colon(:)
in hexadecimal, simply to separate the two fields for my own viewing.
0x06
- Narrowing down the Selection
Typically when performing a SQL injection there are multiple
results you want to look at or possibly just one individual. There are a couple
of ways to narrow down your selection first way is to use the "where"
keyword is just takes a logical parameter such as "where id=1" which
would look in the id column in the table and find which row is equal to 1. The
next way to to use the "limit" keyword; this way is a little more
useful since you do not need to know an additional column name to increment
through the selections limit takes two parameters, where to start the selection
and how many to select. So in order to select only the very first
"user" from the table "users" using the "limit"
keyword you could have:
http://www.site.com/vulnerable.php?id=-1
union all select user from users limit 0,1--
|
to look at the rest of the users individually you just increment the 0 up until
you get an error. In order to look at all the results in a single swipe you can
use the function group_concat() which works very similarly to concat() except
it displays all the results for the given column(s) separated by a comma(,)
(the comma is just the default, you can change it by using the
"separator" keyword and indicate a symbol to use).
0x07
- Obstacles
Excluding the fact that version 4 in general is an obstacle,
there are a few different things web developers can do to try and make sql
injections a little more difficult. The most common of these annoyances would
be magic_quotes; basically magic quotes disallows any type of quotation marks
and breaks it by adding a back-slash(\), which of course is going to mess up
your injection. To get around this there is the nice little function char();
char() takes ascii values and generates the corresponding character value, thus
eliminating the need for a quote. Example time...say we want to look at the
"pass" column FROM the table "users" but only WHERE the
"user" column is only equal to "admin" and the site only
selects one column from the original query, easy enough right? we learned this
earlier
http://www.site.com/vulnerable.php?id=-1
union all select pass from users where user="admin"--
|
curve ball! the developers have enabled magic_quotes therefore your
"admin" will not work properly...i know its sad. To fix it we simply
take the ascii values of each character (http://crashoverron.t35.com/ascii.php)
so now we get
http://www.site.com/vulnerable.php?id=-1
union all select pass from users where user=char(97,100,109,105,110)--
|
TA-DA! injection fixed. Also another safety feature they try to block us with
is regular expressions to search our input, but often times they have their
expressions set to such narrow possibilities that you can bypass them by simply
changing the case, the comment symbol, or replacing spaces with "+"
(SQL is not case sensitive, it also sees "+" as a space filler much
like a space).
0x08
- Additional opportunities
Although I said before version 4 was a pain in the ass, I
have also noticed a nice feature common to version 4 vulnerable sites I have
come across in my adventures; this feature would be the function load_file(),
not saying the function is exclusive to version 4 but from my experience it is
most commonly enabled for current users by developers for some reason in this
version. load_file() acts just as file_get_contents() from PHP in that it
returns the contents of the file into a string format. If enabled this allows
for more than just SQL styles hacks on the server, it now allows for LFI
vulnerabilities as well. Although, load_file() needs to have the exact full
path to the file you are trying to open, for example: /home/CrashOverron/Desktop/file,
and if input as a literal string then it must be encased in quotes, which
brings back the issue of magic_quotes but as before just use the char()
function. The next interesting feature that is hardly ever possible, but I have
seen happen, is the use of the "INTO OUTFILE" keywords. This is the
exact opposite of load_file(), in order to use either of these features the
current user that MySQL is running as must have the FILE privilege on the
server. Again, the full path is needed for the output file, which cannot be an
existing file, though unlike load_file() the char() function does not fix
magic_quotes. Time for an example of both, here is the situation: vulnerable
site has 1 column selected also has a "users" table. load_file no
magic_quotes:
http://www.site.com/vulnerable.php?id=-1
union all select load_file('/etc/passwd')--
|
load_file with magic_quotes:
http://www.site.com/vulnerable.php?id=-1
union all select load_file(char(47,101,116,99,47,112,97,115,115,119,100))--
|
INTO OUTFILE:
http://www.site.com/vulnerable.php?id=-1
union all select "test" INTO OUTFILE "/etc/test" from
users--
|
0x09
- Blind SQL Injection
Blind
SQL injection occurs when the original select query
obtains column information but does not display it onto the screen. In
order to
continue through a blind SQL injection you must basically brute-force
any value
you want to know. There are a few functions we can use in conjunction
with each
other that make this quite easy yet tedious, those would be the mid()
and the ASCII() functions. mid() is MySQL's sub string function and
ascii() does the
exact opposite of char() it takes a character and exchanges it with the
corresponding ASCII numeric value. Doing this allows us to determine the
range
each of our desired value is in on the ASCII chart, thus narrowing each
down
until we find a match. Example situation; we have found a site that is
vulnerable to blind sql injection and we want to figure out which user
MySQL is
currently running as, our injection sequence could look something like:
http://www.site.com/vulnerable.php?id=1
and ascii(mid(user(),1,1)) < 97--
|
(this will tell us if the first letter in the user is above/below "a"
then we can change the 97 to a different value until we find the character to
the first letter)
http://www.site.com/vulnerable.php?id=1
and ascii(mid(user(),2,1)) < 97--
|
(just repeat as before and keep incrementing through the letters and you will
eventually have the current user)
0x10
- Login Bypass
Ok, I left this for towards the end because it is not really
very common anymore but I will through it in because I suppose you may run across
it some day (I have only ran across this vulnerability once in real world). The
concept behind the SQL login bypass is quite simple; in order to execute the
exploit you input a username into the user field then in the password field of
the form you put:
this just ends the current password field and includes the logical OR with a
constant true statement. A simple MySQL login script could look like:
<?php
$user = $_POST['user']; $pass = $_POST['pass']; $ref = $_SERVER['HTTP_REFERER'];
if((!$user) or (!$pass)) { header("Location:$ref"); exit(); } $conn =
@mysql_connect("localhost", "root", "blah") or
die("Could not connect"); $rs = @mysql_select_db("db",
$conn) or die("db error"); $sql = "SELECT * FROM users WHERE
user=\"$user\" AND pass=\"$pass\""; $rs =
mysql_query($sql, $conn) or die("query error"); $num =
mysql_numrows($rs); if($num != 0) { echo("Welcome $user"); } else {
header("Location:$ref"); exit(); } ?>
so if we input the user "admin" and "" or 1=1--" as
the password the query sent to the server is going to look like this:
"SELECT * FROM
users WHERE user="admin" AND pass="" or 1=1--"
|
so the server is going to select row where the "user" equals
"admin" and disregard if the "pass" is correct because it
is asking if the pass OR 1=1 are true, since 1=1 is always true you bypass the
pass section.
0x11
- Useful Keywords/Functions
UNION
ALL SELECT AND/OR ORDER BY WHERE LIMIT LIKE INTO OUTFILE char() ascii() mid()
concat() group_concat() load_file() user() database() version()
That's all about the SQL.... Hope u like it ...
Leave a comment or suggestion...