In this two-part series we discuss two Windows local privilege escalation vulnerabilities that we commonly identify during red team operations. These issues are of particular interest due to their prevalence within organizations with mature security programs. Furthermore, exploitation of the issue is unlikely to trigger a detection within commonly used endpoint and network monitoring products.
The root cause of these issues arises from common system misconfigurations, which makes identifying and exploiting these issues extremely reliable. By contrast, traditional memory-corruption based local privilege escalation vulnerabilities often require fixed offsets depending on the operating system version or system build used by the target. In part one of this series, we cover a local privilege escalation issue arising from a writable directory within the system path environment variable.
Writable System Path Directory Vulnerability
The writable path local privilege escalation vulnerability arises from scenarios where a systems administrator or application installer has modified the system path environment variable to include a directory writable by unprivileged users.
A typical root cause of this issue is when application installers or administrators install applications outside of the appropriate directory (e.g. “Program Files”) and then subsequently modify the system path environment variable to point to the installed directory. As a result, the created directory inherits dangerous permissions from the parent directory.
One example of this is the stark difference between the inherited permissions of a directory created within the “C:\Program Files” directory versus the “C:\” directory. As you may observe in the image below, the “Authenticated Users” group is given the ability to create files and folders within the “C:\” directory. Furthermore, this permission is inheritable, meaning that it applies to all created directories which do not explicitly deny it.
In contrast, the “Program Files” directory does not include this permission by default, and folders created within “Program Files” prevent unprivileged users from writing to them by default as shown in the image below.
By performing a simple experiment, we can confirm the expected behavior. As an administrator, create two folders named “test” in both C:\Program Files\test and C:\test. Next, create an unprivileged user and attempt to write to both directories. Observe that the non-administrative user can write to C:\test\ but not C:\Program Files\test\ as shown in the image below.
Exploitation of the Writable Path Issue
In this post, we are particularly interested in the red team operational perspective which goes beyond the development of a basic proof of concept exploit. The most straightforward way to exploit a writable path vulnerability is to identify an application service running as NT AUTHORITY\SYSTEM that attempts to load a non-existent dynamically linked library (DLL) or attempts to execute a non-existent executable file. For example, a service may attempt to load a DLL file which only exists on desktop operating systems. Since this file doesn’t exist on server operating systems, it will eventually traverse the system path, looking for the file. From an operational perspective, the best scenario for an attacker is when an unprivileged user can trigger this action without requiring a reboot of the target system.
One such example is the NetMan service identified by Clément Labro which allows an unprivileged user to interact with it through an exposed COM interface . An important note is that, according to Microsoft, this behavior does not constitute a vulnerability in Windows as the system is performing the appropriate actions to search the path . However, if a third party application installer has modified the system path environment variable during installation and introduced the writable path privilege issue this likely qualifies for a vulnerability/CVE in the application installer.
However, from an exploitation perspective, things are much more complicated as the susceptible services can vary depending on the operating system version leveraged by the target system. In the table given below, we outline three separate services that can be leveraged to escalate privileges through DLL planting and the corresponding operating system versions where that technique is viable.
When one of these services loads an attacker-supplied DLL, the Windows loader will call the DllMain function, regardless of which exported functions are called by the target service. When DllMain is executed the attacker can then add themselves to the local administrators group.While this is typically fine for a proof of concept exploit, it generally is not ideal from an operational security perspective. Modifying the local administrator’s group membership can create event log entries, which can be alerted on by security tools. A more operationally sound method is to execute a remote administration tool such as Cobalt Strike’s beacon payload within the privileged service context.
Attempting to load a beacon into a hijacked process can result in a deadlock under certain conditions. A common mistake made by operators is to invoke a reflective loader within the context of the hijacked process from within DllMain. Because the Windows loader holds the loader lock during the execution of DllMain, invoking a reflective loader from within DllMain results in a process deadlock when the reflective loader also calls LoadLibrary and waits on the loader lock to be released. The most straightforward way to address this issue is to wait for the service to invoke an export associated with the hijacked DLL when the loader lock is not activated. An attacker can perform reverse engineering of the corresponding service executable to reveal which exports are leveraged by the victim service.
Exploitation Using The Windows Task Scheduler
In his article titled “Windows 10 – Task Scheduler service – Privilege Escalation/Persistence through DLL planting”  Gregory Draperi outlines a method of exploiting the writable path vulnerability by targeting the Windows Task Scheduler service. Gregory identified that this service attempts to load the WptsExtensions.dll file upon startup by calling the LoadLibrary function. The downside of leveraging this method is triggering the behavior of the target service requires a reboot of the system as the service only attempts to load the DLL at system startup .
Exploitation leveraging this vector is relatively straightforward. The attacker simply needs to place a malicious DLL into the writable path directory and either wait for or trigger a system reboot. However, on Windows Server operating systems non-administrative users do not have permission to perform a shutdown or reboot operation. Additionally, performing a reboot of a production system is typically ill-advised and can have adverse implications in terms of red team operational security.
Exploitation Using The NetMan Service
Clément Labro, in his article titled “Windows Server 2008R2-2019 NetMan DLL Hijacking,” outlines his research into the Windows NetMan service and how it can be leveraged to perform DLL hijacking . Labro identified a COM interface exposed by the NetMan service that was accessible by unprivileged users.
By enumerating connection properties using the exposed COM interface, Labro could trigger a call to LoadLibrary to load the “wlanapi.dll” file . While the “wlanapi.dll” file does not exist on any supported Windows Server operating systems by default, it does exist on Windows 10, making this technique only viable when performing privilege escalation targeting Windows Server. However, even in cases where a service isn’t directly usable for local privilege escalation through this vector, an attacker can still use the service to perform lateral movement or establish persistence.
Exploitation is relatively straightforward in this scenario and works by simply copying the attacker “wlanapi.dll” file to the writable path directory. In his article, Labro notes that on Windows Server 2012 R2, the service will instead attempt to load a file named “wlanhlp.dll” ; however, testing by Praetorian indicates that the service now tries to load “wlanapi.dll.” Next, the attacker needs to leverage the code provided by Labro to enumerate network adapters over COM triggering the DLL load attempt .
The Curious Case of the IKEEXT Service
In an article titled “Triaging a DLL Planting Vulnerability” , the Microsoft Security Response Center (MSRC) team describes the process they follow when triaging various types of DLL planting issues. MSRC states that “DLL planting issues that fall into the category of PATH directories DLL planting are treated as ‘won’t fix’.”  One interesting case where Microsoft appears to have deviated from this stated policy is in the case of the IKEEXT service .
In this case Microsoft appears to have addressed the IKEEXT service DLL hijacking by modifying the LoadLibrary call to instead make a call to LoadLibraryEx with the LOAD_LIBRARY_SEARCH_SYSTEM32 flag set to only search the System32 directory for the “wlbsctrl.dll” file as shown in the image below.
However, as the service still attempts to load the non-existent DLL upon startup, this service is still useful for exploiting arbitrary write issues or performing lateral movement, as documented by Dwight Hohnstein .
Alternative Exploitation Techniques
Previously we stated that the simplest way to exploit the writable path vulnerability is to identify a service running as “NT AUTHORITY\SYSTEM” that attempts to load a non-existent DLL by traversing the system path. However, an alternative method does exist to exploit this issue by performing the same attack but against a service running as “NT AUTHORITY\NETWORK SERVICE” or “NT AUTHORITY\LOCAL SERVICE”. Windows services are given the SeImpersonatePrivilege right by default  as shown in the image given below.
Yarden Shafir and Alex Ionescu outline their research into the Windows Fax Service in their article titled “Faxing Your Way to SYSTEM — Part Two”  which documents their discovery that the Windows Fax Service attempts to load a non-existent DLL upon startup. Furthermore, the Windows Fax Service is configured such that any user can trigger a start of the service as shown in the image given below.
Because the Windows Fax Service is granted SeImpersonatePrivilege rights by default it is possible to first create a named pipe and then induce a more privileged service into accessing the named pipe to impersonate the client service . In the article, the authors leverage a technique documented by James Foreshaw in his post “Sharing a Logon Session a Little Too Much.”  This technique involves creating a named pipe and connecting through it using the \\localhost\ path, which triggers an authentication from the SMB network redirector.
The authors then leverage impersonation to gain access to the access token associated with the RpcSs service, open a handle to the service associated with the RpcSs process, and scan the handle table to identify an access token associated with the “NT AUTHORITY\SYSTEM” user . Upon identification of this token, the token is copied to gain SYSTEM privileges .
Additionally, Clément Labro outlines an alternative method of moving from SeImpersonatePrivilege to “NT AUTHORITY\SYSTEM” in his blog post titled “PrintSpoofer – Abusing Impersonation Privileges on Windows 10 and Server 2019”  along with an open source tool for operationalizing the technique .
Unfortunately, when the Windows Fax Service attempts to load the non-existent “ualapi.dll” file it does so through a call to the LoadLibraryExW function with the LOAD_LIBRARY_SEARCH_SYSTEM32 flag set meaning that in this instance the service will not traverse the system path environment variable when attempting to load the DLL . Instead, the service will only check for the DLL file within the “C:\Windows\System32\” directory. While this is useful for both lateral movement and persistence, it is not useful in instances where we are looking to exploit the writable path directory vulnerability in this case.
Post-Exploitation Operational Guidance
From an operational perspective, one of the most desirable targets for local privilege escalation is multi-user systems that are easily accessible and widely used by multiple departments or administrative tiers of users.
Citrix is a perfect example of this design pattern in action. In many organizations, we have noted that access to Citrix does not require multi-factor authentication when the connection originates from the internal network. Furthermore, Citrix is generally accessible by any employee within the organization, and use tends to span across multiple departments. Additionally, Citrix hosts often have a multitude of applications installed and we have frequently observed the writable path privilege escalation issue on these hosts because of this.
After gaining an internal foothold, we can then attempt to connect to Citrix from an internal perspective by proxying the Citrix receiver desktop application through SOCKS to bypass multi-factor authentication. Accessing Citrix in this manner often provides a quick and easy way to achieve initial lateral movement within an environment with minimal risk. Once access to Citrix is achieved, we can often escalate privileges by exploiting configuration issues related to writable directories within the path.
With NT AUTHORITY\SYSTEM level access, we can then install a malicious security support provider to log cleartext credentials for all users who authenticate to any Citrix host within the environment. Often, this provides us with enough access to achieve the objective for the engagement.
Targeting these types of shared user systems is particularly beneficial when targeting an environment with a mature detection and response capability. In these types of environments, the standard red team attack and lateral movement techniques will be quickly detected and result in eviction.
Remediation of the writable path issue is relatively easy as the writable directory’s permissions simply need to be modified. If an application installer introduced the writable path vulnerability by modifying the system path, consider reporting the issue to the application vendor so that the issue can be remediated for all customers. For example, CVE-2020-15264 covers a case where the Boxstarter application installer modified the system path to include a writable directory in program files .
From an architectural perspective, the security boundary between users at the operating system level is often weaker than the security boundary enforced between virtual machines at the hypervisor level. Because of this, we generally recommend avoiding the single-system multi-user design pattern whenever possible, especially in scenarios where multiple tiers of users or departments access the system.
In part one, we discussed the fundamental concepts behind the writable path privilege escalation vulnerability, documented exploitation methods, and provided operational guidance on leveraging this technique during a red team engagement. In part two, we will discuss another common local privilege escalation vector and advise on operationalizing this technique through Cobalt Strike’s beacon.