技术剖析Potato提权原理

* 原创作者:tahf

技术剖析Potato提权原理_第1张图片

(图文无关)

0×00 前言

前一阵子收录了一个名为Potato的提权工具,发现该工具提权的姿势与以往工具不太一样,而且与WPAD代理有关,于是展开测试和分析,主要通过分析其网络数据流量来研究该提权工具的独特姿势。分析中学到了不少东西,希望能把一些思考过的东西跟大家分享下。还请各位大牛批评指正!

整个工程代码和程序在GitHub上。https://github.com/foxglovesec/Potato

貌似是foxglovesec和breenmachine两位大牛在Github上建立的代码库,需要VS2012及以上版本打开!

0×01 初步测试

首先是测试该程序的使用范围和实际效果:

Potato的说明里写到可以在Windows 7,8,10, Server 2008, Server 2012上完成权限提升。看着挺唬人,试试看,以下只列出测试过的系统。

- Windows 7 x86和x64 系统上能够稳定立即提权(后面在分析其机制中会解释立即这词)

- Server 2008 R2 x64   系统上可以提权,但需要时间等待(约30分钟左右,跟Windows Updata时间有关)

- Server 2012 x64     系统上可以提权,但需要时间等待(更长,跟Windows更新证书列表时间有关)

- Windows 8和10等有机会测试下。

 一个重要前提,Potato程序是用C#编写的,需要系统装有.Net Framework 3.5以上版本支持。

0×02 原理分析

以Potato在windows 7系统上的提权为例,详细分析开始:

Potato-master\source\Potato\Potato\bin\Release是Potato项目build后的程序所在目录。

打开cmd以普通用户的身份执行下面命令:

Potato.exe -ip 10.0.0.X -cmd "net user test /add" -disable_exhaust true

PS:测试系统Windows 7 SP1 x64 IP:10.0.0.X

在Potato使用的整个过程中打开抓包工具,由于Wireshark无法抓取127.0.0.1 Loopback上的数据包,这次选择使用RawCap.exe来抓取,该工具需要管理员权限,很好用,文件可以直接保存为pcap。同时对10.0.0.X和127.0.0.1进行抓包。在虚拟机中用RawCap.exe对127.0.0.1 Loopback抓包无效,是在实体机器上测试并抓取网络数据的。

Step 1:让自己认为WPAD是它自己127.0.0.1

 补充:WPAD(Web Proxy Auto-Discovery Protocol)  Web 代理自动发现协议

当系统开启了代理自动发现功能后,用户使用浏览器上网时,浏览器就会在当前局域网中自动查找代理服务器,如果找到了代理服务器,则会从代理服务器中下载一个名为PAC(Proxy Auto-Config)的配置文件。该文件中定义了用户在访问一个 URL 时所应该使用的代理服务器。浏览器会下载并解析该文件,并将相应的代理服务器设置到用户的浏览器中。

Windows系统下,在解析这个WPAD名称时,会先从本机hosts文件开始,然后是问DNS,如果前面都没搞清楚WPAD是谁,则会利用NBNS协议进行广播。Potato在实现其第一阶段时主要利用NBNS协议,但当本机利用NBNS协议询问WPAD是谁时,Potato还是个普通权限,不可能利用嗅探技术把握发送WPAD应答包的时机。而NBNS协议是基于UDP之上,又是无连接协议,Potato在这里使用了称为Local NBNS Spoofer的技术。

当主机利用NBNS询问一个主机名时,它会发出下图中的Name query包。被询问者如果存活的话,会返回Name query response包。此时出现一个问题,如何知道询问与应答是对应关系的呢?实际上NBNS协议中的Transaction ID字段就是来解决这个的。

一问一答的Transaction ID必定相同。Potato在这里向本机的137端口不断发送Name query respose响应包,而Transaction ID字段范围是0-65535,尝试65536种可能,当本机在某时发送询问WPAD的Name query包时,总有一个Transation ID可以与之对应上。

下图是实际截获Potato发送的众多NBNS中的三个数据包,注意看TransationID。

最后来张匹配上的图。

Potato实现了让自己认为自己127.0.0.1是WPAD的目的。这时候ping WPAD 会发现是127.0.0.1

