SQL injection attack, querying the database type and version on MySQL and Microsoft
Understanding Database Fingerprinting in SQL Injection
This lab focuses on using SQL injection to identify the backend database type and extract its version, specifically for MySQL and Microsoft SQL Server. The core idea is not just exploitation, but understanding how different database engines respond to manipulated queries. In real applications, a vulnerable query might look like:
SELECT id, name, price FROM products WHERE id = '1'
When user input is not properly sanitized, this becomes injectable, allowing an attacker to modify its structure and append additional SQL logic.
The goal of this lab is to transform that input into a controlled SQL query that reveals system information, such as the database version.
UNION-Based SQL Injection and Query Structure
The main technique used is UNION-based SQL injection. UNION allows combining results from two SELECT statements:
SELECT id, name FROM products
UNION
SELECT username, password FROM users
In SQL injection, this becomes dangerous because an attacker can inject their own SELECT statement into the original query.
A typical injection attempt starts like this:
' UNION SELECT NULL--
or in more extended form:
' UNION SELECT NULL, NULL, NULL--
The reason this works is because UNION requires both queries to have the same number of columns. If the structure does not match, the database rejects the query. This forces the attacker to discover the correct column count before anything useful can be extracted.
Column Enumeration Using NULL
The first step in exploitation is identifying how many columns the original query returns. Since the attacker cannot see the backend SQL, they test different structures using NULL values:
' UNION SELECT NULL--
If this fails, they increment:
' UNION SELECT NULL, NULL--
' UNION SELECT NULL, NULL, NULL--
' UNION SELECT NULL, NULL, NULL, NULL--
This process continues until the application stops returning errors. At that point, the attacker knows the correct number of columns.
NULL is used because it is compatible with all SQL data types, avoiding type mismatch errors during testing. This step is essential because without matching column counts, UNION injection cannot proceed.
SQL Comments and Query Termination
Once the correct structure is identified, comments are used to terminate the original query so that only the injected part executes.
In MySQL, both of the following are commonly used:
' UNION SELECT NULL, NULL--
' UNION SELECT NULL, NULL#
The purpose of -- or # is to ignore the rest of the original query. For example, if the backend query is:
SELECT id, name FROM products WHERE id = '1'
After injection, it becomes:
SELECT id, name FROM products WHERE id = '' UNION SELECT NULL, NULL--
Everything after -- is ignored, preventing syntax errors.
MySQL supports both -- and #, while Microsoft SQL Server only supports --, which is one of the fingerprinting differences.
Reflection Testing Using String Injection
After discovering the correct number of columns, the next step is identifying which columns are visible in the response. This is done by injecting test strings instead of NULL:
' UNION SELECT 'test', 'test'--
or for multiple columns:
' UNION SELECT 'a', 'b', 'c'--
The attacker then observes which values appear in the HTTP response. Only reflected columns are useful because they represent data that is actually rendered by the application.
This step is critical because even if injection is successful, non-reflected columns cannot be used to display extracted data.
Extracting Database Version in MySQL
Once structure and reflection are confirmed, the attacker can extract system information. In MySQL, database version is available through the system variable @@version.
A successful payload looks like:
' UNION SELECT @@version, 'test'--
This replaces one of the output columns with the database version string.
The response typically includes version information such as:
MySQL version number
Build details
Sometimes OS or architecture information
This confirms both successful injection and backend fingerprinting.
Microsoft SQL Server Version Extraction
In Microsoft SQL Server, version information is also accessible but behaves slightly differently. The equivalent system variable is:
@@VERSION
A typical injection payload in MSSQL would be:
' UNION SELECT @@VERSION, NULL--
Unlike MySQL, MSSQL often returns a more detailed string that includes:
SQL Server version
Operating system information
Build number
Architecture details
This difference is very useful for fingerprinting because the format of the output immediately reveals the database engine.
MySQL vs Microsoft SQL Server Behavior Differences
Although both databases support SQL injection and UNION-based queries, they differ in important ways that affect exploitation.
MySQL is more flexible in handling mismatched data types and supports multiple comment styles such as # and --. It is also more permissive when dealing with implicit conversions in UNION queries.
Microsoft SQL Server is stricter. It enforces stronger type matching rules and does not support # as a comment. It also has a more structured and verbose version output format through @@VERSION.
These differences mean that payloads are not interchangeable. A working MySQL injection may fail in MSSQL without modification. This is why fingerprinting is always done before deeper exploitation.
URL Encoding of SQL Injection Payloads
In real HTTP requests, special characters must be URL encoded to ensure they are transmitted correctly. Without encoding, characters may be blocked or misinterpreted by browsers or servers.
For example, this payload:
' UNION SELECT @@version, 'test'#
becomes:
%27%20UNION%20SELECT%20%40%40version%2C%20%27test%27%23
Each encoded character has meaning:
'becomes%27space becomes
%20@becomes%40#becomes%23
Encoding ensures the payload survives HTTP transmission and is interpreted correctly by the backend database.
Overall Methodology of the Attack Flow
The entire process follows a structured logical progression. First, the injection point is confirmed. Then the column structure is discovered using NULL-based enumeration. After that, reflection testing identifies which output columns are visible. Finally, system-level information such as the database version is extracted.
Each step depends on the previous one. Without knowing the structure, UNION fails. Without reflection mapping, extracted data is invisible. Without fingerprinting, further exploitation becomes unreliable.
This structured progression reflects how real-world SQL injection is performed in professional penetration testing scenarios.
Core Security Insight
The key takeaway from this lab is that SQL injection is not a single exploit but a reasoning process. It exists because applications fail to separate data from executable logic. When user input becomes part of SQL syntax, the database executes it as code.
Understanding SQL injection requires understanding how databases interpret structured input. The attacker is not bypassing the system but interacting with it under its own rules and constraints.
This mindset is what transforms SQL injection from memorized payload usage into a structured analytical process applicable across all injection types, including UNION-based, blind, and time-based techniques.
Comments