FRIKADAS: Ofuscación extrema de código JavaScript con JSFuck

12/04/2017
Artículo original

Lenguaje JSFuck

Hace unos meses os hablábamos aquí mismo de los lenguajes esotéricos. Estos lenguajes se caracterizan por ser súper-crípticos, es decir, incluso teniendo el código delante es casi imposible saber qué hacen. Uno de los más famosos es BrainFuck, que se caracteriza por utilizar tan solo unos pocos símbolos como el mayor (>), menor (<) la suma (+), etc...

Por ejemplo, este sería el "Hola Mundo" en BrainFuck:

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++
++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

Ininteligible, vamos.

Inspirándose en BrainFuck, el programador alemán Martin Kleppe (un frikazo de todo y lomo, y si no me crees échale un vistazo a su página personal) ha creado el lenguaje JSFuck.

JSFuck utiliza tan solo 6 caracteres, a saber: []()!+, pero lo más alucinante es que con ellos puedes crear cualquier programa JavaScript que funcionará en cualquier navegador moderno ?

Por ejemplo, este fragmento aparentemente sin sentido:

[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+
[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]
[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+
[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+
[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]
+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+
!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[
])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[
+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[
]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[
]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(
[![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(
!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+
[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+
!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]
]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]
]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]
+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(!
[]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![
]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

Produce una alerta por pantalla con el número 1, es decir, es equivalente a:

alert(1);

Vale, no es muy útil, y ocupa varias veces más que el código original, pero puedes convertir cualquier otro programa JavaScript a JSFuck y se ejecutará perfectamente, aunque la conversión es muuuy lenta.

Por cierto, en el transformador de pruebas que viene en la página no intentes poner nada más largo de unos pocos caracteres: te colgará el navegador.

Es decir, lo alucinante de esta tremenda "ida de olla" que es JSFuck es que no deja de ser código JavaScript que funciona en cualquier lado. No necesita un compilador especial: simplemente lo metes en una página y funciona.

Por ello, es posible utilizarlo para ofuscar de manera tremenda ciertos fragmentos de código JavaScript. Esto, que puede ser incluso útil en algunas aplicaciones lícitas, también es un problema si lo que se está insertando es código malicioso para hacer ataques de tipo XSS, por ejemplo, donde el código malicioso pasaría inadvertido para muchos analizadores que tratan de detectarlo.

¿Cómo funciona esto?

En cualquier caso es un experimento muy interesante. Las particularidades del lenguaje JavaScript hacen que expresiones sin sentido aparente como esta:

!+[]+!+[]

Realmente funcionen en cualquier compilador. ¿Sabes qué es ese fragmento?: pues nada menos que el número 2. La explicación viene de considerar por un lado las conversiones implícitas de tipos de datos que hace JavaScript al usar ciertos operadores matemáticos, y por otro la precedencia (orden de aplicación) de dichos operadores.

Así, por ejemplo, si intentamos sumar una matriz vacía a nada, o sea esto:

+[]

Obtendremos el número 0 ya que la matriz se convierte a un número para poder sumarla y al no tener un operando por la izquierda se considera que es 0. Así que lo anterior es equivalente a 0+0, que es 0.

Si además le añadimos un ! delante, es decir, lo negamos, entonces obtenemos un true (el contrario en booleano de un 0 (false) es true), y si repetimos la operación de la suma sin nada a la izquierda, lo convierte en el número equivalente (1) y por lo tanto obtenemos un 1, por lo que el 1 se escribe en JSFuck así:

+!+[]

Siguiendo esa lógica, para conseguir un 2 solo tenemos que sumarle otro 1, pero no tenemos que empezar de cero porque ya tenemos un 1 en la expresión anterior, así simplemente con conseguir otro 1 a la izquierda con !+[] ya es suficiente, y queda:

!+[]+!+[]

Que es lo que vimos antes, facilísimo ¿verdad? ?

Para obtener las diferentes letras del abecedario de manera ofuscada utilizan conversiones que dan palabras clave como undefined o NaN y luego las extraen con la sintaxis de elementos de matrices (o sea, corchetes), que también funciona para cadenas. Por ejemplo, se puede obtener un undefined con esta expresión:

[][[]]

Y se puede convertir en una cadena simplemente intentando concatenarla (con +) con algo que no se aun número, así que esta expresión:

[][[]]+[]

Resulta en la cadena "undefined".

Por lo que si ahora la rodeamos con un paréntesis para obtener el resultado y cogemos su primera letra, obtenemos la "u", así:

([][[]]+[])[0]

Con la segunda letra (posición 1) tendríamos la "n" y así sucesivamente.

Hacen esto mismo con el resto de letras posibles y otras palabras clave.

Bueno, pues con esto y unos cuantos trucos más del estilo al final es posible crear un código totalmente indescifrable que ejecute casi cualquier cosa en JavaScript.

En la página de GitHub del proyecto puedes ver el código fuente completo, pero también tiene una buena explicación de cada uno de los trucos que usa.

Más allá de una simple curiosidad y de la frikada, se trata de un proyecto muy interesante que muestra la flexibilidad que posee JavaScript (que es un arma de doble filo y que hace que muchos lo odien). Y nunca se sabe para qué podrías necesitar algo como esto ?