上面是基于询问者用NBNS协议询问WPAD是谁,主机在使用NBNS之前会先问DNS,假如DNS中有WPAD,询问者将不会再用NBNS,第一阶段目的不就泡汤了?

而参数中的-disable_exhaust就是来解决这个问题的,称为UDP端口耗尽技术,目的使DNS失效。下图是来说明DNS走的是UDP协议。

Potato将绑定每一个可以绑定的UDP端口,导致没有可用于UDP请求的源端口,DNS失败后询问者将不得不使用NBNS协议。Potato再次达成第一阶段目标。

PS:理论上而言,只要有一个足够快的连接,应该就可以对任何能用UDP端口137进行通信的Windows主机进行NBNS欺骗。

Step 2:在本机上展开假WPAD代理服务

第一阶段完成对本机的欺骗,使其认为自己127.0.0.1是WPAD,那么本机就会从WPAD上获取PAC文件。

在windows中,Internet Explorer默认会自动尝试通过访问”http://wpad/wpad.dat”来检测网络的代理设置。让人惊奇的是这也适用于一些windows服务,比如Windows Update,但具体情况与Windows版本有关。Potato将绑定127.0.0.1的80端口,运行http服务器,当它收到对”http://wpad/wpad.dat”的请求时,会用下面的内容进行响应。

自己去访问自己认为的WPAD的80端口,获取http://wpad/wpad.dat

Potato假WPAD代理服务回的响应,PAC文件:

下图是其对应代码部分。Potato的-wpad_exclude参数会排除指定域名,也就是后面的域名不会走代理。

Potato第二阶段利用自己架设的假WPAD和PAC文件,会使本机将127.0.0.1:80作为一个代理,本机上的部分流量(除wpad_exclude排除的)都会通过Potato运行在127.0.0.1上的服务器进行重定向。就是本机访问个啥,数据会被第一时间扔到127.0.0.1:80端口上。

原本是:10.0.0.122  >> Internet

现在是:10.0.0.122  >> 127.0.0.1:80 >> Internet

本身Potato没有权限,不可能嗅探数据,但Potato这个第二阶段完成之后,数据被直接扔到Potato自己的127.0.0.1:80上去了……自己成了一个中间人!

Step 3:利用第二阶段完成的数据重定向,HTTP -> SMB NTLM Relay

最后这一阶段涉及到NTLM认证的过程,如果有错误请一定要指正!谢谢!

第二阶段Potato已成功将自己变成一个中间人,在Windows 7环境下,有个Windows Defender更新机制,该机制会通过代理设置访问网络。下图是本机Windows Defender更新机制启动时发送出的HTTP数据,由于前面两个阶段的成功实现,系统将数据包直接扔给了127.0.0.1:80代理。

前面在测试中说在Windows7环境下用了“立即”一词,是指在Windows 7环境下能够通过某种方式让Windows Defender立即检查更新,从而产生例如http://download.windowsupdate.com/*****的HEAD请求。PS:HEAD请求是只请求页面的首部。

Windows Defender更新,触发用的是%ProgramFiles%\Windows Defender\MpCmdRun.exe它有个参数-SignatureUpdate

下图是Potato代码中对应的那段

一旦以MpCmdRun.exe -SignatureUpdate参数运行,Windows Defender立即检查更新,从而产生请求。而且MpCmdRun.exe -SignatureUpdate不需要任何权限就可以运行生效。当请求出现后,Potato的假http服务器响应这个请求,返回的HTTP状态码是302。

302代表暂时性转移,将会做一个重定向,将会跳转到Location字段中的URL。即将页面重新定向至http://localhost/GETHASHES836186  见下图。

当本机向127.0.0.1:80发出HEAD /GETHASHES836186请求后,Potato再次响应这个请求,HTTP状态码401.

401意思是当前请求需要用户验证,该响应必须包含一个WWW-Authenticate的信息头,用以询问用户信息,这个可见假http服务告诉请求者,用NTLM方式验证身份。

下面开始HTTP -> SMB NTLM Relay过程。这里先插入项目README.md中的一段话:

