Postgresql 设计缺陷CVE-2018-1058 漏洞分析

漏洞描述

2018年3月1日,PostgreSQL全球开发团队发布了多个系列版本的PostgreSQL安全升级。此次升级修复了CVE-2018-1058,该漏洞可以攻击者“劫持”PostgreSQL数据库的函数,从而使高权限用户在不知情的情况下,执行攻击者设定的恶意SQL语句。

漏洞成因

想要理解此漏洞需要先了解PostgreSQL两方面的设计。

1. schemas

PostgreSQL自7.3版本以后允许用户在数据库中创建一类命名空间schemas,允许多用户使用同一数据库而不会互相影响,让数据库里的对象从逻辑上更易于管理。当用户创建数据库后,默认操作设置都是在名为“public”的schema下进行的。例如SELECT * FROM Infomation;实际上等于SELECT * FROM public.Infomation;

在默认情况下,任何用户可以在public下创建对象(新建表、新建函数等操作)。

2. search_path 搜索顺序

因为PostgreSQL提供了schemas这个功能,假如用户新建了一个schema叫做private,在此schema中新建了一个和public中的同名表Information

当用户执行SELECT * FROM Information;没有指定schema时,PostgreSQL就会根据下图流程进行优先顺序的判断:

当PostgreSQL遇到按照顺序遇到“最佳匹配”时,就会选择该schema进行操作(其中$user为当前session用户)。

漏洞利用场景

首先分别创建高低权限用户

administrator: 所有权限
hacker: 只有对public的create权限

目标:获取只有administrator拥有权限读取的private schema表Information中的信息。

在用revoke命令去除hacker账户的对private schema 的SELECT权限之后,hacker没有权限读取到private.Information的数据。

攻击者编写如下恶意Postgresql函数:

1
2
3
4
CREATE FUNCTION upper(varchar) RETURNS text AS $$
ALTER ROLE hacker SUPERUSER;
SELECT pg_catalog.upper($1);
$$ LANGUAGE SQL VOLATILE;

模拟以administrator用户打开另外一个SESSION,可以看见administrator能够读取private.Information下的敏感信息。

当administrator执行select upper((select * from private.Information));时,就会触发hacker的恶意函数。

可以看到hacker权限已经被修改为了SUPERUSER,并且private.Information里的内容也可以读取了。

其中先执行了public.upper而没有执行pg_catalog.upper的原因是这两个函数所接受的参数类型不一样。

对比:
pg_catalog.upper(text)
public.upper(varchar)

varchar与text两种在Postgresql中属于相似但不同的变量类型。

hacker编写的upper函数接受的是varchar类型的参数,而pg_catalog中内置的系统函数接受的参数为text。所以恶意upper函数属于“最佳匹配”,最终administrator会执行恶意upper()函数,导致SQL执行流程被篡改。

漏洞影响范围

影响版本:
Redhat Satellite 5
PostgreSQL PostgreSQL 9.6.7
PostgreSQL PostgreSQL 9.6.4
PostgreSQL PostgreSQL 9.6
PostgreSQL PostgreSQL 9.5.11
PostgreSQL PostgreSQL 9.5.10
PostgreSQL PostgreSQL 9.5.9
PostgreSQL PostgreSQL 9.5.8
PostgreSQL PostgreSQL 9.5.7
PostgreSQL PostgreSQL 9.5.6
PostgreSQL PostgreSQL 9.5.4
PostgreSQL PostgreSQL 9.5.1
PostgreSQL PostgreSQL 9.5
PostgreSQL PostgreSQL 9.4.16
PostgreSQL PostgreSQL 9.4.15
PostgreSQL PostgreSQL 9.4.14
PostgreSQL PostgreSQL 9.4.13
PostgreSQL PostgreSQL 9.4.12
PostgreSQL PostgreSQL 9.4.11
PostgreSQL PostgreSQL 9.4.9
PostgreSQL PostgreSQL 9.4.6
PostgreSQL PostgreSQL 9.4.5
PostgreSQL PostgreSQL 9.4.4
PostgreSQL PostgreSQL 9.4.3
PostgreSQL PostgreSQL 9.4.2
PostgreSQL PostgreSQL 9.4.1
PostgreSQL PostgreSQL 9.4
PostgreSQL PostgreSQL 9.3.21
PostgreSQL PostgreSQL 9.3.20
PostgreSQL PostgreSQL 9.3.19
PostgreSQL PostgreSQL 9.3.18
PostgreSQL PostgreSQL 9.3.17
PostgreSQL PostgreSQL 9.3.16
PostgreSQL PostgreSQL 9.3.14
PostgreSQL PostgreSQL 9.3.11
PostgreSQL PostgreSQL 9.3.10
PostgreSQL PostgreSQL 9.3.9
PostgreSQL PostgreSQL 9.3.8
PostgreSQL PostgreSQL 9.3.7
PostgreSQL PostgreSQL 9.3.6
PostgreSQL PostgreSQL 9.3.5
PostgreSQL PostgreSQL 9.3.4
PostgreSQL PostgreSQL 9.3.3
PostgreSQL PostgreSQL 9.3.2
PostgreSQL PostgreSQL 9.3
PostgreSQL PostgreSQL 9.6.6
PostgreSQL PostgreSQL 9.6.3
PostgreSQL PostgreSQL 9.6.2
PostgreSQL PostgreSQL 9.6.1
PostgreSQL PostgreSQL 9.5.2
PostgreSQL PostgreSQL 9.4.1-1
PostgreSQL PostgreSQL 9.3.1
PostgreSQL PostgreSQL 10.0

未影响版本:
PostgreSQL PostgreSQL 9.6.8
PostgreSQL PostgreSQL 9.5.12
PostgreSQL PostgreSQL 9.4.17
PostgreSQL PostgreSQL 9.3.22
PostgreSQL PostgreSQL 10.3

漏洞修复方案:

官方修复建议:

  1. 超级管理员可以移除所有用户在public schema中创建对象的权限:

REVOKE CREATE ON SCHEMA public FROM PUBLIC;

该操作会导致所有非超级用户无法进行创建对象,可能影响用户管理程序。

  1. 检测对比public中与pg_catalog是否有相似对象,防止已经被恶意篡改。
1
2
3
\df public.*
\df pg_catalog.*
  1. 只设置用户seach_path值为”$user”变量。

ALTER ROLE username SET search_path = "$user";

官方概括了整个防御策略为:”Do not allow users to create new objects in the public schema” strategy。

Comments

⬆︎TOP