0x00 前置知识
CLR:通用语言运行平台(Common Language Runtime,简称CLR)是微软为他们的.NET的虚拟机所选用的名称。它是微软对通用语言架构(CLI)的实现版本,它定义了一个代码运行的环境。CLR运行一种称为通用中间语言的字节码,这个是微软的通用中间语言实现版本。
存储过程:是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象,它可以视为数据库中的一种函数或子程序。
0x01 测试环境及使用工具
操作系统:Windows Server 2012 Datacenter
数据库版本:SQLServer 2012
Framework版本:v4.0.30319
开发平台:VisualStudio Professional 2015(14.0.25431.01 Update 3)
使用工具:winhex
0x02 通过CLR在SQL Server中执行代码简述
利用思路:使用VS创建SQL Server项目,使用公共语言运行时(CLR)来创建自定义存储过程,SQL Server将允许执行任何受CLR支持的编程语言代码,比如C#。
限制条件:
需要创建自定义存储过程的能力。
SQL Server上启用CLR。
并且要求SQL Server服务帐户具有执行命令/代码的必要权限。
0x03 通过CLR在SQL Server代码执行实现
1、CLR代码执行方式
创建CLR有两种方式:
①使用DLL文件进行创建
CREATE ASSEMBLY assembly_name from ‘dll_path’
②使用文件16进制流进行创建
CREATE ASSEMBLY assembly_name from 文件十六进制流
第一种方法,需要上传我们所需要的存储过程DLL,攻击门槛高。相比之下第二种方法,只需要一个注入点就可以了。所以本文重点讨论第二种方法的CLR攻击实现。
2、详细测试步骤
①在VS 2015中创建CLR C#项目:
图1 创建CLR项目
新建一个SQL Server的数据库项目,此模板需要在VS安装时勾选SQL Tool选项。
②设置项目属性:
图2:项目属性设置
项目属性设置分为两部分:
在项目设置中,选定目标SQL版本,此处我选定的为SQL2012。
在SQLCLR中设置权限级别UNSAFE,以及选定所用语言为C#。
③添加新建项
图3:新建项目
右键项目,点击添加→新建项→SQL CLR C#→SQL CLR C#存储过程。
④添加代码
关键代码为在SqlStoredProcedure1 ()内,代码逻辑很简单,创建一个cmd进程执行 whoami /user 并把结果写入到本地txt文件中。
⑤进行编译,解压出我们所需要的16进制流数据
图4:解压dacpac文件
找到编译文件夹,将dacpac文件解压出来,获得其中的sql文件。
图5:获得到16进制文件流数据
⑥执行sql语句
逻辑就是创建存储过程,以及获得一个实例,去执行它。
⑦结果
找到C:/sql_exec目录下,里面确实有执行结果,并且所有者为MSSQLSERVER。
0x04 深入研究
1、执行方式的异同
之前所说过,SQL Server执行CLR,有两种方法,一种是引入文件,第二种是FROM文件流。针对这两种方法,我们进行对比。
通过WinHex,打开代码编译后得到的dll文件。进行查看:
图8:编译后得到的dll
之后我们对比解压出来sql文件中的16进制流文件。进行对比:
图9:得到sql文件
经过对比,发现里面的内容是一样的,所以在SQL Server执行过程中,对两种方法的效果是一样的。
2、提权行为分析
在此次试验中,执行sql语句的用户是testUser,并不是高权限的数据库角色。对testUser仅分配了CREATE ASSEMBLY, CREATE PROCEDURE, EXEC权限。
图10:用户
CLR执行的环境是在SQLServer,通过CREATE ASSEMBLY, CREATE PROCEDURE创建存储过程,实例化操作对象,之后再经过EXEC执行。
在整个过程中,对代码进行执行的对象不是数据库角色testUser,而是数库自己本身。之前设计CLR时,执行“whoami/user”指令,打印出的结果为“nt servicemssqlserver”,并且查看生成文件属性中的所有者,是mssqlserver。
在低权限的数据库用户对象,可以通过SQLServer中CLR代码执行,进行获得数据库权限,这也是一种提权的方式,因为这个操作本身的执行者,是数据库,而不是数据库用户。
①程序集的权限的安全策略
决定授予程序集的权限的安全策略定义在三个不同的位置:
1.计算机策略:这是对安装了SQL Server 的计算机中运行的所有托管代码都有效的策略。
2.用户策略:这是对进程承载的托管代码有效的策略。对于 SQL Server,用户策略特定于 SQL Server 服务运行时所使用的 Windows 帐户。
3.主机策略:这是由 CLR(在本文中为 SQLServer)的主机设置的策略,对该主机中运行的托管代码有效。
在SQL Server 中运行时授予托管代码的代码访问安全性权限集为以上三种策略级别授予的权限集的交集。即使 SQL Server 向加载到 SQL Server 中的程序集授予一个权限集,赋予用户代码的最终权限集仍可能受用户和计算机级别策略的进一步限制。所以,针对CLR代码执行的权限最高只是到SQL Server本体,也就是MSSQLSERVER身份。
②SQL Server 主机策略级别权限集
除此之外还有SQL Server 主机策略级别权限集,分别为SAFE、EXTERNAL_ACCESS和 UNSAFE。
SAFE:由具有 SAFE 权限的程序集执行的代码无法访问外部系统资源,例如文件、网络、环境变量或注册表。
EXTERNAL_ACCESS:与 SAFE 程序集具有相同的权限,此外,还可以访问外部系统资源,例如文件、网络、环境变量和注册表。
UNSAFE:允许程序集不受限制地访问SQL Server 内部和外部的资源。从 UNSAFE 程序集内部执行代码时也可以调用非托管代码。
下表总结了授予 SAFE、EXTERNAL_ACCESS 和 UNSAFE 权限集的权限以及为其设定的限制。
所以,之前创建CLR项目,将权限级设为UNSAFE。
③CLR程序执行的过程
对于整个利用流程,如下图:
高权限数据库用户,创建的低权限testUser用户,通过创建存储过程创建CLR执行代码,并且程序集的主机权限设置为了UNSAFE,这样就可以不受限制地访问 SQL Server 内部和外部的资源。但是对于程序执行的对象,是CLR,由于用户策略限制,所以运行的最高身份是MSSQLSERVER。
0x05 现实意义
今天讨论的CLR代码执行开拓了另一种思路。回顾之前的SQL Server执行系统命令常用的方法,有这么几种:
1、XP_CMDSHELL:
exec master..xp_cmdshell "whoami"
但是默认情况下xp_cmdshell是关闭的。需要sp_configure开启
2、SP_OACREATE
在移除xp_cmdshell的情况下,可以使用SP_OACreate
3、修改注册表
修改注册表比较鸡肋,需要对机器进行重启。
相比以上三种方式。CLR代码执行,执行对象是MSSQLSERVER,权限更高。并且不仅仅可以执行操作系统命令,还可以借助C#代码,使操作更丰富,更灵活。
但是,SQL Server执行CLR,必须要满足:
1、数据库开启CLR.
2、数据库用户有CREATE ASSEMBLY, CREATE PROCEDURE, EXEC权限。
查阅SQLServer官方文档,在默认情况下,Microsoft SQL Server 中关闭了公共语言运行库 (CLR) 集成功能。必须启用该功能才能使用 SQL Server 项目项。若要启用 CLR 集成,请使用 sp_configure 存储过程的“启用 clr”选项。
0x06 防范措施
1、非必要条件下,关闭CLR 集成。
2、用户权限分配时,剥夺CREATE ASSEMBLY, CREATE PROCEDURE, EXEC权限。
0x07 参考文档
1、https://msdn.microsoft.com/zh-cn/library/5czye81z(v=vs.80).aspx
2、https://msdn.microsoft.com/zh-cn/library/ms165051(v=vs.80).aspx
3、https://msdn.microsoft.com/zh-cn/library/ms254506(v=vs.80).aspx
4、https://blog.netspi.com/attacking-sql-server-clr-assemblies/#Import
5、http://sekirkity.com/command-execution-in-sql-server-via-fileless-clr-based-custom-stored-procedure/
网站地址:http://cert.360.cn
长按下方二维码关注360CERT!谢谢你的关注!