Authorization disclaimer. This walkthrough is limited to the intentionally vulnerable PortSwigger Web Security Academy lab linked below. Test only systems you own or are explicitly authorized to assess.

Overview

A two-column UNION accepts text and renders version(): abc’ UNION SELECT ‘a’,’b’ – - succeeds and abc’ UNION SELECT ‘a’,version() – - renders the MySQL banner; Microsoft SQL Server would use @@version. The comment syntax and returned banner distinguish the active MySQL path from the Microsoft alternative.

Lab objective/setup

Exercise SQL injection attack, querying the database type and version on MySQL and Microsoft through the endpoint and input recorded in the lab note. abc' UNION SELECT 'a','b' -- - succeeds and abc' UNION SELECT 'a',version() -- - renders the MySQL banner; Microsoft SQL Server would use @@version.

What I observed

abc' UNION SELECT 'a','b' -- - succeeds and abc' UNION SELECT 'a',version() -- - renders the MySQL banner; Microsoft SQL Server would use @@version.

The first `category` UNION places text markers in both columns, confirming two printable positions before the version function is introduced.
The first `category` UNION places text markers in both columns, confirming two printable positions before the version function is introduced.
`abc' UNION SELECT 'a','b' -- -` succeeds and `abc' UNION SELECT 'a',version() -- -` renders the MySQL banner; Microsoft SQL Server would use `@@version`.
`abc' UNION SELECT 'a','b' -- -` succeeds and `abc' UNION SELECT 'a',version() -- -` renders the MySQL banner; Microsoft SQL Server would use `@@version`.

Why it is vulnerable

abc' UNION SELECT 'a','b' -- - succeeds and abc' UNION SELECT 'a',version() -- - renders the MySQL banner; Microsoft SQL Server would use @@version. The application passes that value into the security-sensitive operation without the context-specific validation or encoding needed to prevent this result.

Walkthrough in the authorized PortSwigger lab

Verify two text columns with literal values, preserve the MySQL space after --, and substitute version() into the displayed column. Treat @@version as the SQL Server comparison, not as the observed result for this instance.

Verify two text columns with literal values, preserve the MySQL space after `--`, and substitute `version()` into the displayed column. `@@version` is the SQL Server comparison, while this response identifies MySQL.
Verify two text columns with literal values, preserve the MySQL space after `--`, and substitute `version()` into the displayed column. `@@version` is the SQL Server comparison, while this response identifies MySQL.
Repeater submits a two-column UNION SELECT with version() in the printable column and a MySQL comment containing the required trailing space.
Repeater submits a two-column UNION SELECT with version() in the printable column and a MySQL comment containing the required trailing space.
The shop response renders the MySQL server version string returned by version(), distinguishing the observed DBMS from the SQL Server alternative.
The shop response renders the MySQL server version string returned by version(), distinguishing the observed DBMS from the SQL Server alternative.

Verification

The lab is confirmed when abc' UNION SELECT 'a','b' -- - succeeds and abc' UNION SELECT 'a',version() -- - renders the MySQL banner; Microsoft SQL Server would use @@version. The captured result and the Academy solved state provide the verification; an ordinary status code alone does not.

Impact and defensive lesson

Database banners expose platform and patch clues. Prepared statements remove the UNION path; generic error handling and restricted metadata permissions reduce secondary disclosure.

References