Table of Contents
Summary of the Vulnerability
This lab demonstrates a visible error-based SQL injection vulnerability in an analytics feature that processes the TrackingId cookie. The application incorporates the cookie value directly into a backend SQL query without proper sanitization or parameterized handling.
The attack begins by testing the TrackingId parameter with a single quote ('), which triggers a 500 Internal Server Error, indicating that user-controlled input is breaking the SQL syntax. By appending SQL comments (--), the attacker confirms injection control and suppresses the remaining query logic, returning a normal 200 OK response.
The core technique in this lab revolves around the use of the CAST() function. By forcing database values into an incompatible data type such as INTEGER, the attacker intentionally generates conversion errors. Because those errors are displayed directly in the web response, sensitive values can be leaked inside the error message itself.
Using this approach, the attacker can first enumerate environmental details such as the database version and current database name. The same method is then used against the users table, specifically targeting the username and password columns. Once the password for the administrator account is exposed through the visible error output, the attacker can authenticate as the privileged user and complete the compromise.
Proof of Concept (PoC)
Steps to Reproduce
- Open the SQLi lab and select any category.

- In Burp's HTTP history, Right-click the request → Send to Repeater.
https://<lab-id>.web-security-academy.net/filter?category=Accessories- Trigger an SQLi error by injecting a single-quote (
').

- Append a comment syntax (
--) to ignore the rest of the query. This makes the condition evaluate totrue, and the page renders normally.

- In the context of this vulnerability, we'll be leveraging the
CASTfunction.
What is the CAST function? CAST is a standard SQL function used to convert an expression from one data type to another.
- We'll use the
ANDoperator and cast the data to anINTEGER.

- The page throws an error indicating that when using the
ANDoperator, the expected data type isBoolean. - Modify the query to:
' AND 1=(SELECT 1)::INT--
- The page returns a
200 OKresponse. - Now let's try extracting the database name and version. You can reference the cheat sheet below:
https://portswigger.net/web-security/sql-injection/cheat-sheet
- In the context of this lab, the target is running PostgreSQL 12.22.

- Since this lab was initialized with a known state, meaning the table and column names are already provided, so our only task is to extract the password from the database.
- Running the query at this point causes an error:
ERROR: more than one row returned. To handle this, we need to append aLIMITclause to control how many rows are returned.

- There's still another error, but this time it's different, the query appears to be getting truncated, specifically the comment characters (
--) at the end.

- Check the
TrackingIdparameter, it contains a long string value. Simply clear that value and replace it with a single-quote (').
id=51MEg6PhRk9nCkOz ← this is the TrackingId- Re-run the previous query. The
administratorusername should now be exposed. The same technique applies when switching the target column topassword.

- Below is the extraction of the
passwordcolumn for theadministratoruser.

- Once you've retrieved the credentials, use them to log in as administrator and complete the lab.
https://<lab-id>.web-security-academy.net/login
Impact
- Credential Theft and Account Takeover
- Exposure of Internal Database Information
- Loss of Trust and Compliance Risk
📢 Enjoyed this post? Stay connected! If you found this article helpful or insightful, consider following me for more:
- 📖 Medium: bashoverflow.medium.com
- 🐦 Twitter / X: @_havij
- </> Github: havij13
- ☕ Coffee: Buymeacoffee
🙏Your support is appreciated.