Intro

Hoy vamos a hacer algo diferente, vamos a hacer un keygen con la propia víctima. El término anglosajón para esto es «selfkeygening» y no es que esté muy bien visto por los reversers pero a veces nos puede sacar de apuros.

La víctima elegida es el Crackme 2 de LaFarge. Está hecho en ensamblador.

Injerto Light

Primeramente vamos a realizar un injerto light, con esto quiero decir que vamos a mostrar el serial bueno en la MessageBox de error.

Abrimos Olly y localizamos el código de comprobación del serial, tenemos suerte ya que el serial se muestra completamente y no se comprueba byte a byte ni cosas raras. En la imagen inferior os muestro el serial bueno para el nombre deurus y el mensaje de error. Como podeis observar el serial bueno se saca de memoria con la instrucción PUSH 406749 y el mensaje de error con PUSH 406306.

parche01

Si cambiamos el PUSH del serial por el de el mensaje de error ya lo tendriámos. Nos situamos encima del PUSH 406306 y pulsamos espacio, nos saldrá un diálogo con el push, lo modificamos y le damos a Assemble.

10-09-2014 20-37-18

Ahora el crackme cada vez que le demos a Check it! nos mostrará:

nagserial

Keygen a partir de la víctima

Pero no nos vamos a quedar ahí. Lo interesante sería que el serial bueno lo mostrara en la caja de texto del serial. Esto lo vamos a hacer con la función user32.SetDlgItemTextA.

setdlgitemtext

Según dice la función necesitamos el handle de la ventana, el ID de la caja de texto y el string a mostrar. La primera y segunda la obtenemos fijándonos en la función GetDlgItemTextA que recoje el serial introducido por nosotros. La string es el PUSH 406749.

handleandid

Con esto ya tenemos todo lo que necesitamos excepto el espacio dentro del código, en este caso lo lógico es parchear las MessageBox de error y acierto. Las seleccionamos, click derecho y Edit > Fill with NOPs.

10-09-2014 20-39-24

nopeamos

Ahora escribimos el injerto.

injertokeygen

Finalmente con Resource Hack cambiamos el aspecto del programa para que quede más profesional y listo. Tenemos pendiente hacer el keygen puro y duro, venga agur.

10-09-2014 21-04-52

Links


Introducción Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie
Warning: This challenge is still active and therefore should not be resolved using this information. Aviso: Este reto sigue en
Intro Hoy vamos a hacer algo diferente, vamos a hacer un keygen con la propia víctima. El término anglosajón para
Los retos de criptografía pueden ser muy variados como he dicho anteriormente. El secreto suele estar en saber a que

Introducción

Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie asociado a un nombre la comprobación se realiza mediante checkboxes con una matriz de 7×3. El CrackMe está realizado en Visual C++ lo que facilita en parte encontrar rápidamente la rutina de comprobación.

Comprobación

004013C5   > /8B7424 10     MOV     ESI,[DWORD SS:ESP+10]						;
004013C9   . |33FF          XOR     EDI,EDI
004013CB   > |8B86 74304000 MOV     EAX,[DWORD DS:ESI+403074]                   ;
004013D1   . |8BCB          MOV     ECX,EBX
004013D3   . |50            PUSH    EAX
004013D4   . |E8 6F020000   CALL    <JMP.&MFC42.#3092_CWnd::GetDlgItem>			; Lee el estado del checkbox
004013D9   . |8B48 20       MOV     ECX,[DWORD DS:EAX+20]
004013DC   . |6A 00         PUSH    0
004013DE   . |6A 00         PUSH    0
004013E0   . |68 F0000000   PUSH    0F0
004013E5   . |51            PUSH    ECX                                         ; 
004013E6   . |FFD5          CALL    NEAR EBP
004013E8   . |3B86 20304000 CMP     EAX,[DWORD DS:ESI+403020]					; Comprueba el estado del checkbox (1 activado 0 desactivado)
004013EE   . |75 20         JNZ     SHORT Matrix_C.00401410						; Salto a chico malo
004013F0   . |47            INC     EDI											; Incrementa contador
004013F1   . |83C6 04       ADD     ESI,4
004013F4   . |83FF 07       CMP     EDI,7										; ¿Hemos terminado de leer las columnas? ¿contador = 7?
004013F7   .^|7C D2         JL      SHORT Matrix_C.004013CB                     ; si terminan las columnas deja pasar
004013F9   . |8B4424 10     MOV     EAX,[DWORD SS:ESP+10]
004013FD   . |83C0 1C       ADD     EAX,1C										; contador de filas
00401400   . |83F8 54       CMP     EAX,54										; 3 filas = 1C+1C+1C=54
00401403   . |894424 10     MOV     [DWORD SS:ESP+10],EAX
00401407   .^\7C BC         JL      SHORT Matrix_C.004013C5						; ¿Hemos terminado de leer la fila? ¿contador = 54?
00401409   .  68 D8304000   PUSH    Matrix_C.004030D8                           ;  ASCII "Registration successful!"
0040140E   .  EB 05         JMP     SHORT Matrix_C.00401415
00401410   >  68 C8304000   PUSH    Matrix_C.004030C8                           ;  ASCII "Not registered!"

