SQL Injection
SQL injection is a web attack that tricks a website into running harmful commands on its database. The attacker sends a special string of text that the website wrongly uses in a database query. The database processes the query and sends the results back to the attacker.
This SQL query selects filenames from Dropbox where the owner is "blake," which is provided by the attacker. If the web and database servers don’t filter or encode this input, they’re at risk of SQL injection, letting attackers access any database content or even the database host directly.
Structured Query Language
To perform SQL injection attacks, you need to know how to create SQL statements. SQL is a simple language used to get, change, or remove data from databases, with some variations across different systems.
SQL statements have three main parts: [VERB], [SOURCE], and [REFINEMENT]:
Verb: Defines the action, like SELECT (query), UPDATE (change), or DELETE (remove).
Source: Shows the table(s) the action applies to.
Refinement: Optional, narrows down the action to specific columns or values.
SQL statements use keywords like FROM
to specify the table and WHERE
to start filtering. The SET
keyword is used with UPDATE
to change data in specific columns. The table named dropbox
has three columns: filename
, filetype
, and owner
. Various SQL statements are shown for querying the table with SELECT
, updating columns, and deleting rows. Keywords are shown in uppercase for clarity, but SQL itself does not require this.
Injecting SQL Content
Once you know SQL, you can exploit a weak web app to manipulate SELECT statement results. If users can input data, they might perform SQL injection attacks to access or change database info that shouldn’t be accessible.
To test an app for SQL injection issues, we try different special characters in input fields. We watch for errors or changes in how the app behaves. Once we spot an error, we adjust our input to create a valid SQL query.
An attacker can change an SQL query to get more data than intended. Instead of just getting files owned by 'blake', the attacker uses blake' OR 'a'='a
, which turns the query into SELECT filename FROM dropbox WHERE owner = 'blake' OR 'a'='a'
. The OR 'a'='a'
part always evaluates to true, so the query returns all records from the database, not just those owned by 'blake'. This lets the attacker access extra data.
Testing for Error-Based SQL Injection Vulnerabilities
Testing for SQL injection is like testing for XSS. We change input and check the server's response. For example, the listproducts.php
page uses a cat
parameter for categories. It usually takes numbers, but using 1'
causes a server error.
SQL Union Statement
The SQL UNION clause lets you combine the results of two queries. If you find a server vulnerable to SQL injection, you can add a UNION keyword and a new SELECT query to get data from additional database tables.
In most databases, after using UNION in a SQL query, the next SELECT must have the same number of columns as the previous one. In a SQL injection attack, you might not know how many columns the first SELECT has. You can test by adding more static values to your query (like SELECT ccard, cvv, 1, 2, 3, 4, 5 from payments
). The static values don't pull data from columns but just show fixed numbers.
The attacker adds blake' UNION select ccard, cvv from payments --
to the SQL query, which combines data from the users
table and the payments
table, letting them access both sets of information.
UNION Select Results
We used the UNION
keyword in our vulnerable web app's query to add four columns that give info about MySQL servers:
@@version
: MySQL version numberuser()
: Username and hostnamesystem_user()
: Windows account namedatabase()
: Current database name
The server response shows an error because our query has mismatched columns. To fix this, we used UNION SELECT
with 11 columns to match the other query. We figured out where to place the information by testing where it shows up in the web app.
Sqlmap
Manually checking for SQL injection can take a lot of time, especially without detailed error messages from the database. Automated tools can speed this up by quickly sending multiple SQL queries to check for vulnerabilities. Some commercial tools are Burp Suite Professional and Acunetix, while a popular free tool is Sqlmap.
Sqlmap is a Python tool for finding and exploiting SQL injection issues. Run the sqlmap.py
script with a URL and the -u
option to test for SQL injection. Sqlmap can quickly spot vulnerabilities, like in the cat
parameter, and also check other parameters. Once it finds a problem, it provides details about the web server and database before stopping.
Important Sqlmap Rules
Two important rules to keep in mind when using Sqlmap:
Use a working URL with Sqlmap; if the URL causes errors, Sqlmap might not find vulnerabilities.
Put the URL in quotes to prevent issues with special characters like ampersands (&) being misinterpreted by the shell.
When specifying a URL, always surround the URL with quotation marks, as shown here:
Sqlmap Enumeration
Use Sqlmap to automate database enumeration. After finding a vulnerable HTTP parameter with -u
, run Sqlmap with --dbs
to list available databases. Choose a database and rerun Sqlmap with -D databasename
and --tables
to list its tables.
To check a table, use the previous command with -T tablename
and --columns
to list accessible columns. To get all table data, use -D
for the database name, -T
for the table name, and --dump
to show all entries. For an interactive SQL interface, add --sql-shell
to manually run SQL queries, including WHERE
clauses.
Cloud SQL Does Not Escape Vulnerability
Cloud providers offer databases as part of their cloud services, either as hosted versions of their own products (like Azure SQL Managed Instance) or as separate technologies (like GCE Spanner or Amazon RDS). These cloud databases can still be vulnerable to SQL injection attacks.
SQL injection attacks have become less common because developers now use ORM systems like ActiveRecord, Hibernate, and SQLAlchemy. These tools create SQL statements automatically, reducing the risk of injection attacks. While ORMs can be slower, they improve security by preventing manual SQL statement vulnerabilities.
Cloud databases are not automatically protected from SQL injection attacks. The rise of serverless platforms (like Azure Functions, Amazon Lambda, and Google Cloud Functions) has increased these vulnerabilities.
In serverless systems, developers skip complex ORM tools for better performance, connecting directly to databases. This shift prioritizes speed over security, which can lead to vulnerabilities like SQL injection.
SQL Injection Testing Risk
SQL injection testing can be risky and harm the target organization, depending on the SQL statements used. For instance, the SQL statement from the client profile update page is a good example.
The developer is updating the database to let users change their account names. But, think about the effect of this SQL injection test:
Or removing the comment characters and the following content:
Since the WHERE clause was missing, all database records will be updated to the name Kevin, no matter the customer ID. This is an unpredictable risk, so customers should be ready with tested backups and verify they can restore the database.
SQL Injection Defenses
To defend against SQL Injection, limit the web app's database permissions—don’t give it admin rights. While this won't stop SQL Injection, it can reduce the attacker's access. Filtering input to remove harmful characters is less effective now. Instead, use parameterized queries rather than string concatenation to build SQL statements.
Using parameterized queries prevents SQL injection, is simpler for programmers, and boosts database performance. Security tips that also benefit programmers are easier to adopt. For guidance, check out the OWASP Cheat Sheet here. For specifics on Microsoft IIS and SQL Server, visit this blog.
Enable database logging for failed SQL statements and syntax errors if your database supports it. This helps catch attackers probing for SQL injection but may also log mistakes by internal users. Note that MySQL/MariaDB do not support this. Additionally, use the ModSecurity plugin for Apache, IIS, or Nginx to block SQL Injection and Cross-Site Scripting attacks. ModSecurity can be found at https://modsecurity.org.
Lab 4.5: SQL Injection Attack
In this lab, we will finish our evaluation of the Rook Aviary website as part of the due diligence evaluation prior to acquisition by Falsimentis, Corp. This time we'll identify and exploit a SQL injection vulnerability in the target website.
Let's navigate to the Rook Aviary site at http://www.rookaviary.com.
In this lab, we'll focus on the Employee Directory of the Rook Aviary website. Let's click the Directory link at the top of the browser to access it.
Let's ype "admin" and click Submit.
The site lets us search and shows results. Next, we'll check if it’s vulnerable to SQL injection.
Let's search for admin'
(admin with a single quote at the end), then click Submit and check the server’s response.
The error shows that the web app uses a MariaDB database with SQL. The search term "admin'" is causing an error because it's being added to the SQL query with a wildcard % symbol.
Let's confirm if the system is vulnerable to SQL injection by trying to get extra records. On the Employee Directory page, let's type ' or '1'='1
in the Name field.
Entering ' OR '1'='1
in the search box changes the SQL query to SELECT * FROM users WHERE username='' OR '1'='1';
, which always returns all usernames because '1'='1
is always true.
The site is vulnerable to SQL injection. The attacker’s goal is not just to get extra records but to gather unexpected data from various sources.
We've found that the web app has an SQL injection vulnerability by testing queries manually. Next, we'll use Sqlmap to automate gathering more info from the site.
In Firefox, let's click the Directory link in Rook Aviary to go back to the empty search page. Type "admin" in the search box and click Submit. let's check the URL bar to see the search results, like in the lab example.
To check for SQL injection on the Rook Aviary website:
Use the Search function and copy the URL from the address bar.
Open a new terminal window.
Run Sqlmap by typing
Sqlmap -u
and paste the URL after it.Press Enter to start Sqlmap and check the URL for SQL injection.
Press Enter again to use the default options in Sqlmap.
The message shows that the 'search' parameter is vulnerable to SQL injection. We'll use Sqlmap to exploit this vulnerability and gather data from the database.
Sqlmap can find SQL injection issues and get data from the vulnerable site. Let's add --dbs
at the end to list the databases on the site, then press Enter. Accept the default options when prompted.
Using the --dbs
parameter, Sqlmap lists the databases on the target site. It finds three: information_schema
, test
, and web_app
. Next, we'll list the tables in the web_app
database.
Let's remove --dbs
and add -D web_app
and --tables
. Press Enter to use the default options during the Sqlmap attack.
Sqlmap shows the web_app schema has two tables: comments and users. Next, we’ll get the data from the users table.
Let's remove the --tables
argument, replacing it with two arguments: -T users
(to specify the users table) and --dump
to exfiltrate the contents of the table.
Press Enter to use default cookies with Sqlmap. When asked to save password hashes, type 'y.' For dictionary-based password cracking, type 'n' since it's slow.
Sqlmap will store the password hash in a temporary file in the /tmp directory. Let's use the cat
command to view the file’s contents.
The asterisk before the password hash and the fact that these hashes are from a MySQL/MariaDB server show that they are MySQL password hashes. An attacker could crack these hashes and use them to access the web server's admin interface.
Bonus
1) What is the password for the jleytevidal user?
Let's use Hashcat to crack Sqlmap's temporary password hash. If Hashcat shows "No hash-mode matches," remove the asterisk at the start of each hash with sed
.
Instead of using sed
, we can use a text editor like gedit to remove asterisks from the hash file. Even if we remove the asterisks, Hashcat will still show a "No hash-mode matches" error because it’s not expecting the username before the password hash.
To use Hashcat with Sqlmap password hashes, let's add --user
to our command. We'll remove any asterisks from the hashes and set the hash mode to 300 (-m 300
) for MySQL4.1/MySQL5.
Answer: Florida1
2) What is the password for the rogrady user?
Hashcat won't find the rogrady user's password with just passwords.txt. We'll use --rules
and the best64 rule file to help. With these rules, Hashcat will find the password.
Answer: Vagrant0
Last updated