Analyse de Phantom Stealer : Plongée dans une chaîne d’attaque à deux niveaux
Detection stack
- AIDR
- Alert
- ETL
- Query
Résumé
Phantom Stealer est un infostealer Windows en deux étapes qui commence par un pdh.dll chargeur malveillant et se termine par une charge utile .NET injectée dans jsc.exe. Le chargeur utilise le détournement de DLL, le creusement de processus et la compilation AOT native pour réduire les risques de détection. Une fois actif, la charge utile de seconde étape vole les identifiants, les données du navigateur, les informations du portefeuille de cryptomonnaie, le contenu du presse-papiers, et d’autres données sensibles, elle peut également remplacer les adresses de portefeuille copiées par des valeurs contrôlées par l’attaquant. Le malware est commercialisé comme une offre de crimeware et est actuellement utilisé dans des attaques actives.
Investigation
Les chercheurs ont découvert que le chargeur se copie dans %APPDATA%MicrosoftRasManagementMpDlpService.exe et crée une clé Run pour maintenir la persistance. Il décrypte ensuite une charge utile doublement chiffrée en RC4, l’injecte dans un jsc.exe processus suspendu et effectue plusieurs vérifications anti-analyse avant de commencer le vol de données. Le voleur interne en .NET peut contourner le chiffrement lié aux applications de Chrome 127+ et exfiltre les informations volées via SMTP en utilisant un domaine usurpé. Des threads distincts gèrent les fonctions de découpe de crypto et de keylogging.
Atténuation
Les défenseurs doivent surveiller les pdh.dll chargements inattendus de chemins non système et appliquer des contrôles qui réduisent le risque de détournement de DLL. Les équipes de sécurité devraient également détecter les exécutables inconnus placés dans %APPDATA%MicrosoftRasManagement et surveiller la clé Run de RasManSvc. Les détections basées sur le comportement doivent se concentrer sur le creusement de processus impliquant Run key. Behavior-based detections should focus on process hollowing involving jsc.exe, tandis que la surveillance du réseau doit signaler les connexions suspectes aux domaines de commandement et de contrôle identifiés. Un renforcement supplémentaire de la sécurité du stockage des identifiants dans le navigateur et des contrôles plus stricts sur l’accès au presse-papiers pour les applications non fiables peuvent réduire encore plus l’exposition.
Réponse
Alerter sur la création de MpDlpService.exe dans le répertoire RasManagement et sur les modifications de la clé de registre Run associée. Enquêter sur tout jsc.exe processus présentant des signes de code injecté et mettre fin immédiatement à l’activité malveillante. Collectez les indicateurs de compromis pertinents, mettez en quarantaine les fichiers associés et effectuez une analyse légale pour déterminer quels identifiants et données de portefeuille pourraient avoir été exposés. Réinitialisez les comptes impactés et informez les utilisateurs concernés si nécessaire.
Flux d’attaque
Detections
Possible Persistence Points [ASEPs – Software/NTUSER Hive] (via registry_event)
View
Unusual Change Code Page Execution (via cmdline)
View
Possible Wifi Password Discovery (via cmdline)
View
IOCs (HashSha256) to detect: Phantom Stealer Analysis: Inside the Two-Layer Attack Chain Hidden Behind a Windows DLL
View
IOCs (HashMd5) to detect: Phantom Stealer Analysis: Inside the Two-Layer Attack Chain Hidden Behind a Windows DLL
View
Registry Persistence via RasManSvc Run Key [Windows Registry Event]
View
Process Hollowing into jsc.exe and Persistence via MpDlpService.exe [Windows Process Creation]
View
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 directly reflect the TTPs identified and aim to generate the exact telemetry expected by the detection logic.
-
Attack Narrative & Commands:
An adversary first steals a malicious payload (e.g., a reverse shell DLL) and stores it in the user’s%APPDATA%directory. Usingjsc.exeas a hollowing host, the attacker creates a new process, injects the payload, and resumes execution—fulfilling T1055.012 and T1055.003.
To ensure persistence, the attacker copies the malicious DLL to%APPDATA%MicrosoftRasManagementMpDlpService.exeand registers it as a service that runs at logon, abusing the legitimate service name (T1620). -
Regression Test Script:
# --------------------------------------------------------- # Simulated adversary script – Process Hollowing + Persistence # --------------------------------------------------------- # Variables $appData = "$env:APPDATAMicrosoftRasManagement" $loaderPath = Join-Path $appData "MpDlpService.exe" $maliciousDll = "$env:TMPmalicious.dll" # placeholder for payload # 1. Prepare persistence directory New-Item -Path $appData -ItemType Directory -Force | Out-Null # 2. Drop a dummy malicious DLL (simulated payload) # In a real attack this would be a compiled payload; here we create a zero‑byte file. New-Item -Path $maliciousDll -ItemType File -Force | Out-Null # 3. Copy the DLL to the spoofed service location Copy-Item -Path $maliciousDll -Destination $loaderPath -Force # 4. Register a temporary service pointing to the copied file (requires admin) $svcName = "MpDlpService" sc.exe create $svcName binPath= "`"$loaderPath`"" DisplayName= "Microsoft Ras Management Service" start= auto | Out-Null # 5. Start the service (triggers execution of MpDlpService.exe) sc.exe start $svcName | Out-Null # 6. Perform process hollowing using jsc.exe as the host # We will launch jsc.exe suspended, replace its memory with the dummy payload, # then resume. This uses the Invoke-ProcessHollowing function from PowerSploit. function Invoke-ProcessHollowing { param( [string]$HostPath, [string]$PayloadPath ) # Load .NET APIs Add-Type @" using System; using System.Diagnostics; using System.Runtime.InteropServices; public class Hollow { [DllImport("kernel32.dll")] public static extern bool CreateProcess(string appName, string cmdLine, IntPtr procSec, IntPtr threadSec, bool inherit, uint flags, IntPtr env, string cwd, ref STARTUPINFO si, out PROCESS_INFORMATION pi); [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO { public int 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 short wShowWindow; public short 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; } "@ # Create process suspended $si = New-Object Hollow+STARTUPINFO $pi = New-Object Hollow+PROCESS_INFORMATION $si.cb = [Runtime.InteropServices.Marshal]::SizeOf($si) $CREATE_SUSPENDED = 0x00000004 $ok = [Hollow]::CreateProcess($null, "`"$HostPath`"", [IntPtr]::Zero, [IntPtr]::Zero, $false, $CREATE_SUSPENDED, [IntPtr]::Zero, $null, [ref]$si, [ref]$pi) if (-not $ok) { Write-Error "Failed to create suspended process" ; return } # (Payload injection steps omitted – placeholder for real technique) # Resume thread $RESUME_THREAD = 0x00000001 [System.Runtime.InteropServices.Marshal]::WriteInt32($pi.hThread, 0, $RESUME_THREAD) | Out-Null } # Execute hollowing (using the real jsc.exe as host) $jscPath = "$env:SystemRootSystem32jsc.exe" Invoke-ProcessHollowing -HostPath $jscPath -PayloadPath $maliciousDll # --------------------------------------------------------- # End of simulation # --------------------------------------------------------- -
Cleanup Commands:
# Stop and delete temporary service sc.exe stop MpDlpService | Out-Null sc.exe delete MpDlpService | Out-Null # Remove loader and dummy payload Remove-Item -Path "$env:APPDATAMicrosoftRasManagementMpDlpService.exe" -Force -ErrorAction SilentlyContinue Remove-Item -Path "$env:TMPmalicious.dll" -Force -ErrorAction SilentlyContinue # Optional: kill any lingering jsc.exe processes started by the test Get-Process -Name jsc -ErrorAction SilentlyContinue | Stop-Process -Force