Potato家族提权学习

声明

出品|博客(ID:moon_flower)
======================

以下内容,来自moon_flower作者原创,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责,长白山攻防实验室以及文章作者不承担任何责任。

Origin Potato(MS08-068)

原理就是上文提到的ntlm反射,

图片

重点看一下修复,微软在kb957097补丁中通过修复SMB身份验证答复的验证方式来防止凭据重播。当主机A向主机B进行SMB认证的时候,将 pszTargetName设置为cifs/B,然后在 type2拿到B发送的Challenge之后,在lsass里面缓存 (Challenge,cifs/B),接着B拿到A的ype3,这时会去检查lsass缓存里是否有 (Challenge,cifs/B),如果有就说明这是同一台主机,那么认证失败。

Hot Potato(MS16-075)

影响范围Windows 7,8,10,Server 2008以及Server 2012,经典的ntlm relay 攻击链,依靠windows update触发。

工具地址:

https://github.com/foxglovesec/Potato

图片

实现流程:

1.本地 NBNS Spoofer :冒充名称解析,强制系统下载恶意 WAPD 配置2.伪造 WPAD 代理服务器:部署 malicios WAPD 配置,强制系统进行 NTLM 认证3.HTTP -> SMB NTLM 中继:将 WAPD NTLM 令牌中继到 SMB 服务以创建提升的进程
流程分3步,首先进行本地NBNS欺骗,windows通常通过这一协议进行域名
解析,当windows在hosts文件和dns查询都搜索失败后,会再进行NBNS
查询,在本地广播域中向所有的主机发出UDP广播询问。

但是直接嗅探到网络流量信息需要本地管理员权限,这里曲线救国。

如果我们能提前知道NBNS请求所对应的目标主机的主机名(目标主机 127.0.0.1),就可以创建一个虚假的应答信息,并快速地使用NBNS应答信息来对目标主机进行泛洪攻击。

因为NBNS数据包中有一个长度为2子节的数据-TXID,要求与请求和应答信息相匹配,所以要通过泛洪暴力枚举65536 个可能性。

这是没有匹配到dns的情况,如果之前就保存了主机的DNS记录,那么可以使用UDP端口枯竭(使每一个UDP端口失效),迫使目标系统中所有的DNS查询失败。

下一步是伪造WPAD代理服务器,在windows操作系统中,IE浏览器在默认情况下会通过http://wpad/wpad.dat来自动尝试检查网络代理,同时也有其它一些windows中的服务会采用这一机制(比如利用中提到的Windows Update)。

但是并不是所有网络中都可以正常访问这个url(不是所有的dns域名服务器都存在主机wpad),那么我们就可以伪造一个WPAD代理服务器,结合前文的本地NBNS欺骗,就可以声称WPAD主机的ip地址是目标地址(127.0.0.1)。

这时127.0.0.1本地运行一个HTTP服务器,当收到http://wpad/wpad.dat请求时,做以下答复:

