SOC Prime Bias: High

13 Feb 2026 17:05

OysterLoader Uncovered: Inside a Multi-Stage Evasion Loader

Author Photo
Ruslan Mikhalov Chief of Threat Research at SOC Prime linkedin icon Follow
OysterLoader Uncovered: Inside a Multi-Stage Evasion Loader
shield icon

Detection stack

  • AIDR
  • Alert
  • ETL
  • Query

Summary

OysterLoader is a C++ multi-stage loader used to deploy ransomware and commodity malware such as Vidar. It spreads through compromised sites that impersonate legitimate software installers and is delivered as a Microsoft Installer (MSI). To complicate analysis, it uses API call flooding, custom dynamic API resolution, anti-debug checks, and a custom LZMA decompression routine. The loader talks to a tiered HTTPS C2 infrastructure using obfuscated HTTP headers and a proprietary Base64-like encoding.

Investigation

The report outlines four stages: a packed obfuscator (TextShell), a shellcode layer that inflates content with LZMA, a downloader that performs environment checks and creates a mutex, and a final stage that drops a DLL and installs a scheduled task. C2 traffic relies on hard-coded IPs/domains, custom user-agents, and steganographic payload delivery via PNG icons. Persistence is maintained by a scheduled task configured to run every 13 minutes.

Mitigation

Block unsigned MSI installers from untrusted sources and monitor for creation of the known mutex patterns. Alert on scheduled task name patterns and the use of rundll32.exe to load DLLs from %APPDATA%. Where feasible, enforce TLS inspection to identify the custom HTTP headers and user-agents used by the loader.

Response

If detected, isolate the host, terminate the scheduled task, and remove the dropped COPYING3.dll file. Hunt for additional payloads, enumerate processes matching the mutex values, block the listed C2 domains/IPs, and update detections for the API flooding behavior and custom Base64 encoding.

"graph TB %% Class definitions classDef action fill:#99ccff classDef malware fill:#ffcc99 classDef process fill:#ffeb99 classDef persistence fill:#c2f0c2 classDef c2 fill:#d9b3ff %% Nodes initial_access["<b>Initial Access</b> – <b>T1218.007 System Binary Proxy Execution: Msiexec</b><br/>Signed malicious MSI delivered via compromised website."] class initial_access action process_msiexec["<b>Process</b> – msiexec.exe<br/>Executes malicious MSI"] class process_msiexec process stage1["<b>Stage 1</b> – Packer/Obfuscator<br/><b>Techniques</b>: T1027 Obfuscated Files or Information, T1027.007 Dynamic API Resolution, T1614.001 System Language Discovery, T1480.002 Execution Guardrails: Mutual Exclusion, T1497.002 Virtualization/Sandbox Evasion: User Activity Based Checks"] class stage1 malware stage2["<b>Stage 2</b> – Shellcode<br/><b>Techniques</b>: T1140 Deobfuscate/Decode Files (RC4), LZMA decompression"] class stage2 malware stage3["<b>Stage 3</b> – Downloader & C2<br/><b>Techniques</b>: T1102 Web Service, T1001.003 Protocol or Service Impersonation, T1001.002 Steganography, T1102.001 Dead Drop Resolver"] class stage3 malware c2_server["<b>C2</b> – HTTPS Server<br/>Custom headers and fake Useru2011Agent"] class c2_server c2 dll_payload["<b>Malware</b> – Dropped DLL<br/>Stored in %APPDATA%"] class dll_payload malware process_rundll32["<b>Process</b> – rundll32.exe<br/>Executes DLL via DllRegisterServer"] class process_rundll32 process task_schtasks["<b>Persistence</b> – Scheduled Task<br/>Runs rundll32 with the dropped DLL"] class task_schtasks persistence stage4["<b>Stage 4</b> – Persistence & Execution<br/><b>Techniques</b>: T1546.009 Event Triggered Execution: AppCert DLLs, T1027.003 Steganography, T1102.002 Bidirectional Communication"] class stage4 malware %% Connections initial_access –>|executes| process_msiexec process_msiexec –>|delivers| stage1 stage1 –>|generates| stage2 stage2 –>|downloads| stage3 stage3 –>|communicates with| c2_server c2_server –>|provides payload to| stage3 stage3 –>|writes DLL to| dll_payload dll_payload –>|used by| process_rundll32 process_rundll32 –>|triggered by| task_schtasks task_schtasks –>|scheduled from| stage4 "