En la rutina de comprobación se ve fácil un CMP EDI,7 por lo que podemos deducir que si el creador no se ha molestado mucho la comprobación se realiza de izquierda a derecha y de arriba hacia abajo.

Orden de comprobación

Tal es así que si ponemos un breakpoint en 4013E8, podemos ir sacando el estado correcto de los checkboxes sin mucha molestia.

Resultado final

Enlaces

Warning: This challenge is still active and therefore should not be resolved using this information.
Aviso: Este reto sigue en activo y por lo tanto no se debería resolver utilizando esta información.

Introducción

Realistic Challenge 5: There is a new company out called NullCo. Have a look around the site and see what you can do.
Hay una nueva compañia llamada NullCo. Echa un vistazo a la web haber que puedes hacer.

Analizando a la víctima

Echamos un vistazo a la web y lo único interesante que vemos es un buscador.

Miramos el código fuente y vemos una ruta interesante.

  Si exploramos la ruta «http://www.thisislegal.com/nc/adm/» nos aparece un login. Metemos cualquier cosa y el mensaje de error da demasiada información.

Ahora fijémonos en el menú productos. Pinchamos sobre cualquier producto y a continuación en la imagen para ampliarla, veremos el siguiente enlace.

http://www.thisislegal.com/nc/i.php?img=images/serve

 Explotando la víctima

Vamos a ver si podemos explotar «i.php«. Probamos a obtener información sensible del servidor.

Probamos «http://www.thisislegal.com/nc/i.php?img=adm/login.pwd» y nos da error, seguramente por que está anexionando la extensión de la imagen, es decir, el script está interpretando esto:

http://www.thisislegal.com/nc/i.php?img=adm/login.pwd.png

Vamos a anularlo con un caracter nulo. Probamos y ahora si.

El password está en base64. Lo decodificamos online, nos logueamos y reto superado.

Links

Intro

Hoy vamos a hacer algo diferente, vamos a hacer un keygen con la propia víctima. El término anglosajón para esto es «selfkeygening» y no es que esté muy bien visto por los reversers pero a veces nos puede sacar de apuros.

La víctima elegida es el Crackme 2 de LaFarge. Está hecho en ensamblador.

Injerto Light

Primeramente vamos a realizar un injerto light, con esto quiero decir que vamos a mostrar el serial bueno en la MessageBox de error.

Abrimos Olly y localizamos el código de comprobación del serial, tenemos suerte ya que el serial se muestra completamente y no se comprueba byte a byte ni cosas raras. En la imagen inferior os muestro el serial bueno para el nombre deurus y el mensaje de error. Como podeis observar el serial bueno se saca de memoria con la instrucción PUSH 406749 y el mensaje de error con PUSH 406306.

parche01

Si cambiamos el PUSH del serial por el de el mensaje de error ya lo tendriámos. Nos situamos encima del PUSH 406306 y pulsamos espacio, nos saldrá un diálogo con el push, lo modificamos y le damos a Assemble.

