Lab: SQL injection attack - querying the database type and version on MySQL and Microsoft

Lab: SQL injection attack - querying the database type and version on MySQL and Microsoft

October 11, 2025 7 min read

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):

/filter?category=Gifts'+UNION+SELECT+NULL,@@version#
SQL

💡 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.

Lab homepage highlighting the target database version string.


2 - Step 1: Recon & capturing the vulnerable request

I began by browsing the product categories and intercepting a request in Burp Suite:

GET /filter?category=Gifts HTTP/1.1
Host: <LAB_HOST>
Accept: text/html
...
SQL

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.

Captured GET request showing the /filter?category=Gifts 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):

/filter?category=Gifts'+UNION+SELECT+'abc','def'#
SQL

This payload serves two purposes:

  1. Counts columns - The response displays both 'abc' and 'def', meaning the query returns two columns.
  2. Tests data types - Both columns accept text, so string-based functions like @@version will 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:

/filter?category=Gifts'+UNION+SELECT+NULL,@@version#
SQL

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):

8.0.39-0ubuntu0.20.04.1
SQL

This confirmed that the database was MySQL, since the version format includes “ubuntu” (Linux-based MySQL build).

Screenshot showing the final injected request with '/filter?category=Gifts'+UNION+SELECT+NULL,@@version#'.

Resulting webpage showing the extracted database version string, for example, '8.0.39-0ubuntu0.20.04.1'.


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:

SELECT * FROM products WHERE category = '<user_input>';
SQL

By closing the string and appending a UNION query, we can execute an additional SELECT statement.
In this case:

' UNION SELECT NULL,@@version #
SQL

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
  • @@version
  • version()
  • information_schema references

5. Monitor for probes If logs show repeated category queries containing “UNION” or “@@version,” treat this as a high-severity indicator.

Infographic summarizing defensive measures against SQLi fingerprinting: Parameterize, Hide Errors, Patch DB, Monitor UNION probes.


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

Join the Security Intel.

Get weekly VAPT techniques, ethical hacking tools, and zero-day analysis delivered to your inbox.

Weekly Updates No Spam
Herish Chaniyara

Herish Chaniyara

Web Application Penetration Tester (VAPT) & Security Researcher. A Gold Microsoft Student Ambassador and PortSwigger Hall of Fame (#59) member dedicated to securing the web.

Read Next

View all posts

For any queries or professional discussions: herish.chaniyara@gmail.com