NTLM重放早已众所周知,但是我们通常错误理解了对Windows NTLM认证的攻击。NTLM协议容易受到中间人攻击。如果攻击者能够欺骗一个用户用NTLM向攻击者的机器进行认证,攻击者能够对其它的机器重放这个认证尝试。这种攻击的以前的利用方式是,让受害者利用SMB协议向攻击者使用NTLM认证尝试认证。攻击者可以对受害者机器重放这些凭据,使用像”pesexec”这类技术获得远程访问。微软对此已经进行了修复,利用挑战应答机制禁用了同协议的NTLM认证。这也就意味着SMB->SMB的NTLM重放,从一个主机再到该主机本身,是行不通的了。然而,跨协议攻击,如HTTP->SMB NTLM重放攻击仍然有效。

既然http服务告诉客户端,这个请求需要验证,那么客户端就要开始基于HTTP协议的NTLM认证过程。

1. 首先,客户端向127.0.0.1:80(也就是Potato)发出NTLMSSP_NEGOTIATE认证协商请求。

127.0.0.1:80在收到客户端发来的认证协商后,不急于应答,而是向本机的445端口 MSRPC服务发送基于SMB协议的Negotiate Protocol Request请求,RPC服务给予响应。

Potato利用客户端发来的基于HTTP协议的NTLMSSP_NEGOTIATE认证协商请求,将其中认证信息Base64解码后再通过SMB协议重放给本机的445端口的RPC服务。

上面基于HTTP协议的NTLMSSP_NEGOTIATE认证协商请求中的认证信息是用Base64编码的,解码后是下图。

与上面SMB的比对,确认是重放攻击。

2. 然后,本机的445端口的RPC服务会响应基于SMB协议的NTLMSSP_NEGOTIATE请求,返回一个NTLMSSP_CHALLENGE响应,里面有关键的挑战NTLN Server Challenge。

这个响应会给Potato,Potato将其用Base64编码后用HTTP协议再次重放给客户端。

3. 客户端会用NTLN Server Challenge来对用户和口令作加密处理,然后发给127.0.0.1:80

Potato将客户端发过来的认证Base64解码后再通过SMB协议重放给本机的445端口。

但这里后来发现一个问题,上面HTTP中的NTLM Secure Service Provider中各字段怎么都是空的?抓取了下正常net use \\IP登陆一台主机,也是NTLMSSP_AUTH包,见下图。

正常认证中NTLMSSP_AUTH中NTLM Client Challenge是应该存在的。可是上面的认证中竟然没有,但本机竟然认为认证成功,Session Setup AndX Response中的NT Status表示成功。

这个NTLMSSP_AUTH中关键数据尽然为空的问题后来想出来一种可能,也实际验证了下,后面再作解答,暂且把这个问题放一下。

此时Potato貌似具有了系统权限,于是开始创建服务,并启动服务执行命令了。关于权限是怎么变成系统权限的,一会与上面的问题一起解释。

这个GetShellXXX就是Potato创建的服务。

对应代码,用来实现类似Psexec的功能,实际是创建服务并启动服务。

之前在Potato中-cmd的参数`net user test /add`以成功执行,提权成功。Potato的第三阶段也成功实现!

在Windows 7环境下Potato的整个运行过程,它三大阶段的实现过程如上所述。其他系统环境的区别主要是Windows XXXX更新机制的不同。

- Windows 7下是利用Windows Defender的更新机制,而且有MpCmdRun.exe程序能让该机制立即检查更新,所以能稳定且立即见效。

- Windows Server 2008 下没有自带的Defender,但Windows Update的检查更新的机制可以,但无法控制机器检查更新的时间,实际测试最坏的情况在30分钟左右,Windows Update可能是30分钟检查一次。这个也还算好,起码时间不算长。(实际测试基本能最坏不超过30分钟)

- Windows Server 2012,Windows 8和10中,Windows Update可能不再使用”Internet Option(Internet选项)”中的代理设置,不检查WPAD。但这些版本中,有一个自动更新机制,会每天下载证书信任列表(CTLs),这种机制也是会检查WPAD的,最坏情况是24小时。(实际测试比较理想,等了1个多小时,可能是恰好赶上其证书信任列表更新了)

测试环境均没有连接互联网,跟连不连网关系不大,只要系统中的某种更新机制运转就行了。

0×03 尝试解答前面的一些问题

关于客户端在发给127.0.0.1:80的NTLMSSP_AUTH认证数据包中是Empty的问题。