10-09-2014 20-37-18

Ahora el crackme cada vez que le demos a Check it! nos mostrará:

nagserial

Keygen a partir de la víctima

Pero no nos vamos a quedar ahí. Lo interesante sería que el serial bueno lo mostrara en la caja de texto del serial. Esto lo vamos a hacer con la función user32.SetDlgItemTextA.

setdlgitemtext

Según dice la función necesitamos el handle de la ventana, el ID de la caja de texto y el string a mostrar. La primera y segunda la obtenemos fijándonos en la función GetDlgItemTextA que recoje el serial introducido por nosotros. La string es el PUSH 406749.

handleandid

Con esto ya tenemos todo lo que necesitamos excepto el espacio dentro del código, en este caso lo lógico es parchear las MessageBox de error y acierto. Las seleccionamos, click derecho y Edit > Fill with NOPs.

10-09-2014 20-39-24

nopeamos

Ahora escribimos el injerto.

injertokeygen

Finalmente con Resource Hack cambiamos el aspecto del programa para que quede más profesional y listo. Tenemos pendiente hacer el keygen puro y duro, venga agur.

10-09-2014 21-04-52

Links


Introducción Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie
Introducción Javascript 1 (Serial a la vista) Javascript 2 (La función charAt()) Javascript 3 (Input) Javascript 4 (Fuerza bruta manual) Javascript
Hace poco me puse a leer El oscuro pasajero de Jeff Lindsay, novela que inspiró la serie Dexter. La nostalgia
En una entrada anterior sobre cómo Expediente X abordó la tecnología de vanguardia, comenté que dedicaría un espacio a esos

Introducción

Aquí tenemos un CrackMe diferente a lo que estamos acostumbrados, ya que en vez del típico número de serie asociado a un nombre la comprobación se realiza mediante checkboxes con una matriz de 7×3. El CrackMe está realizado en Visual C++ lo que facilita en parte encontrar rápidamente la rutina de comprobación.

Comprobación

004013C5   > /8B7424 10     MOV     ESI,[DWORD SS:ESP+10]						;
004013C9   . |33FF          XOR     EDI,EDI
004013CB   > |8B86 74304000 MOV     EAX,[DWORD DS:ESI+403074]                   ;
004013D1   . |8BCB          MOV     ECX,EBX
004013D3   . |50            PUSH    EAX
004013D4   . |E8 6F020000   CALL    <JMP.&MFC42.#3092_CWnd::GetDlgItem>			; Lee el estado del checkbox
004013D9   . |8B48 20       MOV     ECX,[DWORD DS:EAX+20]
004013DC   . |6A 00         PUSH    0
004013DE   . |6A 00         PUSH    0
004013E0   . |68 F0000000   PUSH    0F0
004013E5   . |51            PUSH    ECX                                         ; 
004013E6   . |FFD5          CALL    NEAR EBP
004013E8   . |3B86 20304000 CMP     EAX,[DWORD DS:ESI+403020]					; Comprueba el estado del checkbox (1 activado 0 desactivado)
004013EE   . |75 20         JNZ     SHORT Matrix_C.00401410						; Salto a chico malo
004013F0   . |47            INC     EDI											; Incrementa contador
004013F1   . |83C6 04       ADD     ESI,4
004013F4   . |83FF 07       CMP     EDI,7										; ¿Hemos terminado de leer las columnas? ¿contador = 7?
004013F7   .^|7C D2         JL      SHORT Matrix_C.004013CB                     ; si terminan las columnas deja pasar
004013F9   . |8B4424 10     MOV     EAX,[DWORD SS:ESP+10]
004013FD   . |83C0 1C       ADD     EAX,1C										; contador de filas
00401400   . |83F8 54       CMP     EAX,54										; 3 filas = 1C+1C+1C=54
00401403   . |894424 10     MOV     [DWORD SS:ESP+10],EAX
00401407   .^\7C BC         JL      SHORT Matrix_C.004013C5						; ¿Hemos terminado de leer la fila? ¿contador = 54?
00401409   .  68 D8304000   PUSH    Matrix_C.004030D8                           ;  ASCII "Registration successful!"
0040140E   .  EB 05         JMP     SHORT Matrix_C.00401415
00401410   >  68 C8304000   PUSH    Matrix_C.004030C8                           ;  ASCII "Not registered!"