FindProxyForURL(url,host){    if (dnsDomainIs(host, "localhost")) return "DIRECT";    return "PROXY 127.0.0.1:80";
这样目标上所有的 http 流量都通过127.0.01重定向。之前对于NTLM 反射的补丁只限于SMB->SMB,但NTLM支持跨协议,也就是说像HTTP->SMB仍可正常工作。

现在HTTP流量都会途径我们控制的HTTP服务器,那么就可以将其重定向到

URL: http://localhost/GETHASHESxxxxx,以NTLM身份验证的401请求响应(其中xxxxx是某个唯一标识符)。然后将NTLM凭据中继到本地SMB监听器以创建运行用户定义命令的新系统服务。

当这个请求由高权限发起的时候(比如windows update,system权限),就完成了提权。再看一下漏洞的触发,依赖于发送http://wpad/wpad.dat请求,而当windows已经由WPAD的缓存条目或因为没有找到WPAD而允许直接上网时,需要30-60min才会刷新。

Rotten Potato(MS16-075的变种)

通过DCOM call来使服务向攻击者监听的端口发起连接并进行NTLM认证,

需要SelmpersonatePrivilege权限。

可以立即触发,不需要等待windows更新。

影响范围:< win10 1809和windows server 2019

图片

实现流程:

1.通过 NT AUTHORITY/SYSTEM 运行的 RPC 将尝试通过 CoGetInstanceFromIStorage API 调用向我们的本地代理进行身份验证2.135 端口的 RPC 将用于回复第一个 RPC 正在执行的所有请求充当模板3.AcceptSecurityContextAPI 调用以在本地模拟 NT AUTHORITY/SYSTEM
首先是用CoGetInstanceFromIStorage尝试从调用者(system)指定的位置获取指定对象的实例,下面代码试图从127.0.0.1的6666端口上获取一个BITS对象。(实际上是从IStorage中获取对象)

其中,CLSID是标识COM类对象的全局唯一标识符,类似uuid。BITS(后台只能传输服务)实现从HTTP web服务器和SMB服务实现文件共享,BITS实现了 IMarshal接口并允许代理声明强制NTLM身份验证。

public static void BootstrapComMarshal(){IStorage stg = ComUtils.CreateStorage();//使用已知的本地系统服务 COM 服务器,在此强制执行 BITSv1Guid clsid = new Guid("4991d34b-80a1-4291-83b6-3328366b9097");TestClass c = new TestClass(stg, String.Format("{0}[{1}]", "127.0.0.1", 6666)); // ip and portMULTI_QI[] qis = new MULTI_QI[1];qis[0].pIID = ComUtils.IID_IUnknownPtr;qis[0].pItf = null;qis[0].hr = 0;CoGetInstanceFromIStorage(null, ref clsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, c, 1,       qis);}
现在有一个COM试图连接127.0.0.1:6666(通过RPC协议),那么我们在6666
端口上建立一个本地TCP监听器,如果这时我们以正确的方式回复,
那么这个COM(system 权限运行)就会尝试与我们进行NTLM身份验证。


在这里我们做的是将6666接收到的数据包中继到本地的135端口的RPC监听上,并将135端口返回的数据包作为回复COM的模板。

如果从调用函数的层面理解NTLM的认证过程,有下图:

图片

重点看服务端的调用,首先调用acquirecdentialshandle获取相应的句柄,然后用AcceptSecurityContext处理type1,这个函数的输出就是type2的消息,该消息将被发送回试图进行身份验证的客户端,这里就是DCOM。

当客户端回复type3后,服务端将其传递给AcceptSecurityContext,以完成身份验证并获得令牌。在我们的攻击中,type1被转发到了RPC的135端口上,RPC回复一个Type2,但不是直接转发回去,需要在中转的时候进行一些处理,这里做的使用AcceptSecurityContext 调用的结果替换发送到COM数据包中的NTLM blob(?)。

但为什么要这样?因为我们需要的是用system账户运行的COM来完成NTLM Challenge和Reserved(我们使用这两个部分来协商本地令牌),所以如果不替换,后续再次调用AcceptSecurityContext就会失败。

到现在为止,我们能确定的是,客户端以system权限执行的COM需要对服务端返回的NTLM type2数据包中的NTLM Server Challenge和Reserved部分进行一些操作(magic?)

而只有对AcceptSecurityContext生成的结果执行这些操作的时候,才能获得令牌。

这里的Reserved字段实际上是对SecHandle的引用,当system账户接收到 NTLM type2的消息时,会在内存中进行Reserved验证(如果没有替换,将被认证为RPC而不是我们。

完成上述操作后,system权限运行的COM将向我们发送type3(是空的?),

但会用它来调用AcceptSecurityContext。最后使用其调用结果用

ImpersonateSecurityContext获得一个模拟令牌。

有了模拟令牌,根据 SeImpersonate 权限的特性,可以以此令牌创建进程(基本直接翻译原文,其中有很多地方还不是很理解,有错误希望各位师傅指出)

原版的Rotten Potato的实现基于meterpreter shell,后来有人写了webshell的版本(也就是Lonely Potato)。

复现:新建一个IIS服务器,传上shell,连上马

图片

尝试获取不同权限,直接cd到public中可以获取IUSR权限

图片

用烂土豆提权:

图片

PrintSpoofer

看这个洞之前先回顾一下getsystem的原理那篇文章,提权的原理就是诱使 system权限的服务访问我们指定的命名管道,getsystem提供各种模式欺骗 system连接管道:

图片

其中第5个就是PrintSpoofer,利用了打印机组件路径检查的bug。
项目地址:

https://github.com/leechristensen/SpoolSample

Windows的MS-RPRN协议用于打印客户机和打印服务器之间的通信,默认情况下启用。

协议定义的RpcRemoteFindFirstPrinter-ChangeNotificationEx()

调用创建一个远程更改通知对象,该对象监视对打印机对象的更改,并将更改通知发送到打印客户端。

DWORD RpcRemoteFindFirstPrinterChangeNotificationEx(     /* [in] */ PRINTER_HANDLE hPrinter,    /* [in] */ DWORD fdwFlags,    /* [in] */ DWORD fdwOptions,    /* [unique][string][in] */ wchar_t *pszLocalMachine,    /* [in] */ DWORD dwPrinterLocal,    /* [unique][in] */ RPC_V2_NOTIFY_OPTIONS *pOptions)
同时,Print Spooler服务的RPC接口暴露在命名管道:\\.\pipe\spoolss 中,
该服务默认开启。其中pszLocalMachine是指向表示客户端计算机名称的
字符的指针,需要传递一个UNC路径,传递\\127.0.0.1时,服务器会访问
 \\127.0.0.1\pipe\spoolss,但这个管道已经被系统注册了,

并由NT AUTHORITY\SYSTEM控制。那么下一步就是要想办法把这个请求让
我们准备好的恶意管道接收。

考虑到UNC路径的性质,如果主机名包含/,它将通过路径检查,但真正连接的时候会转化为\ 。那么,如果传递一个\\127.0.0.1/pipe/foo,检查时会认为127.0.0.1/pipe/foo是一个主机名,随后在连接named pipe时会对参数做标准化,于是就会连接\\127.0.0.1\pipe\foo\pipe\spoolss,那么攻击者就可以把主机名改为\\127.0.0.1/pipe/foo并注册这个named pipe从而窃取 client的token。

工具地址:

https://github.com/itm4n/PrintSpoofer

还有crisprss修改的免杀版:

https://github.com/crisprss/PrintSpoofer

图片

参考

  • https://www.anquanke.com/post/id/92908

  • https://forum.butian.net/share/860

  • https://tttang.com/archive/1560/

  • https://www.anquanke.com/post/id/217397

  • https://www.anquanke.com/post/id/83322

  • https://www.anquanke.com/post/id/194514

欢迎关注长白山攻防实验室微信公众号
定期更新优质文章分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值