一. PosgreSQL概述
PostgreSQL[1]是一种流行的开源关系型数据库管理系统。它提供了标准的SQL语言接口用于操作数据库。本文旨在简要介绍在该数据库下的一些特性及其相关越权手法,并展示函数、权限和扩展三个方面的示例。
PostgreSQL由共享内存、一系列后台进程和数据文件组成[2]。
其中共享内存是服务器为数据库缓存和事务日志预留的内存缓存空间;
进程一般分为主后台驻留进程(Postmaster Process)、后台进程(Background Process)、后端进程(Backend Process)和客户端进程(Client Process),主后台进程是PostgreSQL启动时执行的初始化进程,负责数据库init操作,并且是所有进程的父进程,后台进程处理一些数据库的维护工作,例如日志记录、脏内存写入等,后端进程负责返回一些运行时的内存结构,例如work_mem、temp_buffers等,客户端进程则对应每一个连接的用户;
数据库文件可分成数据库、表空间和表,在执行initdb() 后会创建template0,template1和postgres数据库,template0和template1数据库是创建用户数据库时使用的模版数据库,包含系统元数据表,initdb () 完成后,template0和template1数据库中的表是一样的,但是template1 数据库可以根据用户需要创建对象,用户数据库是通过克隆template1数据库来创建的,表空间分为pg_default和pg_global,建表时如果没有指定特定的表空间,表默认被存在pg_default表空间中,用于管理整个数据库集群的表默认被存储在pg_global 表空间中,每个表有三个数据文件:一个文件用于存储数据,文件名是表 OID,一个文件用于管理表的空闲空间,文件名是OID_fsm,一个文件用于管理表的块是否可见,文件名是OID_vm,索引没有OID_vm文件,只有OID 和OID_fsm 两个文件。
二. 前置知识
2.1 函数
PostgreSQL为内建的数据类型提供了大量的函数和操作符且基本位于系统schema pg_catalog下,数据库建立之初就存在,例如version() 函数返回数据库编译版本信息。这些函数或以C语言或以SQL形式被定义声明,其中函数所有者为数据库初始化的超级用户,默认普通用户对大部分系统函数具备执行权限,除涉及到宿主系统操作函数,例如pg_read_file可以读取系统文件,一般被限定为超级用户可用。需要注意的是定义函数时的SECURITY DEFINER将会使函数执行时以函数拥有者身份执行。
2.2 权限
PostgreSQL的权限控制围绕角色(Role)展开,可分为LOGIN:允许登录、SUPERUSER:拥有超级用户权限、CREATEDB:允许创建database、CREATEROLE:允许创建角色、REPLICATION:允许备份、INHERIT:是否继承权限,允许通过GRANT将其它角色赋予该角色、PASSWORD:指定密码。除此之外数据库建立之初已初始化的一些角色具备不同权限,如图1所示,若用户被赋予了pg_read_server_files权限,则可以读取宿主机文件。随后是对各类数据库对象操作的权限,一般由角色、授权目标、权限三部分组成,所有的权限枚举如图2所示,例如grant usage on schema pg_catalog to xxx。
图1 PostgreSQL数据库初始角色
图2 PostgreSQL数据库权限
2.3 扩展
PostgreSQL数据库能够通过动态载入把用户编写的代码结合到它自身中。用户能够指定一个实现了一个新类型或函数的对象代码文件(例如一个共享库),PostgreSQL将按照要求载入它。Extension一般由描述文件.control、执行文件.sql和相应的库.so或.dll组成,创建extension时会调用执行文件执行相应的SQL语句。一般而言,扩展的执行文件都是安全的,但引入三方扩展可能会带来越权风险。
三. 提权示例
PostgreSQL提权的基本思想在于尝试让超级用户执行特定的代码[3]。本文基于上述前置知识将从函数、权限、扩展三个方面各假定一种场景,描述从这三种情况下进行用户提权的手法。图3和图6描述了将test用户提权成为超级用户的权限表变化。
图3 各场景下假定的初始权限表
3.1 函数面
场景:超级用户创建了一个test函数会调用test1函数,test函数是SECURITY DEFINER,而恶意用户xxx可控test1函数。
如图4所示,test函数调用了一个未限定模式名的test1函数,导致恶意用户可以创建一个public下的test1函数,通过执行test函数从而以超级用户的身份执行自己的提权逻辑。
图4 test函数原型
3.2 权限面
场景:恶意用户xxx被授予pg_write_server_files权限。
利用pg_write_server_files权限,通过copy xxx to ‘pg_hab.conf’的方式来复写PostgreSQL的认证逻辑,如图5所示,其中一种方式为使得超级用户无需密码登录。
图5 pg_hba.conf设置
3.3 扩展面
场景:一个恶意三方扩展被引入到数据库中。
恶意三方扩展,会在执行create extension xxx语句时,执行自身配置的sql,而扩展的安装往往是由超级用户的身份来执行的,一种可行的方式是创建提权函数,用以后续恶意用户xxx登入提权。
图6 各场景下提权后的权限表
四. 防御建议
监测
1. 在数据库角色平面可以做到:数据库越权一般伴随着超级用户权限的转移或新增,在数据库角色平面上可以实时查看到这种变化,设置关键触发机制,可以有效感知到数据库越权事件。
2. 在宿主机上可以做到:借助HIDS[4]或者EDR[5] 实时监控宿主机异常行为,可以及时发现并响应数据库服务被攻破后的后续攻击。
防御
1. 纵深防御:多点纵深防御,尤其是云上资产要利用好容器技术和K8s技术的安全机制;
2. 登录凭证是数据库安全的关键之一:可以利用审计工具监测超级用户的认证日志;
3. 最小授权原则:依据用户角色所在的不同业务组的需求授权数据库权限。
参考文献
[1] https://www.postgresql.org/
[2] https://my.oschina.net/postgresqlchina/blog/5329288
[3] https://staaldraad.github.io/post/2020-12-15-cve-2020-25695-postgresql-privesc/
[4] https://baike.baidu.com/item/HIDS/10383239
[5] https://www.ibm.com/cn-zh/topics/edr
内容编辑:创新研究院 马胜
责任编辑:创新研究院 陈佛忠
声明:本文来自绿盟科技研究通讯,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。