En la rutina de comprobación se ve fácil un CMP EDI,7 por lo que podemos deducir que si el creador no se ha molestado mucho la comprobación se realiza de izquierda a derecha y de arriba hacia abajo.

Orden de comprobación

Tal es así que si ponemos un breakpoint en 4013E8, podemos ir sacando el estado correcto de los checkboxes sin mucha molestia.

Resultado final

Enlaces

Introducción

Los retos de Javascript son los retos más sencillos que podemos encontrar. Muchas veces solamente mirando el código fuente obtenemos la respuesta. Suponen una mala implementación de seguridad debido a que el código se ejecuta del lado del cliente, por lo que el código fuente es accesible y por lo tanto, javascript no garantiza seguridad alguna. En estos cinco casos haremos un recorrido por lo más básico, cinco retos fáciles de superar y que nos proporcionan los conocimientos base para Javascript. Dicho esto os puedo asegurar que en ocasiones he encontrado retos javascript realmente complicados que requieren de horas descifrarlos y en los que es fácil tirar la toalla.

Cuando el reto lo requiera, es buena idea utilizar un compilador online para obtener de forma rápida el valor de una variable o realizar una prueba concreta. Yo utilizo Jsfiddle para realizar pruebas pero existen muchos más.

Javascript 1

Este primer reto es lo básico, en el código fuente se pueden apreciar directamente el usuario y la clave.

<script language=JavaScript>
function Verify(name,pass)
{
if (name=="admin" & pass=="3***3")
	{
	location.href = name + pass + '.htm';
	}
else 
	{
	alert("Si ya fallamos el primero...");
	};
}
</script>

Javascript 2

Este segundo reto es bastante sencillo pero ya te obliga a conocer la función charAt() de Javascript. Dicha función lo que hace es coger el caracter indicado mediante un índice que comienza en cero. Por ejemplo si nombre = deurus y hacemos letra = nombre.charAt(3), estariámos extrayendo la cuarta letra, es decir, la letra r de la variable nombre.

function Verify(name,pass)
{
var name1 = "CrawlinG", pass1 = "capriccio"
	if (name==name1 & pass==pass1)
	{
	location.href = name + ".htm";
	}
else 
	{
	var x =  name1.charAt(7) + pass1.charAt(3)+ name1.charAt(2) + pass1.charAt(5) +  name1.charAt(5) + pass1.charAt(1);x = x.toLowerCase();
	var y =  name.charAt(3) + name.charAt(1) + pass.charAt(1)+ pass.charAt(6) +  pass.charAt(7) + name.charAt(2);var x1 = "des" + y;
	if (x==y){location.href = x1 + ".htm"}else{alert("Esto no va bien");location.href = "js2.htm"}
	}
}

Lo interesante está en la formación de las variables x e y. La variable x se forma de las variables name1 y pass1, formando la palabra gracia. Por otro lado, la variable y se forma con el nombre y clave que introduzcamos nosotros. Vemos que la variable x e y deben ser iguales, por lo tanto debemos construir un nombre (name) y una clave (pass) que cumpla con lo siguiente:

  • 4ª letra del nombre = 1ª letra de la palabra «gracia»
  • 2ª letra del nombre = 2ª letra de la palabra «gracia»
  • 2ª letra de la clave = 3ª letra de la palabra «gracia»
  • 7ª letra de la clave = 4ª letra de la palabra «gracia»
  • 8ª letra de la clave = 5ª letra de la palabra «graci
  • 3ª letra del nombre = 6ª letra de la palabra «gracia«

Como véis simplemente se trata de interpretar correctamente la función charAt() y de fijarse bien en los nombres de las variables.

Javascript 3