仔细思考了下,有一种可能,就是上面的127.0.0.1:80到127.0.0.1:445的认证过程等同于net use \\127.0.0.1  开个CMD,无论权限大小,输入net use \\127.0.0.1都会成功。

这个过程有数据包产生么?当然有!用RawCap.exe对127.0.0.1 Loopback抓包。

这里是在Window 7的环境抓取的,为何协议是SMB2呢?在发送Negotiate Protocol Request时,客户端在这个包里会标明自己支持哪些协议的认证。(Dialects翻译过来是“方言”的意思,有意思~)

服务端会回一个Negotiate Protocol Respose,里面会有它选择的“方言”。服务端选择Dialects是有几条原则的,一是必须是客户端发来数据包中的列表里支持的,二是本身必须支持的,三是就高不就低。高版本安全性必然好,但得考虑下兼容。还与本地安全策略中的设置有关。

举测试过的例子,左边是客户端,右边是服务端。

- XP -> XP  NTLM 0.12

- Windows 7 -> Windows 7 SMB 2

- Windows 7 -> Server 2003 NTLM 0.12

- Windows 7 -> Server 2008 SMB 2

NTLM 0.12的安全性一般,嗅探到整个通信过程貌似是可以暴力破解的。SMB2中貌似加入了时间戳,重放攻击会失效。本次环境明摆着是Windows 7 -> Windows 7怎么没用SMB 2呢?

实际上Potato做了降级处理,它向本机的445端口发Negotiate Protocol Request包时,这个包是Potato自己构造的,它的Dialects中只有NTLM 0.12 服务端按照上面的选择原则,只能选NTLM 0.12。

NTLM 0.12的安全性是无法抵御重放攻击的,很多中间人攻击都有降级这招。

这里也是Empty,原来net use \\127.0.0.1貌似是不用验证的哈,但认证的流程还是走了一遍。那么前面的问题就可以解释通了。包括http://localhost/GETHASHES836186貌似也是只把认证的流程走了一遍。

Potato只是干了个relay,本机向假http认证的过程被它relay给了本机的RPC服务。

那么就剩一个问题,权限是怎么提升的???

本机普通用户net use \\127.0.0.1后,虽然成功,但还是普通权限。那么究竟这高权限是从哪来的?把上面分析的网络数据行为绘制了一张图,从上至下代表发生的时间。

Potao后来获得的系统权限应该是从客户端这块来的!

net use \\127.0.0.1 后所对应的权限应该对应发起net use的客户权限。如果是一个系统服务发出的net use \\127.0.0.1 那么成功后获得的一定也是系统权限。而HTTP请求也一样,当HTTP请求来自于高权限的客户时,认证后的权限也是对应的高权限。

Windows 7环境下,是利用MpCmdRun.exe加个参数运行,启动Defender的更新。运行MpCmdRun.exe时是个普通权限,说明该程序不是真正发出HEAD请求的客户端。并且做了简单的静态分析,发现该程序Imports中没有与网络通信有关的函数。个人推测真正的客户端,HEAD请求真正的发起者可能是Windows Defender(WinDefend)服务,或者是Windows Update(wuauserv)服务,这两个都是系统权限的且开机后就一直在运转的。

0×04 小结

综述,Potato首先是想办法使自己成为一个中间人,再找到一种触发Windows更新机制的方法,或者干脆等待Windows定时检查更新。检查更新时实际上是系统的更新服务作为具有高权限的客户端,发出http请求,Potato中间人在响应中重定向并要求客户端进行认证,利用高权限的客户端向本地假http服务的认证过程,将认证数据转发给系统的RPC服务,迫使系统RPC服务认为Potato中间人是个具有高权限的客户,从而完成提权!

简单分析下Potato的缺点:

在Windows 7下,Potato利用Windows Defender的更新机制可以做到立即。而在其他环境下,Potato在提权时第一阶段会使用NBNS Spoofer技术,会快速发送大量的数据包,测试来看还是比较消耗CPU的,而且要等待较长时间。目前还未测试在该过程中是否会影响到主机访问网络,毕竟部分网络数据被发往127.0.0.1:80。

Potato的具体代码实现就不多说了,可以转换成其他语言编写,从而不依赖.NET,使其适用范围更大。

* 作者:tahf,本文属FreeBuf原创奖励计划文章,未经许可禁止转载

你可能感兴趣的:(Windows渗透)