Attack Flow

Simulation Execution

Prerequisite: The Telemetry & Baseline Pre‑flight Check must have passed.

Rationale: This section details the precise execution of the adversary technique (TTP) designed to trigger the detection rule. The commands and narrative MUST directly reflect the TTPs identified and aim to generate the exact telemetry expected by the detection logic. Abstract or unrelated examples will lead to misdiagnosis.

  • Attack Narrative & Commands:
    The adversary, having gained initial foothold on the endpoint, deploys the OysterLoader payload.

    1. DLL Registration via Rundll32 – The loader copies a malicious DLL (COPYING3.dll) into the temporary directory and registers it using rundll32.exe with the DllRegisterServer entry point, producing a command line that matches selection1.
    2. Anti‑Debug Check – To evade analysis, the payload loads ntdll.dll and calls IsDebuggerPresent. This generates a process record where Image contains ntdll.dll and the command line includes IsDebuggerPresent, satisfying selection2.
    3. Memory Allocation – For in‑memory execution, the loader invokes NtAllocateVirtualMemory via ntdll.dll. The resulting process creation event contains NtAllocateVirtualMemory in the command line, satisfying selection3.
  • Regression Test Script:

    # OysterLoader detection validation script – PowerShell
    # ----------------------------------------------------
    # 1. Create a dummy malicious DLL (empty file for simulation)
    $dllPath = "$env:TEMPCOPYING3.dll"
    New-Item -Path $dllPath -ItemType File -Force | Out-Null
    
    # 2. Trigger selection1 – rundll32 with DllRegisterServer
    Write-Host "Executing selection1 (rundll32 DLL registration)..."
    Start-Process -FilePath "rundll32.exe" -ArgumentList "`"$dllPath`" DllRegisterServer" -NoNewWindow
    
    # 3. Trigger selection2 – ntdll with IsDebuggerPresent
    Write-Host "Executing selection2 (IsDebuggerPresent)..."
    $scriptBlock = {
        Add-Type -MemberDefinition @"
            [DllImport("ntdll.dll", SetLastError = true)]
            public static extern bool IsDebuggerPresent();
    "@ -Namespace WinAPI -Name NativeMethods
        [WinAPI.NativeMethods]::IsDebuggerPresent() | Out-Null
    }
    Start-Job -ScriptBlock $scriptBlock | Wait-Job | Receive-Job
    
    # 4. Trigger selection3 – ntdll with NtAllocateVirtualMemory
    Write-Host "Executing selection3 (NtAllocateVirtualMemory)..."
    $scriptBlock2 = {
        Add-Type -MemberDefinition @"
            [DllImport("ntdll.dll", SetLastError = true)]
            public static extern int NtAllocateVirtualMemory(
                IntPtr ProcessHandle,
                ref IntPtr BaseAddress,
                IntPtr ZeroBits,
                ref UIntPtr RegionSize,
                uint AllocationType,
                uint Protect);
    "@ -Namespace WinAPI -Name NativeMethods
        $process = [System.Diagnostics.Process]::GetCurrentProcess()
        $handle = $process.Handle
        $base = [IntPtr]::Zero
        $size = [UIntPtr]::Zero
        [WinAPI.NativeMethods]::NtAllocateVirtualMemory($handle, [ref]$base, [IntPtr]::Zero, [ref]$size, 0x1000, 0x04) | Out-Null
    }
    Start-Job -ScriptBlock $scriptBlock2 | Wait-Job | Receive-Job
    
    # Cleanup
    Remove-Item -Path $dllPath -Force
    Write-Host "Simulation completed."
  • Cleanup Commands:

    # Ensure any lingering rundll32 or job processes are terminated
    Get-Process -Name "rundll32" -ErrorAction SilentlyContinue | Stop-Process -Force
    Get-Job | Remove-Job -Force
    # Delete temporary DLL if still present
    $tempDll = "$env:TEMPCOPYING3.dll"
    if (Test-Path $tempDll) { Remove-Item $tempDll -Force }