Shared Modules (T1129) is malicious code executed by loading a DLL, shared object or dylib into a process, which lets malware split its features into plug-ins and run them through the same loader every legitimate program uses. ATT&CK v20 places T1129 in the Execution tactic (TA0002) on Windows, Linux and macOS, with no sub-techniques and one mapped mitigation, Execution Prevention (M1038). Because every process loads modules all the time, the signal is not the load itself but where the module came from, who signed it and what happened next. This page covers the loader mechanics on each platform, ATT&CK procedure examples, the v20 detection strategy, hardening settings, testing and framework mapping. Hijacking the search order to make a legitimate program load a planted library is a different technique, covered in the T1574 Hijack Execution Flow Defensive Guide.
Key takeaways
- It is how modular malware works. ATT&CK lists more than 20 procedure examples, from Stuxnet and PlugX-era loaders to RotaJakiro on Linux and OSX_OCEANLOTUS.D on macOS.
- Location and signer are the signal. ATT&CK v20 strategy DET0018 looks for modules loaded from user-writable, temp or UNC paths, or with unsigned or invalid signers, shortly after they were written or downloaded.
- Identity infrastructure is a target. ATT&CK records FoggyWeb loading its DLL on compromised AD FS servers, and Ebury running through a hooked keyutils.so used by OpenSSH.
- Code integrity is the mitigation. M1038 means application control that can block unknown modules, not only unknown executables: App Control for Business DLL rules, fapolicyd, and macOS library validation.
- Linux loader variables matter. LD_PRELOAD and LD_LIBRARY_PATH pointing at /tmp or /dev/shm are a v20 detection element; the dynamic linker ignores them for set-user-ID programs in secure-execution mode, but not for ordinary processes.
How module loading works on each platform
| Platform | Loader and API | Module type | Where abuse shows |
|---|---|---|---|
| Windows | LoadLibrary and LoadLibraryEx, implemented in NTDLL.dll as part of the Native API; ATT&CK notes the loader accepts arbitrary local paths and UNC network paths | .dll (any extension can be loaded) | DLLs in AppData, Temp, ProgramData or on \\server\share, loaded by a process that just wrote them |
| Linux | dlopen and dlsym (dlfcn.h); the dynamic linker ld.so also honours LD_PRELOAD, LD_LIBRARY_PATH and /etc/ld.so.preload | .so | Shared objects in /tmp, /dev/shm or home folders; processes started with loader variables pointing at non-system folders |
| macOS | dyld with dlopen and dlsym | .dylib (macOS can also load .so) | Libraries in ~/Library or /tmp, unsigned or ad hoc signed |
Two loader facts help defenders. On Windows, Microsoft documents safe DLL search mode (on by default) and the KnownDLLs list under HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs, which forces the system copy of listed DLLs; it also warns that a DLL loaded by full path still has its dependencies resolved by name. On Linux, the ld.so manual states that in secure-execution mode (AT_SECURE set, typically set-user-ID programs) LD_LIBRARY_PATH is ignored and LD_PRELOAD entries containing slashes are ignored. Ordinary processes get no such protection. The API layer itself is ATT&CK T1106 Native API.
Real cases
| Software or actor | What ATT&CK v20 records | Defender lesson |
|---|---|---|
| FoggyWeb (S0661) | Loader calls load() to put the FoggyWeb DLL into an Application Domain on a compromised AD FS server (Microsoft, September 2021) | Monitor module loads on identity federation servers as tier 0 assets |
| Ebury (S0377) | Executes by hooking the keyutils.so file used by OpenSSH and libcurl (ESET, May 2024) | File integrity on system libraries used by SSH protects credentials directly |
| RotaJakiro (S1078) | Uses .so files through dlopen() and dlsym() for additional functionality (360 Netlab, 2021) | Linux backdoors are modular too; watch .so writes outside package-managed folders |
| OSX_OCEANLOTUS.D (S0352) | Loads a .dylib with dlopen() and calls it through dlsym() for network communications (Palo Alto Networks, 2017) | Unsigned dylibs loaded by unsigned apps on macOS are a lead |
| LightSpy (S1185) | Loads its main executable and module .dylib files with dlopen() | Plug-in style surveillance frameworks on macOS |
| Mustang Panda (G0129) | Has used LoadLibrary to load DLLs (ESET, March 2022) | State groups rely on ordinary loader calls |
| Stuxnet (S0603) | Calls LoadLibrary then executes exports from a DLL (Symantec, 2011) | The pattern predates most current tooling and still works |
See the Mustang Panda Threat Actor Profile Guide.
What to detect and where
ATT&CK v20 detection strategy DET0018 is a behaviour chain: a module load from a suspicious place or signer, close in time to the module being written, followed by more execution or network activity.
| Platform (analytic) | Behaviour | Log sources named in v20 |
|---|---|---|
| Windows (AN0052) | A process (often a LOLBin or user-launched program) loads a DLL from a user-writable, UNC or Temp path, or with an unsigned or invalid signer; within a short window the DLL was newly written, is run again through rundll32 or regsvr32, or the process connects out | Sysmon 7 (image load), Sysmon 11, Security 4688, Sysmon 3 and 22, Microsoft-Windows-CodeIntegrity/Operational |
| Linux (AN0053) | A process loads a .so through dlopen, LD_PRELOAD or open from /tmp, /dev/shm or other non-standard paths, especially soon after it was written or fetched, or runs with LD_PRELOAD or LD_LIBRARY_PATH pointing at non-system folders | auditd openat and mmap on .so files, auditd EXECVE with loader variables, syslog, network flow for ELF transfers |
| macOS (AN0054) | A process loads a non-system .dylib or .so from ~/Library or /tmp, or soon after the library was created or downloaded, often followed by egress or persistence | Unified log dyld entries, Endpoint Security exec and open events |
Making it workable
- Do not log every load: Sysmon event 7 is high volume. Filter at collection to non-system paths, unsigned images and sensitive processes (LSASS, AD FS, web servers, SSH daemons) rather than ingesting all image loads.
- Join write and load: a file creation followed by a load of the same path within minutes is far stronger than either alone.
- Watch rundll32 and regsvr32 children: the v20 analytic names them as the common follow-on execution for a newly written DLL. See the T1218 System Binary Proxy Execution Defensive Guide.
- Treat UNC module loads as rare: few modern applications load code from a network share; those that do can be allow-listed by path and server.
- Use CodeIntegrity events even in audit mode: an App Control policy in audit mode records the DLLs that would have been blocked, which is a ready-made hunting list.
- On Linux, check /etc/ld.so.preload: it is a system-wide preload list; any unexpected entry deserves investigation. See the Linux Logging and auditd for Defenders Guide.
Mitigations and hardening
| Control | Platform | Setting or mechanism | Notes |
|---|---|---|---|
| M1038 Execution Prevention (ATT&CK) | All | Application control that can stop unknown modules from loading, not only executables | The only v20 mitigation mapped to T1129 |
| App Control for Business DLL enforcement | Windows | App Control policies apply to DLLs as well as executables; audit first, review CodeIntegrity events, then enforce | AppLocker DLL rules are optional and add performance cost |
| Safe DLL search and KnownDLLs | Windows | Keep SafeDllSearchMode at its default (enabled) under HKLM\System\CurrentControlSet\Control\Session Manager | Limits planted DLLs being picked up by name |
| fapolicyd | Linux | Trust database of package-managed files; deny execution and mapping of untrusted .so files | Covers shared objects as well as binaries |
| noexec mounts | Linux | Mount /tmp and /dev/shm with noexec where workloads allow | Reduces simple staging in writable folders |
| Hardened Runtime and library validation | macOS | Apple documents that the Hardened Runtime protects against code injection and library hijacking; avoid shipping com.apple.security.cs.disable-library-validation or allow-dyld-environment-variables unless required | Applies to apps you build or approve |
| File integrity monitoring | All | Monitor system library folders and SSH, PAM and web server modules | Catches Ebury-style library replacement |
See the M1038 Execution Prevention, the App Control for Business (WDAC) and the fapolicyd and Linux Application Allowlisting Guide.
Decision guidance
- Start with tier 0 and servers: AD FS, domain controllers, identity providers, SSH bastions and web servers have stable module sets, so DLL and .so allow-listing is practical there first.
- Workstations: use EDR detection plus App Control in audit mode, then enforce once the pilot ring is clean. Developer machines will need wider rules and closer monitoring.
- Linux fleets: fapolicyd suits package-managed servers; container hosts benefit more from immutable images and read-only root filesystems.
- Small teams: rely on EDR alerts for unsigned modules from writable paths and file integrity monitoring on identity servers before attempting full module allow-listing.
Where identity fits
Two of the ATT&CK cases target identity directly. FoggyWeb ran inside AD FS, where token-signing certificates and federation trust live; Ebury hooks a library used by OpenSSH, where server and user credentials pass through. After any confirmed malicious module on such a host, treat the identity material on it as exposed: rotate AD FS token-signing and decryption certificates, SSH host keys and the service account credentials the host used, and review federation trusts. The same logic applies to build agents and secrets brokers. See the T1055 Process Injection Defensive Guide for the related in-memory case.
How to test
- Build a benign test module: a DLL, .so or .dylib that only writes a marker file, created by your team for testing.
- Load it from a writable path: on a test host, load it from Temp, /tmp or ~/Library with a small test harness or an authorised emulation framework.
- Verify telemetry: confirm Sysmon 7 and 11 (Windows), auditd openat or mmap (Linux) and Endpoint Security or unified log events (macOS) reach the SIEM.
- Verify the chain rule: write then load within the window should alert; a signed vendor DLL from Program Files should not.
- Verify prevention: with App Control or fapolicyd in enforce mode on the pilot, confirm the load is blocked and logged.
- Roll back: keep the prior policy ready, remove the test module and record exceptions.
Measures: tier 0 servers with module allow-listing enforced, unsigned module loads from writable paths per week, mean time to alert in tests, and unexpected entries in /etc/ld.so.preload across the Linux fleet (target zero).
Common failure patterns
- Executable-only allow-listing: policies that check .exe files but not DLLs leave T1129 untouched.
- Ingesting all image loads: the SIEM drowns, the data source is turned off, and nothing remains.
- Ignoring identity servers: AD FS and SSH hosts are treated as ordinary servers, although modules there reach token-signing keys and credentials.
- Writable system paths: loose permissions on application or library folders let attackers place modules where loaders trust them.
- Disabling library validation for convenience: granting the macOS exception entitlements broadly removes the platform's own defence.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| MITRE ATT&CK v20 | T1129, TA0002, DET0018 (AN0052, AN0053, AN0054), M1038 | Technique, detection strategy and mitigation |
| MITRE ATT&CK v20 | T1106, T1574, T1574.001, T1574.006, T1218.011, T1055 | Related techniques (each has its own page) |
| MITRE D3FEND | D3-EAL Executable Allowlisting, D3-FCA File Creation Analysis, D3-PA Process Analysis | Module allow-listing, write-then-load analysis |
| NIST SP 800-53 Rev 5 | CM-7(5), SI-7, SI-7(15), SI-4, AU-12 | Allow-by-exception, integrity, code authentication, monitoring, audit generation |
| NIST CSF 2.0 | PR.PS-05, DE.CM-09, DE.AE-02 | Unauthorised software prevention, endpoint monitoring, analysis |
Practitioner checklist
- Implement DET0018: module write followed by load from writable, temp or UNC paths.
- Filter Sysmon 7 to non-system paths, unsigned images and sensitive processes.
- Run App Control for Business with DLL coverage in audit, then enforce, starting with tier 0 servers.
- Deploy fapolicyd or equivalent on package-managed Linux servers.
- Alert on processes started with LD_PRELOAD or LD_LIBRARY_PATH pointing at non-system folders.
- Monitor /etc/ld.so.preload and system library folders with file integrity monitoring.
- Keep SafeDllSearchMode at its default and review KnownDLLs changes.
- Rotate identity material on any host with a confirmed malicious module.
Standards and references
- MITRE ATT&CK: T1129 Shared Modules
- MITRE ATT&CK: M1038 Execution Prevention
- Microsoft Learn: Dynamic-link library search order
- Linux man-pages: ld.so(8)
- Apple Developer: Hardened Runtime
- Microsoft Learn: Applications that can bypass App Control and how to block them
- MITRE D3FEND: Executable Allowlisting
Related NHI Mgmt Group resources: ATT&CK Execution Tactic Guide · T1574 Hijack Execution Flow Defensive Guide · Top 10 Infrastructure as Code Misconfigurations · Linux Logging and auditd for Defenders Guide · Sysmon Guide