0x1 前言
if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM. ——@decoder_it
0x2 初代土豆:Hot Potato
Hot Potato在2016年被提出,其主要原理是通过NTLM中继和NBNS欺骗来提升权限。
0x01 NBNS欺骗
https://foxglovesecurity.com/2016/01/16/hot-potato/
当Windows进行DNS解析时,会按照以下的顺序进行:
-
1. 查找本地hosts文件
-
2. DNS缓存或DNS服务器
-
3. 链路本地多播名称解析(LLMNR)和NetBIOS名称服务(NBT-NS)
但在进行第3步的查找时,是通过广播的形式,询问所有主机,所以攻击者可以通过一个错误的主机名,让目标进行LLMNR和NetBIOS名称服务解析,再响应目标的询问,获取凭证信息。
嗅探网络流量需要本地管理员权限,但如果是本地提权的情况下,一般不具有该权限。
NBNS数据包中存在一个NAME_TRN_ID
,也叫交易ID,用来确保请求包和响应包保持一致,大小为2字节:
所以在对本地(127.0.0.1)做NBNS欺骗时,可以通过遍历交易ID的方式来确保请求响应匹配。
为了防止所请求的DNS服务器记录中有我们要进行欺骗的域名,可以使用UDP端口耗尽技术,它可以使目标系统上所有DNS查询失败,原理是占用每个UDP端口。
将NBNS欺骗与WPAD代理结合,可以让目标的所有流量通过受控的代理服务器,即127.0.0.1.
0x02 NTLM中继
低权限用户进行NBNS欺骗,高权限用户也会受到影响,这是提权的关键。
NTLM中继有多种利用方式,这里用到的是HTTP->SMB
,原因是最初的SMB->SMB
被微软修补而无法使用(MS16-075)。
目前我们通过NBNS欺骗使得目标的所有HTTP流量都流经受控的代理服务器,这时将其重定向至一个请求NTLM身份验证的URL,例如401验证,再将得到的NTLM凭据中继到本地SMB服务,就可以创建相应的服务。
当该请求高权限用户发起的时,最终就能以SYSTEM权限执行命令。
0x03 利用
在利用方面,主要问题是如何触发NTLM验证,作者给了以下几种解决方案:
-
• Windows 7下,利用Windows Defender更新机制触发
-
• Windows Server 2008下,利用Windows更新机制触发,不过这个不够稳定
-
• Windows 8/10/Server 2012下,利用不受信任证书的自动更新程序特性来触发,也不够稳定
PoC地址:https://github.com/foxglovesec/Potato
微软已经给出了该漏洞的修复方案:Microsoft 安全公告 MS16-077 https://learn.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-077
顺带一提,该方案也是修复BadTunnel
攻击的一部分,该攻击方式由著名的@tombkeeper
提出,两者有一些相似之处,Hot Potato
的作者还在新闻报道之后联系过@tombkeeper
,以为是思路重合了,但交流过后发现并不是,他对Tunnel的思路非常赞赏。
0x3 二代土豆:Rotten Potato
https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/
在初代土豆提出后不久,该作者又找到了新的攻击方式,将其命名为Rotten Potato.
相对之前的,Rotten Potato使用了另一种方法来进行NTLM中继,即利用DCOM/RPC机制。
下图是攻击流程,我们参照该图来分析整个过程:
0x01 流程分析
1. 利用CoGetInstanceFromIStorage()
CoGetInstanceFromIStorage()
的作用是加载指定对象的实例,通过该API,我们可以加载BITS对象,那么BITS服务就会向受控的端口发起RPC连接。
作者的示例代码:
public static void BootstrapComMarshal()
{
IStorage stg = ComUtils.CreateStorage();
// Use a known local system service COM server, in this cast BITSv1
Guid clsid = new Guid("4991d34b-80a1-4291-83b6-3328366b9097");
TestClass c = new TestClass(stg, String.Format("{0}[{1}]", "127.0.0.1", 6666)); // ip and port
MULTI_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);
}
这段代码的作用是通过指定的地址去加载指定对象的实例,其中指定地址由IP和端口构成,TestClass
是对其进行包装的IStorage
对象;指定对象则由CLSID
确定,CLSID
是COM组件的唯一标识符Guid
的一种,另一种是针对接口的IID
,这里指定的是BITS对象。
2. 发起NTLM协商
在成功与BITS服务通信后,我们尝试让其进行NTLM身份认证,NTLM身份认证的第一步是协商(Type 1).
3. 中继NTLM认证
本地的6666端口是我们控制的代理服务器,所以可以将NTLM身份认证数据包中继至本地的RPC服务即135端口处,之后调用AcceptSecurityContext()
进行强制本地身份验证。
4. 中继NTLM质询
4和5都会返回NTLM质询(Type 2),但数据包稍有不同,下面是对比图:
可以看到,Challenge
和Reserved
值不同。因为我们的目的是进行本地权限提升,这两个值关乎认证的目标,所以6的数据包的两个值要跟5保持一致,这里需要做一下替换处理。
5. 中继NTLM验证
之后的7和8,BITS服务会返回NTLM验证(Type 3),需要将其中继至AcceptSecurityContext()
处。
6. 协商模拟令牌提权
最终的9,我们使用QuerySecurityContextToken()
来获取访问令牌,提升权限。
0x02 利用
利用该方法提权,需要当前用户具有SeImpersonatePrivilege
特权或SeAssignPrimaryTokenPrivilege
特权。
Local Service
和Network Service
通常都具有前者,所以实际场景中常常用来从IIS或SQL Server服务账户权限提升至SYSTEM权限。
PoC:https://github.com/SecWiki/windows-kernel-exploits/tree/master/MS16-075
微软同样修复了该漏洞,在≥Windows 10 1809 和 Windows Server 2019 的版本不可使用,原因是在这些版本上IStorage COM组件只能与135通信,无法重放。
0x03 Juicy Potato
Juicy Potato是Rotten Potato的改进版本,它允许自定义COM服务器监听端口(原版为6666),允许修改CLSID来指定其他服务(原版为BITS服务),使用起来更灵活,适用范围和原版一致。
PoC:https://github.com/ohpe/juicy-potato
0x4 三代土豆:PrintSpoofer
https://itm4n.github.io/printspoofer-abusing-impersonate-privileges/
PrintSpoofer
也叫PipePotato
或BadPotato
,这里沿用原作者的称呼。
因为微软通过对COM组件进行限制,导致无法再使用RPC协议进行中继,所以作者找到了使用命名管道进行中继的方法。
关于命名管道,有一个很有用的API:ImpersonateNamedPipeClient()
,它允许服务端进程模拟连接到它的客户端进程,也就是说,如果现在有一个非管理员权限的命名管道服务端进程,并且有一个管理员权限连接到该服务端,那么就可以模拟出管理员权限,当然这需要SeImpersonatePrivilege
特权。
所以只需要使SYSTEM用户连接到我们的命名管道客户端,就可以获取SYSTEM令牌进行提权,漏洞作者解决该问题的方法是Printer Bug
即打印机错误。
Printer Bug
是利用了MS-RPRN协议中的RpcRemoteFindFirstPrinterChangeNotificationEx()
:
DWORD RpcRemoteFindFirstPrinterChangeNotificationEx(
[in] PRINTER_HANDLE hPrinter,
[in] DWORD fdwFlags,
[in] DWORD fdwOptions,
[in, string, unique] wchar_t* pszLocalMachine,
[in] DWORD dwPrinterLocal,
[in, unique] RPC_V2_NOTIFY_OPTIONS* pOptions
);
参数pszLocalMachine
即指向客户端计算机名称的字符串指针,通过该参数,就可以达到强制该主机向其他主机进行身份验证的目的。
根据MS-RPRN协议文档,可以看到打印机服务端初始化时,RPC接口是绑定在命名接口pipespoolss
上的:
在本地提权的场景中,需要将认证请求的目标也设为自己,这时通知会发送到\IPpipespoolss
,就带来两个问题:
-
• 该管道已经存在,并且是由SYSTEM控制,所以不能创建同名管道
-
• 不能使用
\IPpipetest
来接收,这样无法通过路径验证
解决办法是一个小技巧,如果主机名包含/
,这时可以通过路径验证,但是在计算要连接的命名管道的路径时,又会将其转换为,所以利用这样的名称
\IP/pipe/test
能够通过校验,最后会转换为\IPpipetestpipespoolss
,该管道和\IPpipespoolss
并不是同一个,所以符合要求。
0x5 土豆拾遗
0x01 Sweet Potato
Sweet Potato是Juicy Potato的优化版,并且集合了PrintSpoofer.
PoC:https://github.com/CCob/SweetPotato
0x02 Rogue Potato
Rogue Potato是Rotten Potato的改进版,因为微软限制了COM组件导致无法控制RPC对特定的IP和端口进行通信,所以漏洞作者提出了使用其他远程主机的135端口进行转发,将数据传到本地的RPC服务器上,具体参看:https://decoder.cloud/2020/05/11/no-more-juicypotato-old-story-welcome-roguepotato/
0x03 其他
还有一些土豆还没来得及研究,暂时将其列在这里,以后填坑:
-
• Ghost Potato
-
• Remote Potato
-
• Efs Potato
0x6 参考链接
-
• https://www.geekby.site/2020/08/potato%E5%AE%B6%E6%97%8F%E6%8F%90%E6%9D%83%E5%88%86%E6%9E%90/
-
• https://tttang.com/archive/1560/
-
• https://www.wangan.com/p/7fy747c482c3331f
-END-
如果本文对您有帮助,来个点赞、在看就是对我们莫大的鼓励。
推荐关注:
团队全员均持CISP-PTE(注册信息安全专业人员-渗透测试工程师)认证,积极参与着各类网络安全赛事并屡获佳绩,同时多次高水准的完成了国家级、省部级攻防演习活动以及相关重报工作,均得到甲方的一致青睐与肯定。
原文始发于微信公众号(弱口令安全实验室):Windows提权——土豆家族分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论