Este reto nos muestra diálogo donde nos pide la contraseña para validar el reto. Al fallar  o cancelar vuelve al índice para no dejarnos ver el código fuente. Aquí se pueden seguir varios caminos como bloquear el uso de javascript en el navegador o instalar un plugin en chrome o firefox para habilitar/deshabilitar de forma rápida el uso de javascript.

Una vez deshabilitado javascript vemos lo siguiente:

<script language="JavaScript" src="js3.gif" type=text/javascript>
<!--
function verify()
{
var pass="thebest";
var password=prompt("Introduce el password para superar el nivel","");
	if (password==pass)
		{
		location.href = pass + ".htm";
		}
	else
		{
		alert("No vamos bien...");
		location.href = "index.htm";
		}
}
//-->
</script>

Aquí el truco es darse cuenta que el código que se está ejecutando esta en «js3.gif» y no el código que nos muestra como válida la clave thebest. Si descargamos el archivo js3.gif y lo abrimos con un archivo de texto vemos nuestra querida clave.

function verify()
{
var pass="mo****ver";
var password=prompt("Introduce el password para superar el nivel","");
	if (password==pass)
		{
		location.href = pass + ".htm";
		}
	else
		{
		alert("No vamos bien...");
		location.href = "index.htm";
		}
}

Javascript 4

En este reto ya entramos con que la clave no es reversible y la debemos obtener por fuerza bruta. En este reto utiliza una nueva función como charCodeAt() que lo que hace es obtener el valor ascii del caracter indicado.

function Verify(pass1)
{
var cont1= 2, cont2= 6
var suma1 = 0, suma2 = 0
var pass2 = "FDRLF"
for(i = 0; i < pass1.length; i++) 
{
suma1 += (pass1.charCodeAt(i) * cont1);
cont1++
}
for(i = 0; i < pass2.length; i++) 
{
suma2 += (pass2.charCodeAt(i) * cont2);
cont2++
}
if (suma1==suma2)
{
window.location=suma1+".htm";
}
else
{
alert ("Algo no va bien...");
}
}

Vemos dos bucles en los que se calculan sendos valores suma que finalmente se comparan. la variable suma1 se calcula mediante nuestro password y la variable suma2 la obtiene de la palabra «FDRLF». Con el script que os muestro a continuación obtenemos que usando como clave deurus, suma1 = 3048 y suma2 = 2936. Nuestro punto de referencia es suma2 = 2936, de modo que vamos alterando con paciencia la variable pass1 obteniendo valores cercanos a 2936. Por ejemplo «deurua» nos da suma1 = 2922, un valor bastante cercano.

var pass1 = "deurus";
var cont1= 2, cont2= 6
var suma1 = 0, suma2 = 0
var pass2 = "FDRLF"
for(i = 0; i < pass1.length; i++) 
{
suma1 += (pass1.charCodeAt(i) * cont1);
cont1++
}
for(i = 0; i < pass2.length; i++) 
{
suma2 += (pass2.charCodeAt(i) * cont2);
cont2++
}
alert (suma1);
alert (suma2);

La solución a este reto es múltiple. Dos claves válidas son por ejemplo dfurqfzwfabz.

Javascript 5

Este último reto es similar al anterior pero ya nos obliga a crearnos una pequeña herramienta que nos busque el serial válido.

function Verify(pass)
{
var suma=0
var cadena = "abcdefghijklmnopqrstuvwxyz"
for (var i = 0; i < pass.length; i++) 
	{
	var letra = pass.charAt(i)
	var valor = (cadena.indexOf(letra))
	valor++
	suma *= 26
	suma += valor
	}
if (suma==6030912063)
	{
	window.location=pass+".htm";
	}
else
	{
	alert ("Algo no va bien...");
	}
}

Para esta ocasión utiliza una nueva función llamada indexOf() que lo que hace es devolver un número entero que representa la posición en la que se encuentra el parámetro pasado a la función. Por ejemplo, si tengo variable = deurus y realizo posición = variable.indexOf(«s»), obtengo como resultado 5 (se empieza a contar desde cero).

