0%

从烂土豆开始的土豆家族入门

从烂土豆开始的土豆家族入门

对.NET和COM一窍不通,代码一行都没写过,全篇内容由读各种文章+自行想象完成,不保证准确性,若发现错误请及时联系我更改

windows在远古版本前,各种服务都是以最高权限SYSTEM跑起来的,那个时候mssql的一个xp_cmdshell就可以一键打到底,而在某个版本后,添加了local service用户,之后iis或者mssql就被降权为了networkservice之类的账户,权限很低,直接操作几乎啥也干不了,但由于这些账户本身作为服务账户,也需要在特定的情况下拥有高权限,微软是允许这些账户进行提权的,而如果我们能对这些情况进行滥用,同样的也就可以将networkservice账户恢复到system

土豆系列提权的核心是NTLM中继,通过欺骗运行在高权限(Administrator/SYSTEM)的账户进行ntlm认证,同时作为中间人对认证过程进行劫持和重放,最后调用本地认证接口使用高权限账号的ntml认证获取一个高权限token,只要当前进程拥有SeImpersonatePrivilegeSeAssignPrimaryToken权限即可进行令牌模仿,即可取得对应权限(同理,对于直接的令牌窃取利用也需要拥有SeImpersonatePrivilege权限,感觉一般只用于Administrator提到SYSTEM,其他的用户一般来说要么没有这个权限,要么没法直接open高权限账户的token

hot potato

最初的土豆,需要通过叫做NBNS欺骗的方法欺骗本地主机和攻击者构造的虚假WPAD服务器交互,进而实现NTLM重放,这个不能一打就通还得等待windows update触发,并且NBNS欺骗还需要大量发包进行投毒,总之就是不实用,不学

利用流程如下图
Image Diagram 1

本文该风格图片来源为Potatoes - Windows Privilege Escalation

修复情况

该漏洞在16年就被修了(虽然实际上遇到的机器比16年老的比比皆是)

Microsoft patched this (MS16-075) by disallowing same-protocol NTLM authentication using a challenge that is already in flight. What this means is that SMB->SMB NTLM relay from one host back to itself will no longer work. MS16-077 WPAD Name Resolution will not use NetBIOS (CVE-2016-3213) and does not send credential when requesting the PAC file(CVE-2016-3236). WAPD MITM Attack is patched

阻止了SMB协议到SMB协议的NTLM中继,并且修了对WAPD的中间人攻击

前置知识

土豆攻击感觉一定程度上是.NET反序列化,不过这里反序列化的利用链和其他语言的利用环节并不一致,由于是凭证窃取,所以是在反序列化过程中引诱高权限进程与恶意服务进程交互,从而完成提权

The key feature that the exploit abused is standard COM marshaling. Specifically when a COM object is marshaled so that it can be used by a different process or host, the COM runtime generates an OBJREF structure, most commonly the OBJREF_STANDARD form. This structure contains all the information necessary to establish a connection between a COM client and the original object in the COM server.

Rotten Potato

tl;dr

简单的说,就是远程加载一个引用对象,然后解析引用对象的时候需要去其指定的OXID resolver找,然后COM server在和远程服务器(这里直接开在本地的一个端口上)的交互过程中需要进行认证,导致NTLM中继。(总觉得有一点像jndi注入里的远程reference)

详解

最经典的土豆,强烈推荐阅读原作者博客,讲得非常清楚
Rotten Potato – Privilege Escalation from Service Accounts to SYSTEM

NTLM中继流程可以参考如下图片

Image Diagram 2

  1. 对以SYSTEM权限运行的COM组件调用CoGetInstanceFromIStorage,该函数会尝试和攻击者启动的6666端口进行NTLM认证
  2. (图中步骤2/3)对交互过程进行中继,当COM组件发起NTLM negotiate时,除了将该请求中继到135端口外,同时提取出其中的NTLM协商部分,发起AcceptSecurityContext调用,将截获的NTLM协商发送过去。
  3. (图中步骤4/5/6)收到NTLM challenge,此时收到的challenge有两个,中继到135端口的challenge和调用AcceptSecurityContext得到的challenge,此时需要将5中的challenge返回给服务端,这样子才能使服务端应答的是AcceptSecurityContext的challenge
  4. 将NTLM Auth重放,最终AcceptSecurityContext会给出一个安全上下文,通过QuerySecurityContextToken可以获取该上下文的token(此处为SYSTEM),利用Impersonate权限提权到SYSTEM

讲一点从CoGetInstanceFromIStorage到NTLM认证的具体环节。

CoGetInstanceFromIStorage是一个Windows API函数,用于从一个存储对象中获取COM对象的实例。它可以通过指定服务器信息、类标识符、外部接口、上下文环境和存储对象来创建一个新的COM对象实例,并通过指定接口标识符来返回该实例。它可以用于在应用程序中访问和使用存储在存储对象中的COM对象。

为了让对象能够在进程和主机间传播,COM需要对对象进行序列化(marsharl),序列化时会创建的OBJREF会包含OXID,OID等恢复该对象所需的标识符,如下是从project zero博文中copy出来的从OBJREF中恢复原对象的过程

Connecting to the original object from the OBJREF is a two part process:

  1. The client extracts the Object Exporter ID (OXID) from the structure and contacts the OXID resolver service specified by the RPC binding information in the OBJREF.
  2. The client uses the OXID resolver service to find the RPC binding information of the COM server which hosts the object and establishes a connection to the RPC endpoint to access the object’s interfaces.

这里利用的是过程1,在序列化时手搓数据,将OBJREF中的RPC binding information中的指定为启动在6666端口上的中继服务,当COM server上来访问我们的PRC server时进行NTLM认证实现中继

抄一个project zero的图

image2

juicy potato

作者的介绍 Juicy Potato
不是新的利用手法,而是对Rotten Potato的强化版本,也是最广为流传的利用版本。Rotten Potato默认使用的是windows的BITS服务作为发起认证的服务端,并且默认在6666端口上,然后微软把BITS服务默认关掉就跑不起来了。

但实际上任意一个运行在Administrator/SYSTEM权限下且实现了IMarshal接口的服务均可作为利用目标,同时这个COM服务需要可以被当前用户实例化(我感觉既然是一个被提供出来的服务应该都可以实例化吧。。。)

利用手法和烂土豆一致,但是提供了一系列武器化的工具,给出了一个GetCLSID.ps1,可以查找当前机器上可用的CLSID,还有一个test_clsid.bat,可以对classID进行批量测试,将可利用的classID、空闲的端口和对应的token输出出来,最后使用juicypotota.exe一键打通

作者为了稳妥起见,还使用的低权限local service账户进行搜索,使用如下命令可以启动一个local service权限的终端,需以administrator权限运行

.\PsExec64.exe -i -u "nt authority\local service" cmd.exe

不过我试了一下在winserver2008和另一个啥机子上(好像是win7?)ps脚本跑起来报错。。。

修复情况

No more rotten/juicy potato?中指出了修复情况,微软不允许指定OXID resolver的端口,如果指定了端口就会直接挂掉,只能使用默认的135端口,这样子就不能将请求劫持到自定义的恶意listener上了,如果在其他机器的135端口上部署一个listener,虽然可以发出请求,但是由于host指定为远程机器,身份认证的时候使用的是匿名登录,导致利用失效。

截止到versions >= Windows 10 1809 & Windows Server 2019无法利用(实际上是打了补丁的版本低一点的机器也不能用)

WinRM利用

We thought they were potatoes but they were beans
decoder的又一篇博客,在上述修复出现后,他们测试时发现,正常启动bits服务时,其会对5985端口上的winrm服务发起NTLM认证,而在windows10上winrm是默认关闭的,此时可以在5985端口上启动一个listener完成NTLM中转

然而这个攻击的条件限制较多,win server上winrm通常默认开启,只有win10上面默认关闭,BITS服务只在启动时会连接winrm,所以如果bits服务已经在运行则无法触发

题外话

今天装了个winserver12的虚拟机进行测试,由于winserver12装VMware tools有奇怪的bug,网上搜了一圈需要装一系列补丁,装完之后还要手动添加CD驱动器才能挂载VMware tools装上

然后发现装完补丁的winserver12也不会被烂土豆打通了,等于说微软也做了向前兼容,老一点的操作系统如果补丁够齐可能也不会被打烂

RoguePotato

tl;dr

简单的说,就是微软禁止了OBJREF解析时可以任意指定端口,且指定远程机器时进行匿名登录,这个时候就不能在OXID resolver环节打通了,但是可以将resolve的结果再指向某个用户可控的服务,在那个服务中完成后续利用

详解

juicyPotato的修复为利用添加了一系列的限制,禁止在OBJREF中指定端口,默认访问135端口,而访问远程的135端口又会导致不是local authorization无法利用,作者提出了通过fake OXIDresolver解析RPCss服务连接本地命名管道的方式再次完成利用

直接Ctrl C/V原作者的内容

  • You try to initialize a DCOM object identified by a particular CLSID from an “IStorage Object” via standard marshalling (OBJREF_STANDARD)
  • The “IStorage” object contains, among other things, the OXID, OID, and IPID parameters needed for the OXID resolution in order to get the needed bindings to connect to our DCOM object interfaces. Think about it like sort of DNS query
  • From “Inside COM+: Base Services”: The OXID Resolver is a service that runs on every machine that supports COM+. It performs two important duties:
    • It stores the RPC string bindings that are necessary to connect with remote objects and provides them to local clients.
    • It sends ping messages to remote objects for which the local machine has clients and receives ping messages for objects running on the local machine. This aspect of the OXID Resolver supports the COM+ garbage collection mechanism.
  • OXID resolver is part of “rpcss” service and runs on port 135. Starting from Windows 10 1809 & Windows Server 2019, its no more possible to query the OXID resolver on a port different than 135
  • OXID resolutions are normally authenticated. We are only interested in the authentication part, which occurs via NTLM in order to steal the token, so we can specify in our case for OXID, OID and IPID just 32 random bytes.
  • If you specify a remote OXID resolver, the request will be processed with an “ANONYMOUS LOGON“.

根据如上内容可知,在先前的攻击中,通过CoGetInstanceFromIStorage,通过构造引用对象使指定CLSID的COM组件连接恶意服务端进行认证,这里访问的服务端就是OXID resolver,其会解析需要加载的Instance bind在什么地方,在这个访问环节中存在NTLM认证,Rotten potato就是在和OXID resolver交互的过程中进行NTLM中继,但是由于微软的修复,不能指定135以外的端口+访问远程使用匿名登录,烂土豆失效。rogue potato的想法就是不在查询环节进行利用,而是通过更改查询的结果,通过实现ResolveOxid2方法对解析结果进行控制,将COM组件(或者说rpcss?)再次重定向回本地的恶意服务

而回到本地后有两个利用手法:

  1. 回复RPC server地址,使rpcss对RPC server的IRemUnknown2接口进行查询,这会导致一个RPC调用,使用RpcImpersonateClient对其进行模仿(这个方法在BITS上失败了,具体原因后面会说)
  2. 回复命名管道,rpcss会与命名管道进行交互,通过ImpersonateNamedPipeClient对其进行模仿

具体为什么让rpcss连接到自己的恶意命名管道就能提权,需要阅读如下内容
From NETWORK SERVICE to SYSTEM
递归学习Sharing a Logon Session a Little Too Much

PrintSpoofer - Abusing Impersonation Privileges on Windows 10 and Server 2019
这篇文章解释了windows的奇怪特性,RPC server和named pipe server分别可以通过RpcImpersonateClientImpersonateNamedPipeClient分别模仿调用/连接的客户端,前者是为了RPC调用中降权,防止client利用高权限下运行的RPC进行恶意操作,至于后者为什么会有这个功能就完全不能理解了捏,并且后者需要客户端连接并写入才能生效,当然,两个函数都需要SeImpersonatePrivilege

最终的结论如下

if you can trick the “Network Service” account to write to a named pipe over the “network” and are able to impersonate the pipe, you can access the tokens stored in RPCSS service

具体方式如下:

  1. 触发COM服务连接远程机器135端口
  2. 在远程机器的135端口上设置一个端口转发,将所有流量转发到部署的fake OXIDresolver上(resolver可以部署在远程机器上,既然如此为什么不直接让resolver监听135端口?)
  3. OXID resolver将目标解析到本地恶意named pipe上
  4. 然后rpcss会连上我们的named pipe然后写入,简单看了一眼代码,这里就是调用ImpersonateNamedPipeClient拿到rpcss的token,这是一个network service token,但是可以通过这个token遍历rpcss内的handle拿到system token

不过这个操作就是直接偷token了,和之前土豆的NTLM中继有点出入

Image Diagram 3

也抄一个project zero的图

image5

不过rpcss连接的命名管道的名称是固定的,如果名字不对会拒绝连接,但是这里使用了一个技巧,如果提供的路径中在主机名后添加/分隔路径,可以通过管道名的check,而在实际连接时又会将其转化为管道名的一部分,如\\HOST/path[\pipe\aaa]会变为\\HOST[\past\pipe\aaa],以此将其控制到用户可控管道且通过检查

利用限制

需要出网,或者在内网中存在一台可控且135端口未被占用的机器

自己测试的时候因为没有公网windows,用linux做了个frp端口转发再转一层回来,但是跑起来的时候远程135根本没收到流量,wireshark抓一下有135端口的流量,但是全是报错tcp retransmission。不懂

但是这个只要能重定向回pipe就能直接获取完全权限的话,那么任意满足rotten potato的类均可进行利用,比后续几个potato适用于部分类会更普适一些

PrintSpoofer/BadPotato

rouge potato的上位替代品,也是其利用的思路来源
BeichenDream师傅实现了一版利用工具后命名为BadPotato
原理详见PrintSpoofer - Abusing Impersonation Privileges on Windows 10 and Server 2019
利用了一个打印机bug,通过调用RpcRemoteFindFirstPrinterChangeNotificationEx让打印机服务通过命名管道发送通知,强行使SYSTEM连接到目标命名管道,然后通过如上介绍的方法直接获取到SYSTEM权限

这里管道名同样是需要经过check的,同样使用上述方法绕过。这里itm4n提到了该方法的防御手段,在使用CreateFile打开命名管道时,可以添加SECURITY_IDENTIFICATION flag使得模仿时得到的token是identification token。是否rogue potato用rpc调用时打不通也是这个原因呢?

这是对很多年Service Tracing的利用的修补方案,Service Tracing在用户修改注册表一个项之后,系统服务会将日志写到注册表中指定的路径,然后注册表填一个命名管道打通,微软通过添加了这个flag使得连上去也打不通。但是后来微软再遇到这种洞就不修了,并表示从拥有Impersonate权限的进程提升到SYSTEM是符合预期的行为。

说起来potato应该是指通过NTLM中继进行认证授权实现的攻击手法,这里算是一种token窃取,是不是应该归类为potato我不好说

修复手段

额,修不好就关机运维,微软说这个不是洞不修,但是这个奇怪的打印机服务一般情况也没人用,所以把这个关了就行了

PrintNotifyPotato/JuicyPotatoNG

这两个名字也是一个东西,只不过一个是BeichenDream师傅的C#实现,一个是antonioCoco的C++实现

发展

顺着decoder的博客继续衍生得到的更为广泛的potato家族
The impersonation game中解释了为什么RPC调用中得到的token是identification token,确实是发起RPC调用时设定好的,并通过寻找注册表,发现了一个名为PrintNotify的服务,其注册表中的Impersonation levelimpersonation,使用该CLSID对fake OXID resolver进行查询,重定向到本地evil RPC server后,在第一次RPC远程调用得到anonymous logon后,由查询IremUnknown2触发的回调成功拿到了SYSTEM,然而这个组件需要用户在INTERACTIVE组中才能完全利用。
后续在Giving JuicyPotato a second chance: JuicyPotatoNG中给出了更完整的利用,使用LogonUser函数进行登录,由于使用的是LogonNewCredentials,LSASS会直接给这个token加一个INTERACTIVE,由于这个token只适用于远程网络认证,所以随便填一个用户名密码均可成功。

实现

然而,你就算再好用,这里还是有一个最大的限制,出网。难道就不能讲所有利用只在本地完成吗?

谷歌的project zero团队提出了解决方案:Windows Exploitation Tricks: Relaying DCOM Authentication

Note that the string bindings in the OBJREF are only for binding to the OXID resolver, not the COM server itself.

看起来一个普通的OBJREF已经无法满足我们的需求,所以其将OBJREF变为了一个objref moniker,这个像是给OBJREF再套了一层,正常情况下OXIDresolver解析这一步就能够确定对应的obj位于哪个机器上,然后对其进行RPC调用就可以获取句柄,这种情况下是无法resolve到我们的恶意服务上的,但是objref moniker就可以再指定一次,使其连接到恶意的COM server

moniker是通过name进行加载的,展示出来是一个形如OBJREF:xxxx一堆base64的数据,其他进程可以使用这个name调用BindToMoniker方法从name中加载moniker引用的对象

后续的利用有一点些许的抽象,似乎为了让client能连上我们的COM server,需要对该服务进行注册,而不是监听端口手写TCP。当目标Client尝试解析OXID时,COM Runtime会调用UseProtSeq让我们的COM server随机监听一个端口让client链接,但是这个是要求监听全网卡,这样子会触发经典defender的是否允许其在网络上活动的那个弹窗,但实际利用只需要监听本地就行了,但是这样子client最后会认为COM server不可达。最后是一通fuzz加分析找RPCSS怎么判断端口通不通,最后得出结论是靠PEB中的module name,并且fuzz出System这个名字可以通过,改PEB内容实现绕过

也有提到COM Server的那个端口会由RPC runtime绑定上,这时是无法再使用自己的其他代码去使用那个端口的(大概是规范了那个端口必须绑定对应的服务?)

解决方案1是写一堆黑魔法去抢占那个端口,解决方案2是直接hook交互过程中的函数,方案2hook更加稳定并且直接从交互过程中偷,更加成功

虽然这里是hook住AcceptSecurityContext,但是并不是复现的rotten potato的NTLM中继,而是直接偷token,只能说是rogue potato的本地优化版

衍生

除了PrintNotify,通过遍历全CLSID,有一个ActiveX Installer Service可以利用,但是在winserver上默认关闭,剩下的COM组件可以获取当前系统上的活跃用户,虽说有用但仍然有点鸡肋,实际利用时需要临时找

修复

最为通用的PrintNotify需要使用LogonUser虚假登录获得INTERACTIVE组权限,所以微软把这个地方修了,具体修复普及程度不明(我本机win10最新更新后仍然可以利用)

GodPotato

BeichenDream师傅的最新一版potato,但是没给分析文章,360 noah lab上有一篇之前的PrintNotifyPotato的分析文章
COM安全 新型土豆提权 第一部分,去年12月发的第一部分,今年四月了第二部分还没发。。。

C#垃圾也不太看得懂代码,不过看到了rogue potato中的那个经典name pipe,猜测是可以直接诱导RPCSS连接命名管道进而提权,这样子就是顶级通杀了,怪不得敢命名为GodPotato

不过我感觉只要微软把那个pipe名字解析洞修了就无敌防御了。。。

其他思考

为什么土豆中的NTLM中继不能在域里面中继一下?看完了利用之后发现,只有最老的potato是真的在中继NTLM,靠后的potato都是通过诱导RPCSS访问命名管道或者发起RPC调用的环节进行token窃取,自然无法进行哈希传递,而对于烂土豆的哈希传递,由于认证的是当前机器的SYSTEM,并不是域内通用账户,自然就不能用一台机器的SYSTEM登录其他机器
(上述内容来自脑补,不保证准确性)

参考链接

给大家表演一个递归式学习
project zero的博客是最后看的,但是感觉是最详细的。。。建议先看
Rotten Potato – Privilege Escalation from Service Accounts to SYSTEM
No more rotten/juicy potato?
We thought they were potatoes but they were beans
From NETWORK SERVICE to SYSTEM
Sharing a Logon Session a Little Too Much
PrintSpoofer - Abusing Impersonation Privileges on Windows 10 and Server 2019
The impersonation game
Giving JuicyPotato a second chance: JuicyPotatoNG
COM安全 新型土豆提权 第一部分
强烈推荐project zero的博文
Windows Exploitation Tricks: Relaying DCOM Authentication