Lab: SQL injection attack - querying the database type and version on MySQL and Microsoft
Learn to retrieve the database type and version string using UNION-based SQL injection. Step-by-step PortSwigger lab walkthrough with payloads, query logic, troubleshooting, and defensive insights.
⚠️ Disclaimer
This write-up is for educational and defensive purposes only. The techniques shown here are intended for safe, controlled environments like PortSwigger’s Web Security Academy. Do not apply them to any unauthorized systems.
TL;DR
This PortSwigger lab demonstrates how to identify the database type and version by injecting a UNION-based SQL query.
After confirming the query returned two text-compatible columns, I injected the MySQL/MSSQL-specific version function to extract the DB version string.
✅ Final Payload (lab-safe):
💡 Goal: Display the database version string (8.0.39-0ubuntu0.20.04.1) on the product page.
1 - Understanding the lab goal
The lab challenge clearly states:
“This lab contains a SQL injection vulnerability in the product category filter. To solve the lab, display the database version string.”
So, my goal was to identify which database powers the backend (MySQL or Microsoft SQL Server) and extract its version value.
Expected outcome:
The database version should appear somewhere on the product listing page as part of the UNION query output.
Why this matters: Knowing the database type and version helps assess which syntax, features, and potential exploits (e.g., stacked queries, specific functions) are available - critical knowledge for both ethical hackers and defenders.

2 - Step 1: Recon & capturing the vulnerable request
I began by browsing the product categories and intercepting a request in Burp Suite:
Observation: The category value (Gifts) is directly reflected in the response - a clear sign the server dynamically builds SQL queries based on user input. This makes it a candidate for injection via the category parameter.

3 - Step 2: Determining column count and text-capable fields
To confirm the structure of the underlying SQL query, I followed the same approach as in previous UNION labs.
Initial test payload (to check syntax):
This payload serves two purposes:
- Counts columns - The response displays both
'abc'and'def', meaning the query returns two columns. - Tests data types - Both columns accept text, so string-based functions like
@@versionwill render cleanly.
At this stage, I knew I could safely inject a text-returning SQL function in place of one of the literal values.
4 - Step 3: Building the version extraction payload
The MySQL and Microsoft SQL Server databases both support the built-in function @@version, which returns the database’s version string.
Final payload:
Explanation of each component:
NULL: Placeholder for the first column (to match the structure).@@version: A global variable returning the DB engine’s version string.#: MySQL/MSSQL comment syntax, ignoring the rest of the original query.
After sending this payload in Burp Repeater, the lab’s response displayed the database version string directly within the page body.
✅ Extracted version (lab value):
This confirmed that the database was MySQL, since the version format includes “ubuntu” (Linux-based MySQL build).


5 - Step 4: Understanding why this works
When an application builds SQL queries dynamically from user input, the input is directly concatenated into a WHERE clause, like:
By closing the string and appending a UNION query, we can execute an additional SELECT statement.
In this case:
This retrieves the DB version value as part of the combined result set.
Because both queries return the same number of columns, the DB happily merges them and returns our injected output, which the application displays.
6 - Beginner breakout: Understanding @@version
@@version is a system variable supported by both MySQL and MSSQL. It returns a string showing:
- The database type (MySQL, Microsoft SQL Server, etc.)
- The version number (e.g., 8.0.39)
- Sometimes the OS or build info (e.g., Ubuntu, Windows NT)
Examples by platform:
- MySQL:
8.0.39-0ubuntu0.20.04.1 - MSSQL:
Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 - PostgreSQL: Uses
version()instead of@@version
This function is often used for fingerprinting the backend during vulnerability assessment.
7 - Troubleshooting & alternative checks
Common issues I considered during testing:
| Issue | Cause | Fix |
|---|---|---|
| Error “different column count” | Mismatch in SELECT columns |
Match count exactly (use NULL placeholders) |
| Error “unknown column” | Wrong syntax or DB not MySQL/MSSQL | Try version() for PostgreSQL or banner for Oracle |
| Payload not working | Comment character incorrect | Use -- for standard SQL, # for MySQL, --+ for MSSQL |
| Version string hidden in HTML | Output is escaped | Check full page source (Ctrl+U) |
Beginner tip: The comment symbol matters - if you use -- without a trailing space, the query might still break.
8 - Real-world context
In real-world penetration tests, identifying the DB version helps in:
- Tailoring payloads: Some DBs allow stacked queries or XML functions; others don’t.
- Finding CVEs: Specific DB versions may have known security issues.
- Avoiding noise: You can use non-destructive queries (
@@version) instead of data-extracting ones when verifying injection presence.
Example 1 - Pentest discovery:
A finance app running MSSQL returned Microsoft SQL Server 2014 when tested with UNION SELECT NULL,@@version--.
This revealed outdated software, later confirmed to be missing security patches for SQLi mitigations.
Example 2 - Bug bounty report:
A SaaS platform leaked its internal PostgreSQL 10.15 banner through the same logic flaw.
The researcher responsibly disclosed the finding and earned a bounty, as it exposed backend infrastructure info.
9 - Defensive perspective: Preventing database fingerprinting
Understanding how attackers retrieve version info helps defenders block it early.
1. Use parameterized queries Never interpolate user input into SQL strings. Use frameworks that support parameter binding.
2. Suppress detailed error output DB version leakage often begins with verbose SQL error messages. Use generic error pages.
3. Remove system banners
Disable verbose banners (@@version, version()) from production logs and status pages.
4. Web Application Firewall (WAF) Add WAF signatures for:
UNION SELECT@@versionversion()information_schemareferences
5. Monitor for probes If logs show repeated category queries containing “UNION” or “@@version,” treat this as a high-severity indicator.

10 - Ethical and professional testing
Responsible vulnerability testing involves:
- Always using safe, non-destructive functions (like
@@version) first. - Never running write/update queries in testing environments.
- Reporting findings through authorized channels (PortSwigger labs, bug bounty platforms, internal security teams).
11 - Real-life parallels and impact
- Information disclosure risk: Revealing version info gives attackers insight into unpatched software.
- Supply chain awareness: Identifying DB type helps defenders manage consistent patching across infrastructure.
- Developer awareness: Many devs unknowingly leak DB versions in stack traces or API responses - this lab makes the risk tangible.
Case Study: In 2023, a public-facing portal leaked its MySQL version through an injectable query parameter. Attackers used the version to craft a time-based SQLi exploit specifically tuned for that build. The fix was simply: sanitize inputs and remove verbose banners.
12 - Defensive checklist (for devs and ops)
✅ Always sanitize and parameterize queries.
✅ Disable DB version display and verbose error messages.
✅ Monitor logs for UNION SELECT and version probes.
✅ Regularly patch database engines.
✅ Conduct internal SQLi testing before deployment.
✅ Run bug bounty-style dry runs on staging.
13 - Final thoughts
This lab demonstrates how a single exposed field in a UNION query can leak critical environment details. Extracting the DB version is one of the first steps attackers take to fingerprint systems - and one of the easiest to prevent.
By practicing this lab, I deepened my understanding of how SQL functions differ across databases, and how simple syntax awareness can make or break an exploit.
References
- PortSwigger Web Security Academy – SQL injection UNION labs
- OWASP SQL Injection Prevention Cheat Sheet
- MySQL documentation on
@@version - Microsoft Docs –
@@VERSION