Las operaciones que realiza el bucle son las siguientes:

  • Coge las letras del nombre una a una.
  • valor = posición de nuestra letra dentro de la variable de texto llamada cadena.
  • valor = valor + 1.
  • Multiplica la variable suma por 26.
  • Suma = suma + valor.

Aunque el proceso de recuperación de esta clave es algo más largo, podemos acortarlo introduciendo una clave de inicio de fuerza bruta próxima al objetivo. Al ser una función bastante lineal podemos rápidamente mediante pruebas con nuestro código de fuerza bruta o con un compilador online, establecer que la clave tendrá 7 caracteres e incluso que para ahorrar tiempo podemos aproximar la clave para que su valor suma esté cercano al valor suma buscado 6030912063.

Realizando pruebas obtenemos:

  • Clave = aaaaaaa -> suma = 321272407
  • Clave = zzzzzzz -> suma = 8353082582
  • Clave = smaaaaa -> suma = 6024332887
  • Clave = smkkkkk -> suma = 6029085437

Como vemos, la clave smkkkkk ya está bastante próxima al objetivo y será un buen punto para lanzar la fuerza bruta.

Os dejo el código de fuerza bruta en .Net

Module Module1
    Sub Main()
inicio:
        Console.WriteLine("-------------------------")
        Console.WriteLine("Modo [1] Prueba password")
        Console.WriteLine("Modo [2] Fuerza bruta")
        Console.WriteLine("-------------------------")
        Dim modo = Console.ReadLine()
        '
        If modo = 2 Then
            Console.WriteLine("¿Password para comenzar?")
            Dim pass = Console.ReadLine()
inicio2:
            Dim cadena As String = "abcdefghijklmnopqrstuvwxyz"
            Dim valor As Integer = 0
            Dim suma As Long = 0
            Dim letra As String
            For i = 0 To pass.Length - 1
                letra = Mid(pass, i + 1, 1)
                valor = cadena.IndexOf(letra)
                valor += 1
                suma *= 26
                suma += valor
            Next
            Console.WriteLine("Password: " & pass & " - Sum: " & suma.ToString)
            pass = IncrementString(pass)
            If suma = 6030912063 Then
                MsgBox("Password is " & pass)
            Else
                If pass = "aaaaaaaa" Then
                    Console.WriteLine("pass not found")
                    Console.ReadKey()
                Else
                    GoTo inicio2
                End If
            End If
        End If
        '------------------------------------------------
        If modo = 1 Then
            Console.WriteLine("Password:")
            Dim pass = Console.ReadLine()
            Dim cadena As String = "abcdefghijklmnopqrstuvwxyz"
            Dim valor As Integer = 0
            Dim suma As Long = 0
            Dim letra As String
            For i = 0 To pass.Length - 1
                letra = Mid(pass, i + 1, 1)
                valor = cadena.IndexOf(letra)
                valor += 1
                suma *= 26
                suma += valor
            Next
            Console.WriteLine("Password: " & pass & " - Sum: " & suma.ToString)
            Console.WriteLine(".......")
            Console.WriteLine("Good = 6030912063")
            Console.WriteLine("Suma = " & suma.ToString)
            Console.ReadKey()
            Console.Clear()
            GoTo inicio
        End If
    End Sub
    Function IncrementString(ByVal strString As String) As String
        '
        ' Increments a string counter
        ' e.g.  "a" -> "b"
        '       "az" -> "ba"
        '       "zzz" -> "aaaa"
        '
        ' strString is the string to increment, assumed to be lower-case alphabetic
        ' Return value is the incremented string
        '
        Dim lngLenString As Long
        Dim strChar As String
        Dim lngI As Long

        lngLenString = Len(strString)
        ' Start at far right
        For lngI = lngLenString To 0 Step -1
            ' If we reach the far left then add an A and exit
            If lngI = 0 Then
                strString = "a" & strString
                Exit For
            End If
            ' Consider next character
            strChar = Mid(strString, lngI, 1)
            If strChar = "z" Then
                ' If we find Z then increment this to A
                ' and increment the character after this (in next loop iteration)
                strString = Left$(strString, lngI - 1) & "a" & Mid(strString, lngI + 1, lngLenString)
            Else
                ' Increment this non-Z and exit
                strString = Left$(strString, lngI - 1) & Chr(Asc(strChar) + 1) & Mid(strString, lngI + 1, lngLenString)
                Exit For
            End If
        Next lngI
        IncrementString = strString
        Exit Function

    End Function
