😛SQL Injection
Beginner's Guide
SQL Injection is a common web application vulnerability that allows attackers to interfere with the queries that an application makes to its database. In this guide, we'll explore the basics of SQL Injection and provide insights into prevention techniques.
1. Understanding SQL Injection
What is SQL Injection?
SQL Injection is an attack technique where an attacker inserts malicious SQL code into a query, manipulating the database to perform unintended operations. This can lead to unauthorized access, data disclosure, and other malicious actions.
How Does SQL Injection Work?
User Input Handling:
Web applications often take user inputs and use them in SQL queries.
Malicious Input:
An attacker provides input that includes SQL code to manipulate the query.
Query Manipulation:
The injected SQL code alters the original query's behavior.
Unauthorized Actions:
Depending on the injected code, attackers can retrieve, modify, or delete data.
2. Types of SQL Injection
Classic SQL Injection:
Involves injecting malicious SQL statements through user inputs.
Blind SQL Injection:
Exploits a true or false condition to infer data without directly retrieving it.
How to detect
Labs:
--UNION
So we know there is a user Jeremy, let's try to test out how strict is the db and how verbose it is:
Basic Input Testing:
When we input the name "Jeremy," the database returns information about Jeremy.
However, if we manipulate the input with a space or any other character, the database search breaks, resulting in a message like "No users found."
Let's test out if we can retrieve more infos:
SQL Injection Testing:
We can exploit potential vulnerabilities by injecting SQL statements into the user input.
Statements like
jeremy' or 1=1#
orjeremy' or 1=1-- -
demonstrate that the application is susceptible to SQL injection. In these cases, the database returns information because the injected condition is always true.
We can also pull some infos and learn more about other tables with UNION statement. Let's say we want to know how many columns are in the table:
UNION Statements for Information Gathering:
Employing the
UNION
statement allows us to retrieve information from other tables.For example, by using
jeremy' union select null,null,null#
, we determine that there are 3 columns being selected.
Extracting Specific Information:
Once we know the number of columns, we can selectively extract information. For instance,
jeremy' union select null,null,version()#
allows us to retrieve the database version.
Now let's see all the tables that exist in the database
jeremy' union select null,null,table_name from information_schema.tables#
jeremy'
: Closing single quote to end the original string.union select null, null, table_name
: Adds a new SELECT statement to the original query. It selects thetable_name
column from theinformation_schema.tables
table, usingNULL
as placeholders for the other columns.from information_schema.tables#
: Specifies the table (information_schema.tables
) from which to retrieve data. The#
comments out the rest of the query.
This query aims to list all the tables present in the database.
we can also modify this to see only the columns:
Similar to the first example, but now it's targeting the
information_schema.columns
table to list all columns in the database.
This query is used to retrieve the names of all columns across all tables in the database.
Now we want to find the username/password of jeremy
explanation:
The provided SQL injection statement is attempting to retrieve the hashed passwords from a table named injection0x01
. Let's break down the components of the statement:
jeremy'
: This part is likely the closing single quote of the user input. The apostrophe is used to close the initial string input in the SQL query.union select null, null, password
: TheUNION
statement combines the results of two SELECT statements. In this case, it's being used to append results to the original query. TheNULL
values in the first and second positions signify placeholders for potential additional columns to match the structure of the original query. Thepassword
column is selected from theinjection0x01
table.from injection0x01#
: This specifies the table (injection0x01
) from which the data is to be retrieved. The#
is a common SQL comment character, used to comment out the rest of the query. This is done to ensure that the injected part of the query doesn't interfere with the existing query structure.
So, in summary, the injection attempts to concatenate the original query with a new SELECT statement that fetches the password
column from the injection0x01
table. If successful, it would return the hashed passwords from that table, assuming the injection point is vulnerable to this kind of attack.
A good resource0 to see what sort of database we're attacking and an efficient cheat sheet is:
--Blind Part
Let's start by adding a scope to our burp suite so we don't get pollution from other website requests:
now we log in to jeremy's account and capture the request:
So now let's try to play around with an SQL injection ' or 1=1#
but be careful, we need to encode like this (you can use ctrl+u):
username=jeremy'+or+1%3d1%23&password=jeremy
username=jeremy'
:This is the original username provided in the input field.
'+or+1%3d1%23
:'+
appends the single quote and the rest of the payload to the original input.or
introduces the boolean condition that is always true (1=1
).%3d
is the URL-encoded form of the equal sign (=
).1%23
is the URL-encoded form of the hash symbol (#
), which comments out the rest of the query.
&password=jeremy
:This is the original password provided in the input field.
Putting it all together, the payload manipulates the original SQL query to effectively say "select everything from the users table where the condition is always true." This is a classic SQL injection technique to bypass login forms when the application doesn't properly sanitize user inputs.
Encoding in the context of SQL injection is often necessary to ensure that special characters or symbols in the injected SQL code do not interfere with the structure of the original SQL query or cause syntax errors. There are a few key reasons why encoding is important:
Special Characters in URLs:
URLs have reserved characters with special meanings (e.g.,
&
,=
,?
). If you include these characters directly in your payload, they might be misinterpreted or cause parsing issues in the URL.
Spaces and URL Encoding:
Spaces are not allowed in URLs, and they need to be replaced. URL encoding replaces spaces with the
%20
sequence. However, in some cases, using+
is also acceptable as a space substitute in the query parameters.
Reserved Characters in SQL:
SQL queries have reserved characters such as single quotes (
'
) and equal signs (=
). If these characters are part of the payload without proper encoding, they might conflict with the syntax of the original SQL query.
Comments in SQL:
The hash symbol (
#
) is often used as a comment character in SQL to indicate that the rest of the line should be ignored. If you want to include a hash symbol as part of your payload, it needs to be properly encoded to%23
to prevent premature termination of your injected code.
Preventing Syntax Errors:
Encoding helps to prevent syntax errors in the SQL query. Incorrectly placed or unencoded special characters can lead to a broken query, resulting in errors and potentially revealing the attempted SQL injection.
URL Encoding Standards:
Adhering to URL encoding standards ensures compatibility across different web applications and servers. It provides a standardized way to represent special characters in a URL.
Let's try to automate the SQL injection process using SQLMap:
in a .txt file, copy and paste the raw request from burp and save it:
(don't do like me, remove the encoded request, come back to
username=jeremy&password=jeremy
)
and then let's call the SQLMap tool:
and we get:
So no injectables.
Let's look back at the request,
There's a request containing a
Cookie
header with a specificsession
value:6967cabefd763ac1a1a88e11159957db
.The content length of the response is initially observed as 1221
SQL Injection Attempt with True Condition:
An attempt is made to inject SQL code into the cookie to check if the server is vulnerable.
The injected payload is
' and 1=1#
, making the condition always true.After changing the cookie, the content length remains at 1221, indicating a successful SQL injection.
Now we are going to test one by one the characters to ask yes or no questions to the server like 'is the first character a, b ,c etc and get a yes or no response. We are going to use SQL's substring function:
Testing Characters Using SQL Substring Function:
The goal is to extract information character by character using SQL's
SUBSTRING
function.The initial test uses the payload
' and substring('a', 1, 1) = 'a'#
.This asks the server if the first character of some string (in this case, 'a') is equal to 'a'.
The content length remains the same (1221), indicating success, but no useful information is extracted.
if we send this:
Purpose of Character Testing:
The subsequent steps involve systematically testing each character to ask yes or no questions to the server.
By incrementing the position in the substring function (
start
parameter), you can identify each character in the string one by one.
Next Steps:
To make the process more interesting and informative, you would need to modify the payload to extract actual data from the database, such as usernames or passwords.
For example, a payload like
' and substring((SELECT version()), 1, 1) = '7'#
might be used to extract the first character of the first username in theusers
table.The input
' and substring((SELECT version()), 1, 1) = '7'#
is attempting to extract the first character of the result of theSELECT version()
query and checking if it is equal to '7'. Let's break down the payload:' and substring((SELECT version()), 1, 1) = '7'#
:substring((SELECT version()), 1, 1)
: This part executes theSELECT version()
query and extracts the first character from the result. The1, 1
parameters indicate starting from the first character and extracting one character.= '7'
: It checks if the extracted character is equal to '7'.#
: The hash symbol is used to comment out the rest of the SQL query.
If the content length of the response remains the same (1221 in this case), it suggests that the condition was true, indicating that the first character of the version is '7'.
The Content-Length changes so we know for a fact that the first value of the version(), is not =7
let's try 8
success
So the SQL versions are often 8.X.X so it's not dumb to think that next character is going to be a .
:
Let's start over and over until we have full version:
so here we have an error message, we test the 5 strings and it errored out on the last 0, now we just have to go 1,2,3,4 until we get our correct content length:
Success! version of SQL is 8.0.3
Now the version is cool but what interests us is the password.
Let's try for user jessamy
our new payload is:
so obviously it would be to long to go all manual and try one by one a bruteforce.
So with a CRTL+i we send our request to intruder to automate the bruteforce:
select the letter to put in a variable and then click the add button
our variable would be the 'p'
then go in the payload section, click enter letters a to z and add them (manually this time but you can download lists for longer stuff
start the attack
While checking the content length of all the letters we now see that z is the only one that gives us a good length.
Let's try using SQLMap now
paste the '1' request in the file '2' and run it using command line 3
--level=2
: This option sets the testing level for SQL injection. The testing level ranges from 1 to 5, with 1 being the least aggressive and 5 the most aggressive. In this case, --level=2
indicates a moderate level of testing aggressiveness. This means that sqlmap
will perform a more comprehensive and in-depth analysis compared to the default level.
Since we do cookie injection we need level 2
during the attack we get a
so let's let SQLMap work for us:
and eventually:
Challenge
We have this basic website that we are going to test out, let's start by seeing what it allows and what it does not:
We are going to try using UNION to find out how many columns there are in this table or in the query being called using null
Hooray, now it's going to be easy -->
it printed out every table so we just have to pull the one that is interesting for us:
Username and Password busted, now let's try using automated tools:
Make a request on the website, capture the packet on burp and copy paste it in a .txt file
Success SQLI! next is XSS 👏
Last updated