Save the Environment (Variable): Hijacking Legitimate Applications with a Minimal Footprint
Wietze Beukema (CrowdStrike)
BSides NYC 2023 (0x04) · Day 1 · Talk - Red
Overview
In this insightful talk from BSides NYC, Wietze Beukema of CrowdStrike unveils a novel and stealthy technique for DLL hijacking that leverages environment variables. The presentation delves into how attackers can trick legitimate, trusted Windows executables into loading malicious DLLs from attacker-controlled locations, all while maintaining an incredibly minimal operational footprint. This method stands out because it bypasses many traditional detection mechanisms that focus on common DLL hijacking variants, offering a fresh perspective on an old attack vector.

Key moments
- 1:00 What is DLL Hijacking?
- 1:45 Attacker Benefits of DLL Hijacking
- 2:15 Explaining DLL Side-Loading (Most Common Type)
- 4:20 Phantom DLL Hijacking: Exploiting Missing DLLs
- 6:15 Current DLL Hijacking is Well-Documented & Detected
- 6:55 Introducing Environment Variables for Novel Hijacking
- 7:30 Understanding What Environment Variables Are
Save the Environment (Variable): Hijacking Legitimate Applications with a Minimal Footprint
Speakers: Wietze Beukema, Consultant, CrowdStrike
Conference: BSides NYC
YouTube: https://www.youtube.com/watch?v=pWyVOn0k1Tc
Overview
In this insightful talk from BSides NYC, Wietze Beukema of CrowdStrike unveils a novel and stealthy technique for DLL hijacking that leverages environment variables. The presentation delves into how attackers can trick legitimate, trusted Windows executables into loading malicious DLLs from attacker-controlled locations, all while maintaining an incredibly minimal operational footprint. This method stands out because it bypasses many traditional detection mechanisms that focus on common DLL hijacking variants, offering a fresh perspective on an old attack vector.
Beukema's work is particularly significant for both offensive and defensive security practitioners. For red teams, it provides a new avenue for bypassing allow-listing solutions like Microsoft AppLocker and evading naive Endpoint Detection and Response (EDR) systems. For blue teams, it highlights a critical blind spot in current detection strategies, urging a re-evaluation of how process execution and environment variable manipulation are monitored. The talk not only demonstrates the technical feasibility but also provides a comprehensive methodology for discovering new vulnerabilities, revealing a widespread issue across the Windows ecosystem and popular third-party applications.
The core of the discovery lies in the often-overlooked interaction between process-level environment variables and how applications resolve DLL dependencies. By manipulating these variables at the process level before an application launches, an attacker can redirect legitimate DLL loads to a malicious version without altering the system registry or the legitimate executable itself. This subtle yet powerful technique underscores the persistent challenge of supply chain attacks and the need for deeper scrutiny into how trusted software components interact within the operating system.
Background
▶ Watch: What is DLL Hijacking? (1:00)
To fully appreciate the novelty of Beukema's technique, it's essential to understand the foundational concepts of DLL hijacking and environment variables.
DLL Hijacking is a broad category of attacks where an attacker tricks a legitimate application into loading a malicious Dynamic Link Library (DLL) instead of its intended, legitimate counterpart. This allows the attacker to execute arbitrary code within the context of a trusted process, often inheriting its privileges and reputation. Common forms of DLL hijacking include:
- DLL Side-Loading: The most prevalent type, where a vulnerable executable is placed in a directory controlled by the attacker (e.g., a temporary or download folder) alongside a malicious DLL. The executable then loads the malicious DLL from its current directory.
- DLL Search Order Hijacking: Windows searches for DLLs in a predefined order if a full path isn't specified. Attackers exploit this by placing a malicious DLL in a directory that is searched before the legitimate DLL's location (e.g., the application's directory before
System32). - DLL Substitution: Directly replacing a legitimate DLL with a malicious one, sometimes proxying calls to the original DLL to maintain functionality. The Stuxnet attack famously used this to modify a DLL in
System32. - Phantom DLL Hijacking: Exploiting applications that attempt to load non-existent DLLs. An attacker can create a malicious DLL with the expected name in a search path location, and the application will load it.
- Windows Side-by-Side (WinSxS) Hijacking: A rarer technique targeting Windows' compatibility mechanism for loading older DLLs.
- Input-Based Hijacking: Modifying registry entries or command-line parameters to redirect DLL loads.
While these techniques are well-documented and widely researched, leading to improved detection capabilities in modern EDR and antivirus solutions, they often leave observable footprints such as moving executables, modifying system files, or altering registry entries.
Environment Variables are global variables within an operating system that can be accessed by any program or process. They store critical system information, user preferences, and paths. Historically, environment variables originated in Unix systems (Version 7 Unix, 1979) to solve the problem of repetitive information (like username or home path) that programs frequently needed. This provided a centralized, easily accessible mechanism for configuration.
PC-DOS 2.0 (1983), which laid the groundwork for Windows, adopted environment variables, and their core functionality (e.g., using SET to define, %VARIABLE% for expansion) remains largely unchanged even today. However, with the advent of Windows 3.1 and the Windows Registry in 1992, a more robust and flexible mechanism for storing system and application settings emerged. The Registry offered typed data, hierarchical structures, and granular permission schemes, theoretically rendering environment variables redundant for many purposes.
Despite the Registry's superiority, environment variables persisted, largely due to backward compatibility and convenience. This persistence has historically led to security vulnerabilities. Beukema highlights a 1997 message board complaint about Microsoft's perceived inaction regarding environment variable security and notes that some of the earliest CVEs, dating back to the start of the millennium, involved privilege escalation issues related to environment variables, particularly the PATH variable. This legacy mechanism, while useful, has proven to be a recurring source of unforeseen security challenges due to its widespread use and the subtle ways it can be manipulated.
In Windows, environment variables are stored in several locations:
- Machine-wide: Defined in
HKEY_LOCAL_MACHINEin the Registry, loaded at boot. - User-specific: Defined in
HKEY_CURRENT_USERin the Registry, loaded upon user login. - Current Session: Temporary variables that last for the duration of a login session.
- Process-level: Crucially, every process has its own Process Environment Block (PEB) containing an environment block. When a new process is started, it typically inherits the environment variables from its parent process. However, the Windows API allows for the overriding of environment variables when launching a new process, enabling a child process to have a different set of variables than its parent. This specific mechanism is the linchpin of Beukema's technique.
The problem, therefore, exists due to the confluence of these factors: the enduring presence and utility of environment variables, their process-level modifiability, and the tendency of legacy and even modern applications to rely on them for resolving paths and loading dependencies, including DLLs.
Key Findings
▶ Watch: Explaining DLL Side-Loading (Most Common Type) (2:15)
Wietze Beukema's research uncovered a significant and broadly applicable method for DLL hijacking by manipulating process-level environment variables. The key findings include:
- A Novel, Low-Footprint Technique: The primary discovery is that by programmatically altering environment variables when launching a new process, attackers can redirect DLL loads to malicious versions without touching the registry, moving the legitimate executable, or modifying system files. This "process-level environment variable hijacking" results in a significantly reduced operational footprint compared to other DLL hijacking methods, making it challenging for traditional EDRs to detect.
- Widespread Vulnerability on Windows: Through systematic testing on a vanilla Windows 11 installation, Beukema identified a substantial number of vulnerable components.
- 82 distinct executables in the
System32folder were found to be susceptible. - These executables attempted to load 91 unique DLLs via manipulated environment variables.
- This translates to nearly 300 unique executable-DLL combinations that can be exploited out-of-the-box on a standard Windows installation using this technique.
- Impact on Third-Party Applications: The vulnerability is not confined to Windows' native components. Beukema demonstrated that popular third-party software is also affected:
- Microsoft Office 2021 applications (Word, PowerPoint, Excel) were all found to load at least one DLL using the
SYSTEMROOTvariable, making them vulnerable. - Major web browsers like Edge, Chrome, and Firefox also loaded DLLs in a way that could be manipulated.
- Common communication and productivity tools like Slack and Zoom were identified as potential targets. This broad applicability suggests that the issue is a systemic pattern rather than isolated flaws.
- Persistence Capabilities: The technique can be leveraged for persistence. By modifying registry entries for Windows services (e.g., the Printer Spooler service), an attacker can embed environment variable overrides. Upon system reboot or service restart, the service will launch with the manipulated environment, loading the malicious DLL. This was demonstrated to achieve code execution in the
SYSTEMcontext, an elevated privilege level that is highly desirable for attackers, even if it doesn't represent a direct privilege escalation from a user context.
- Limitations for Privilege Escalation: Beukema noted a crucial defensive measure implemented by Microsoft. When a process elevates via a User Account Control (UAC) prompt, Windows consciously resets or re-initializes its environment variables, preventing it from inheriting potentially malicious variables from a lower-privileged parent. This design decision largely mitigates direct privilege escalation via this specific environment variable hijacking method. However, Beukema also highlighted that a few specific processes might manually circumvent this behavior by copying parent environment variables post-elevation, leaving a narrow scope for exploitation.
- Importance of DLL Proxying and Resource Cloning: To ensure successful and stable exploitation without crashing target applications, simply creating a generic malicious DLL is insufficient. Beukema's methodology relies on DLL proxying (function redirection) and resource cloning. These techniques ensure that the legitimate functionality of the original DLL is preserved by redirecting calls to the original file, while still allowing the malicious code to execute within the trusted process's address space.
Overall, the key finding is the identification of a pervasive, stealthy attack vector that leverages a fundamental and often overlooked aspect of Windows process execution, posing a significant challenge for current defensive strategies.
Technical Deep Dive
▶ Watch: Phantom DLL Hijacking: Exploiting Missing DLLs (4:20)
The technical core of Wietze Beukema's research involved a systematic methodology to discover and exploit DLL hijacking opportunities using environment variables. This process required sophisticated techniques to ensure the stability of target applications while testing for vulnerabilities.
The methodology can be broken down into three main steps:
- Creating Malicious DLL Implants (Fake DLLs):
- Beukema aimed to test every DLL in the
System32folder on a vanilla Windows installation. To do this effectively, he needed a way to create "fake" versions of these DLLs that, when loaded, would simply register their execution without causing the legitimate application to crash. - Challenges: Simply creating a generic DLL with a
DllMainfunction often fails. Legitimate applications expect specific exports (public functions) and ordinals (numerical identifiers for exports) from their DLLs. If these are missing or incorrect, the application will likely crash or behave unexpectedly, making the test unreliable. Furthermore, DLLs often contain resources (e.g., images, icons, cursors) that applications might rely on. - Solutions:
- DLL Proxying (Function Redirection): This clever technique allows a malicious DLL to define the same exports as a legitimate DLL but redirect calls to these functions to the original, legitimate DLL. When the malicious DLL is loaded, its
DllMainexecutes, allowing the attacker's code to run. However, any subsequent calls to the DLL's exported functions are seamlessly passed to the original DLL, preserving the application's intended functionality. This is achieved by specifying the original DLL as a "forwarder" for each export in the malicious DLL's definition. - Resource Cloning: To handle embedded resources, Beukema's process involved copying all resources from the legitimate DLL to the malicious (cloned) DLL. This ensures that if an application tries to access a resource, it finds it in the malicious DLL, preventing crashes.
- Implant Functionality: When loaded, each implant DLL executes a simple
generate_fingerprintfunction. This function writes a file to a user-writable public folder (e.g.,C:\Users\Public\Downloads). The filename encodes critical information:[executable_name]_[dll_name]_[function_name]_[elevation_status]. For example,hostname_MSWSOCK_DllMain_0.txtwould indicate thathostname.exeloaded the maliciousMSWSOCK.dllvia itsDllMainfunction without elevation. - Automation: A Bash script, runnable on Linux (using MingW) or Windows, was developed to automate the creation of these proxy DLLs. It iterates through all target DLLs, identifies their exports and resources, and compiles corresponding malicious proxy DLLs.
- Target Selection and Execution:
- The next step involved selecting target executables. Beukema focused on all executables within the
C:\Windows\System32directory. - A PowerShell script was then used to iterate through each of these executables. For each executable, the script performed the following actions:
- It created a new process block.
- It specified the path to the legitimate executable (e.g.,
hostname.exeinC:\Windows\System32). Crucially, the executable itself was not moved or altered. - It then removed and re-added a target environment variable, such as
SYSTEMROOT, setting its value to a malicious, attacker-controlled path (e.g.,C:\temp\evil). - Finally, it launched the executable with these modified process-level environment variables, without any command-line arguments or user interaction.
- Validation:
- The success of an attempted hijack was validated by the presence of the fingerprint files generated by the malicious DLLs. If a fingerprint file appeared in the
C:\Users\Public\Downloadsfolder, it confirmed that the target executable had successfully loaded the malicious DLL from the manipulated path. This systematic approach allowed for the discovery of hundreds of unique vulnerable combinations.
The chosen environment variable, SYSTEMROOT, typically points to C:\Windows. Many applications rely on it to construct paths to other system directories, including C:\Windows\System32, where many legitimate DLLs reside. By changing SYSTEMROOT to C:\temp\evil, the applications would then look for DLLs in C:\temp\evil\System32 (if they append \System32 to the variable) or directly in C:\temp\evil (if they just use the variable as a base path).
This meticulous process, combining automated DLL generation with targeted process execution and robust validation, allowed Beukema to uncover the true scope of this environment variable-based DLL hijacking vulnerability. The emphasis on DLL proxying and resource cloning was critical to developing a stable and reliable testing methodology, which is often a major hurdle in DLL hijacking research.
Demo / Proof of Concept
▶ Watch: Introducing Environment Variables for Novel Hijacking (6:55)
Wietze Beukema presented several compelling demonstrations and proofs of concept to illustrate the efficacy and stealth of his environment variable-based DLL hijacking technique.
The primary demonstration involved hostname.exe, a mundane Windows utility whose sole function is to display the computer's hostname. Despite its simplicity, hostname.exe was found to be vulnerable.
- The Attack Setup:
- A malicious DLL, specifically a proxied version of
MSWSOCK.dll(a legitimate DLL often loaded byhostname.exe), was crafted. This maliciousMSWSOCK.dllwas placed inC:\temp\evil\System32. - The malicious DLL was programmed to perform two actions upon loading:
- Display a pop-up message box (a visual indicator of compromise).
- Launch
calc.exe(the Windows calculator), a classic and undeniable proof of arbitrary code execution. - Procmon (Process Monitor), a Sysinternals utility, was run in the background to capture detailed process and file system activity, providing forensic evidence of the DLL load.
- Execution via PowerShell:
- The attack was initiated using a concise PowerShell script. This script was designed to launch
hostname.exewith a modifiedSYSTEMROOTenvironment variable. - The key steps in the PowerShell script were:
- This script effectively launched
hostname.exefrom its normal, trustedC:\Windows\System32location, but with its process-levelSYSTEMROOTenvironment variable temporarily redefined toC:\temp\evil.
- Visual Confirmation and Procmon Evidence:
- Upon executing the PowerShell script, a message box immediately popped up, followed by
calc.exelaunching. This visually confirmed that the malicious DLL had been successfully loaded and executed within thehostname.exeprocess. - Procmon logs provided irrefutable evidence. They showed
hostname.exe(running fromC:\Windows\System32) attempting to loadMSWSOCK.dlland, due to the manipulatedSYSTEMROOTvariable, successfully loading the malicious version fromC:\temp\evil\System32\MSWSOCK.dllinstead of the legitimate one.
Beukema also briefly showcased an equivalent proof of concept using VBScript, demonstrating that the technique is not limited to PowerShell and can be executed via other built-in scripting engines, making it accessible even in environments with restricted PowerShell execution. The VBScript example was similarly concise, using the WScript.Shell object to manipulate environment variables and execute the target process.
Beyond local DLL planting, Beukema highlighted that the technique could potentially support remote DLL loading. By pointing the manipulated environment variable to a UNC path (e.g., \\attacker-share\evil) or even a WebDAV path, an attacker could load the malicious DLL directly from a remote server, further reducing the on-disk footprint on the target system. This could potentially bypass detections that rely on monitoring local file writes or specific temporary directories.
Finally, a proof of concept for persistence was demonstrated using the Printer Spooler service.
- The
Environmentoption within a service's registry entry (e.g.,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Spooler) can be manually added. - By setting this
Environmentvalue to overrideSYSTEMROOTtoC:\temp\windows64(containing a malicious DLL), and then restarting the service or rebooting the machine, the Printer Spooler service (spoolsv.exe) would load the malicious DLL. - Crucially, this allowed code execution in the
SYSTEMcontext, demonstrating a powerful persistence mechanism that is difficult to detect, as the legitimatespoolsv.exeis still running, and the environment variable change is subtle. While this does not represent a privilege escalation from a standard user toSYSTEM(as modifying service registry entries typically requires administrator privileges), it provides a robust way to maintainSYSTEMlevel access once those privileges are initially obtained.
These demonstrations collectively underscored the stealth, versatility, and impact of environment variable-based DLL hijacking, showcasing its potential for initial access, bypass, and persistence.
Defensive Implications
▶ Watch: Understanding What Environment Variables Are (7:30)
Wietze Beukema's research provides critical insights for both software developers and security defenders (blue teams) to mitigate the risks associated with environment variable-based DLL hijacking.
For Developers
Developers play a crucial role in preventing these types of vulnerabilities at their source. Beukema's recommendations are straightforward:
- Use Absolute Paths: Whenever possible, developers should avoid relying on environment variables to construct paths for loading DLLs or other critical files. Instead, they should use absolute paths to ensure that the application always loads the intended, legitimate file. Windows API calls exist (e.g.,
GetSystemDirectory(),GetWindowsDirectory()) that provide trusted, kernel-approved paths, removing the ambiguity and susceptibility to environment variable manipulation. - Validate DLLs: For scenarios where absolute paths are not feasible (e.g., portable applications that must load components relative to their own location), developers should implement robust DLL validation. This includes checking digital signatures, computing and verifying checksums, or using other integrity checks before loading a DLL. While this might have a minor performance impact, it significantly increases the bar for attackers.
For Defenders (Blue Team)
Current EDR and antivirus solutions often struggle to detect this specific type of DLL hijacking due to its low footprint. Beukema offers several actionable recommendations for improving detection:
- Monitor Process-Level Environment Variable Changes: This is the most direct and impactful detection strategy. Most EDRs do not currently monitor the environment block passed to new processes. Defenders should look for instances where a child process is spawned with an environment variable (like
SYSTEMROOT,PATH, orTEMP) that differs significantly from its parent process, especially if the new value points to a user-writable or otherwise unusual directory. This would require enhanced telemetry collection from EDRs or custom instrumentation. - Monitor DLL Loads from Unusual Locations: While not foolproof, monitoring for DLLs being loaded from non-standard locations (e.g.,
C:\temp,C:\Users\Public\Downloads, orUNCpaths) remains a fundamental detection technique. Specifically forSYSTEMROOThijacking, defenders should look for instances wheresystem32subfolders are being accessed from a base path other thanC:\Windows. Beukema noted thatsystem32folders outsideC:\Windowsare extremely rare in legitimate operations, making this a high-fidelity indicator. - Leverage HijackLibs: Beukema introduced HijackLibs, an open-source, collaborative platform designed to document known DLL hijacking instances. This resource is invaluable for defenders:
- It lists environment variable-based hijacking instances discovered in his research, as well as known side-loading, phantom, and search order hijacking vulnerabilities.
- For each documented DLL, it provides information such as its normal location, vulnerable executables, and basic detection logic in Sigma language. Sigma rules can be converted to various EDR and SIEM query languages, enabling defenders to implement specific detections for known vulnerable combinations.
- The platform categorizes vulnerabilities by vendor, allowing organizations to prioritize monitoring for software prevalent in their environment (e.g., VLC, Office applications).
- By actively using HijackLibs, blue teams can baseline their environments and identify anomalous DLL loads that match known hijacking patterns.
- Focus on Post-Exploitation Behavior: Even if the initial DLL hijacking is missed, the malicious code will likely perform subsequent actions that are easier to detect. Defenders should focus on:
- Unusual network connections: Malicious DLLs often attempt to establish C2 (command and control) communications.
- Suspicious process spawning: If a legitimate process like
hostname.exeorspoolsv.exesuddenly spawnscmd.exe,powershell.exe, or other unusual executables, it's a strong indicator of compromise. - File system modifications: Ransomware or data exfiltration often involves writing or encrypting files.
Beukema emphasized that while it's impossible to monitor every single potential DLL hijacking vector, focusing on known instances and the subsequent actions of malicious code provides a robust layered defense. The community-driven nature of HijackLibs encourages collaboration, allowing defenders to stay updated on emerging threats and contribute their own findings.
Key Takeaways
- Environment Variable-Based DLL Hijacking is a Novel and Stealthy Attack Vector: By manipulating process-level environment variables, attackers can trick legitimate applications into loading malicious DLLs with a minimal operational footprint, bypassing many existing EDR and AV detections.
- Widespread Vulnerability Across Windows and Third-Party Software: Beukema's research identified nearly 300 unique vulnerable executable-DLL combinations on a vanilla Windows 11 installation, affecting core Windows components, Microsoft Office, popular browsers, and communication applications like Slack and Zoom.
- DLL Proxying and Resource Cloning are Critical for Stable Exploitation: To prevent application crashes and maintain functionality, successful exploitation often requires techniques like DLL proxying (redirecting legitimate function calls to the original DLL) and resource cloning.
- Persistence is Achievable, but Privilege Escalation is Largely Mitigated: The technique can be used for persistence by modifying service environment variables (e.g., Printer Spooler service for
SYSTEMcontext). However, Windows' UAC mechanism typically resets environment variables for elevated processes, limiting direct privilege escalation via this method. - Developers Must Prioritize Absolute Paths and DLL Validation: To prevent these vulnerabilities, developers should use absolute paths for loading dependencies and implement strong validation (e.g., digital signatures, checksums) for DLLs when absolute paths are not feasible.
- Defenders Need Enhanced Monitoring and Community Resources: Blue teams should focus on monitoring for changes to process-level environment variables, unusual DLL load paths (especially
system32folders outsideC:\Windows), and post-exploitation behaviors. The open-source HijackLibs project (github.com/Wietze/HijackLibs) is a valuable resource for identifying known vulnerable combinations and implementing detection rules.
About the Speaker(s)
Wietze Beukema is a Security Consultant at CrowdStrike, a prominent cybersecurity technology company. Originally from Amsterdam, he is now based in London, UK. Beukema is an experienced speaker, having presented his research at various reputable security conferences, including BSides London, BSides Rome, and Defcon. His work often focuses on offensive security techniques and novel methods for bypassing security controls, contributing valuable insights to the broader cybersecurity community.
Reviews
Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT
Beukema takes a well-worn attack class and finds genuinely new surface by pivoting to process-level environment variable injection — a mechanism most DLL hijacking research walks right past. The scope of the finding (nearly 300 vulnerable combinations on a stock Win11 install, hitting Office, Chrome, Slack, Zoom) and the disciplined methodology (proxy DLLs, resource cloning, automated validation) make this worth the room's time. Doesn't reinvent the wheel, but drills meaningfully into a spoke nobody was looking at.
Heather Calloway (CISO) — SOLID
Technically rigorous research on an underexplored DLL hijacking variant with real defender value for EDR tuning and detection engineering. The scope stays narrow — this is a Windows exploitation technique with tooling and detection guidance — and it doesn't reach governance, institutional risk, or the executive decisions that follow.