End Module

Enlaces

Hace poco me puse a leer El oscuro pasajero de Jeff Lindsay, novela que inspiró la serie Dexter. La nostalgia me invadió y al final decidí volver a ver la primera temporada que tanto me gustó hace unos años. Para mi sorpresa, muchos de los detalles que recordaba de la serie eran incorrectos o incompletos. Bueno, el caso es que en esta ocasión me he fijado más en los detalles y he descubierto una pequeña perla en el capítulo 8 de la primera temporada.

ALERTA DE SPOILER: Aunque la serie tiene unos añitos no quisiera fastidiarsela a nadie. Si continuas leyendo puede que te enteres de algo que no quieras.

Missed connection

En un momento dado, a Dexter se le ocurre la feliz idea de contactar con el asesino en serie que le está dejando regalitos y no se le ocurre mejor idea que hacerlo en una web de contactos cualquiera. La web en cuestión es www.miamilist12.com/miami/main y Dexter decide escribir un mensaje en el hilo missed connections. A continuación la secuencia de imágenes.

mailto:frozenbarbie@hotmail.???

La simple idea de escribir en un tablón, foro, lista, etc y esperar que el asesino en serie lo lea ya es una locura. Pero señor@s, esto es ficción, y por supuesto el asesino no solo ve el mensaje si no que responde a Dexter creando un pequeño error con las direcciones de email. Y es que cuando el asesino ve el mensaje se puede apreciar que la dirección de email de Dexter es frozenbarbie@hotmail.web y cuando el asesino le responde, se ve claramente que lo hace a la dirección frozenbarbie@hotmail.com. A continuación las imágenes.

Además me ha llamado la atención que aunque es evidente que el asesino usa Windows XP, se puede apreciar que han retocado en post-producción el botón de inicio para que quede oculto.

Nos vemos en el siguiente BTM.

En una entrada anterior sobre cómo Expediente X abordó la tecnología de vanguardia, comenté que dedicaría un espacio a esos tres personajes tan peculiares y entrañables que, desde el segundo plano, se ganaron un hueco en el corazón de los seguidores de la serie: los Pistoleros Solitarios. Pues bien, ha llegado el momento.

Estos tres tipos —John Fitzgerald Byers, Melvin Frohike y Richard “Ringo” Langly— no necesitaban armas ni placas del FBI. Su poder estaba en los teclados, los cables enredados y los monitores de tubo que parpadeaban en un sótano lleno de conspiraciones y café frío. Eran los outsiders de Expediente X, tres hackers con alma de periodistas que luchaban por algo tan simple y tan enorme como la verdad.

Su primera aparición fue en E.B.E. (temporada 1), casi como un alivio cómico: tres frikis que ayudaban a Mulder a rastrear información sobre ovnis. Pero pronto quedó claro que había algo especial en ellos. No solo eran fuente de datos, sino conciencia crítica en un mundo plagado de mentiras digitales y gobiernos con demasiados secretos. Con el tiempo se convirtieron en aliados imprescindibles de Mulder y Scully, y también en el reflejo más humano de lo que significa ser hacker: curiosos, testarudos, torpes a veces, pero con un sentido moral inquebrantable.

Byers era el idealista, el que aún creía en la decencia y en las instituciones (al menos en teoría). Frohike, el cínico veterano con corazón de oro, siempre dispuesto a arriesgarse por una buena causa… o por impresionar a Scully. Y Langly, el genio rebelde que parecía vivir en permanente conversación con su módem de 56 k. Juntos formaban un trío excéntrico, pero perfectamente equilibrado.

