No es que Twitter se caracterice por su solidez —todos sus usuarios conocemos a nuestra vieja amiga la Twitter Whale—. Pero esta vez alguien (¿@judofyr?) ha estado haciendo unas pruebas contra la rutina que linkifica los mensajes y se ha dado cuenta de que estaba mal escrita. Así, en plan amiguete, todos reconocemos una dirección en la web como algo que empieza por las letras http://
, aunque no sepamos muy bien qué es eso. Pues bien: una dirección, o más formalmente un URI o identificador de recurso universal es algo que tiene un formato muy estricto, descrito en el estándar RFC2396 (Uniform Resource Identifiers: Generic Syntax). Un linkificador añade lo necesario para que http://www.example.com/
se transforme en http://www.example.com/
, siguiendo (en teoría, al menos) las reglas del estándar. El proceso de linkificado consiste en tomar el texto entre http:
y la última barra —ambos incluidos— y colocarlo dentro de algo así:
<a href="[TEXTO_DEL_ENLACE]">[TEXTO_DEL_ENLACE]</a>
… Sustituyendo donde dice [TEXTO_DEL_ENLACE]
. En la rutina usada por Twitter, el problema aparece en algo tan sencillo como el uso de un separador (en este caso, las comillas dobles) dentro de una dirección en un mensaje:
http://x.xx/@"[CÓDIGO_MALICIOSO]/
Cada usuario de Twitter al que le llegue un mensaje que contenga ese texto lo verá en la web como un enlace. El código que genera el linkificador y se sirve a los navegadores tiene esta apariencia:
<a href="http://x.xx/@"[CÓDIGO_MALICIOSO]/">http://x.xx/@"[CÓDIGO_MALICIOSO]/</a>
Aquí se ve claramente un problema. La comilla doble ha sido insertada tal cual en el código HTML de la página, y es interpretada por los navegadores como el final del argumento href
de una marca de enlace a
. La parte marcada como [CÓDIGO_MALICIOSO]
puede contener cualquier texto que quepa dentro del límite de 140 caracteres de Twitter, y si no contiene ningún carácter prohibido en el código HTML, será interpretado y ejecutado por el navegador sin más preguntas. En la primera versión del hack (todavía no era un ataque) se usaba el fallo para inyectar una directriz de estilo CSS:
style="background:#000;color:#000;
El efecto, gracioso, era que el enlace dentro del mensaje aparecía como un rectángulo negro, casi como en un rasca y gana. El siguiente paso, ya más peligroso, fue añadir un atributo onmouseover
. El atributo onmouseover
ejecuta su valor, una rutina en Javascript, cuando el puntero de ratón pasa por encima del contenido de la marca que lo lleva. Suele usarse, atentando contra el buen gusto, para iniciar animaciones al pasar con el ratón encima de algún elemento activo. Haber logrado inyectar un atributo onmouseover
en un enlace servido por Twitter tenía que provocar que algunos engranajes empezaran a girar en ciertas mentes.
El tercer paso consistió en aprovechar que Twitter utiliza, para sus efectos dinámicos en su web, la conocida biblioteca de funciones JQuery. Ésta permite a los desarrolladores producir un código muy conciso, abstraído de las diferentes implementaciones de Javascript de los distintos navegadores. La inyección de código escrito con llamadas a JQuery garantiza, a la vez, que la cadena de texto resultante será extremadamente corta (ideal para su difusión en Twitter) y que funcionará en todas las plataformas. A partir de este punto, ya fue sencillo añadir una función que pulsara automáticamente el botón Retwittear, garantizando la propagación inmediata del gusano.
Durante dos horas de media tarde en el huso centroeuropeo han circulado gran cantidad de variantes del virus. Las más peligrosas se dedicaban a inyectar en el código de la página referencias a otros scripts externos, y al menos en teoría se han podido robar contraseñas del servicio o aprovechar otras vulnerabilidades para instalar virus más tradicionales. Una de las más ingeniosas disponía un elemento invisible por encima de todos los demás de la página, ocupando toda su extensión y con un onmouseover
que ejecutaba más código. Así, ni siquiera era necesario pasar el ratón sobre los mensajes afectados para que se efectuara la propagación: bastaba con tener un mensaje infectado en el timeline.
Lo que ha ocurrido en Twitter ha sido un ataque XSS de manual. ¿Cómo ha podido llegar a suceder? Observemos el formato de los enlaces maliciosos: contienen una secuencia de un caracter reservado, la arroba @
y un delimitador prohibido, la comilla doble "
. Al parecer, el linkificador de Twitter fallaba (al menos) con esa secuencia de caracteres. El estándar RFC2396 antes citado, en su apartado 2.4, especifica qué hacer cuando se procesa una dirección que contiene caracteres potencialmente problemáticos: se codifican mediante secuencias de escape. Dicho de otro modo, cada caracter prohibido o problemático según el apartado 2.4.2 se sustituye por una secuencia especial que está compuesta por un caracter prohibido, el signo de porcentaje %
y dos dígitos en hexadecimal. Este proceso permite introducir en una dirección caracteres no permitidos a priori: habréis visto secuencias del tipo http%3A%2F%2F
, que es lo que aparece casi siempre que se embebe una dirección dentro de otra (significa http://
).
Pero (y ahora viene lo bueno) cualquier lenguaje de programación para la web incluye alguna función para codificar y decodificar cadenas de caracteres de acuerdo con la norma. Os haré una demo en Javascript aquí mismo:
Observaréis que si cortáis y pegáis el enlace que lo originó todo, los caracteres problemáticos aparecen codificados. Pero quizá los chicos de Twitter no se conformaron con la función elemental de su lenguaje (Ruby on Rails), sino que decidieron rehacerla por algún motivo. Hay que repetir la pregunta: ¿cómo ha podido llegar a suceder? Bueno, decía Larry Wall, el creador del famoso lenguaje de ordenador de sólo escritura Perl, que las tres virtudes cardinales de un programador han de ser:
Pereza, impaciencia y soberbia
¿Qué combinación de estos tres maravillosos elementos ha sobrado en Twitter?