Mientras Mulder y Scully perseguían abducciones y virus extraterrestres, los pistoleros combatían en otra trinchera: la digital. Hackeaban redes gubernamentales, interceptaban comunicaciones cifradas y desmantelaban cortafuegos que, en los noventa, parecían pura ciencia ficción. Lo suyo no era la acción física, sino la resistencia informativa. Y aunque muchas veces eran el chiste del capítulo, también representaban algo muy real: la gente corriente que lucha contra el poder desde el conocimiento.

Su lema no declarado podría haber sido el clásico “la información quiere ser libre”, y en eso se mantuvieron firmes hasta el final. Si había que elegir entre la seguridad o la verdad, ellos siempre elegían la verdad, aunque les costara caro.

TemporadaEpisodioTítuloComentario
117E.B.E.Primera aparición de los pistoleros.
23BloodManipulación de dispositivos y mensajes ocultos. También control mental a través de la tecnología.
225AnasaziUn hacker roba archivos clasificados. Se tratan temas como el cifrado y filtración de datos del gobierno.
315ApocryphaAcceso a bases de datos secretas y descifrado de archivos comprometidos.
323WetwiredManipulación de señales televisivas.
414Memento MoriInfiltración digital en sistemas médicos y vigilancia biotecnológica.
51ReduxRobo y manipulación de pruebas digitales.
53Unusual SuspectsOrígenes de los pistoleros: intrusión, cifrado y espíritu hacker de los noventa.
511Kill SwitchIA autónoma y malware inteligente.
620Three of a KindHacking social, suplantación y síntesis de voz para infiltración corporativa.
713First Person ShooterHackeo de entornos virtuales y brechas de seguridad en sistemas de realidad aumentada.
915Jump the SharkSu sacrificio final: bloqueo de una amenaza biológica, ética hacker y altruismo extremo.
112ThisLangly como conciencia digital en un servidor. Debate sobre IA y trascendencia del código.

Morir por la verdad

El final de los pistoleros fue tan inesperado como heroico. En el episodio “Jump the Shark” de la novena temporada, descubren un complot bioterrorista que amenaza con liberar un virus mortal. No hay tiempo para avisar a nadie, ni margen para escapar. Así que, fieles a su estilo, deciden sacrificarse para salvar a otros. Sellan el laboratorio desde dentro, sabiendo que no volverán a salir.

Lo reconozco, este desenlace mi cogió completamente por sorpresa. No hay épica de Hollywood, ni música grandilocuente. Solo tres hombres anónimos haciendo lo correcto. Mueren juntos, sin reconocimiento, sin medallas, pero con la serenidad de quienes saben que su causa era justa. Y en ese silencio final, Expediente X nos recordó algo que las grandes historias suelen olvidar: que los verdaderos héroes a veces no llevan traje ni pistola, solo convicción.

Años después, Mulder vuelve a verlos —o cree verlos— en The Truth. Ya no están en este mundo, pero siguen a su lado, como fantasmas digitales de la conciencia hacker. Es un homenaje discreto a quienes siempre pelearon desde las sombras por liberar la verdad.

Para cerrar el círculo, Langly reaparece de forma inesperada en la temporada 11, dentro del episodio This. Su mente, o más bien su copia digital, sobrevive atrapada en un servidor, reclamando ser liberada. Es el epílogo perfecto: el hacker que muere físicamente, pero cuya conciencia sigue inmortal. Una vez más me volvió a sorprender Chris Carter con este homenaje.

Me gusta pensar que los pistoleros solitarios representaban algo más que tres hackers secundarios en una serie de los noventa. Fueron el reflejo de una época en la que creíamos que la tecnología podía liberar al ser humano, antes de que las redes sociales y la hiperconectividad lo diluyeran todo. Byers, Frohike y Langly no luchaban por fama ni por dinero: luchaban por entender el sistema para exponerlo, por esa curiosidad genuina que hoy apenas sobrevive entre líneas de código y algoritmos opacos. Quizá por eso seguimos recordándolos y mola tanto volver a ver los capítulos. Porque, de algún modo, todos los que amamos el conocimiento libre llevamos dentro un pequeño pistolero solitario, buscando la verdad entre los bits.