Articles

Aprendiendo XSS con el Juego XSS de Google

Instrucciones paso a paso sobre cómo resolver el Juego XSS de Google

Foto de Markus Spiske temporausch.com from Pexels

XSS aka Cross Site Scripting es una de las vulnerabilidades del lado del cliente más peligrosas y uno de los métodos de caza de bugs que más gustan.

Google XSS Game es una plataforma de entrenamiento proporcionada por google para practicar XSS. Consta de 6 niveles y en cada uno de ellos tienes que ejecutar una alerta JavaScript para poder avanzar al siguiente nivel. En cada nivel, se le proporcionarán diferentes problemas y tendrá que ejecutar la alerta utilizando diferentes técnicas en cada nivel. Esto le ayudará a entender varios métodos que pueden ser utilizados para ejecutar XSS en una página web.

Así que vamos a empezar.

Navegue a https://xss-game.appspot.com. Aquí es donde está disponible el Juego XSS de Google.

Verás una página como esta

Pulsa el botón ¡Déjame! para entrar en el juego.

Primera tarea : Hola mundo de XSS

Tienes que inyectar el payload xss en el navegador virtual. Puedes ver el código fuente haciendo clic en el enlace «toggle». Si no puede inyectar, puede obtener las pistas haciendo clic en el enlace «mostrar».

Mientras revisa el código fuente, es un script de python y las 2 partes interesantes en la función
def get(self) son

self.response.headers.add_header("X-XSS-Protection", "0")

y

query = self.request.get('query', '')
message = "Sorry, no results were found for <b>" + query + "</b>."
message += " <a href='?'>Try again</a>."

La primera parte desactivará el auditor XSS de chrome y nos permitirá inyectar la carga útil XSS en el navegador.

La segunda parte muestra que el valor del parámetro url query se añade directamente al cuerpo. Ahí es donde tenemos que explotar.

Esto es sencillo y puedes intentar introducir cualquiera de los siguientes (e incluso hay más) en la caja de búsqueda y buscarlo

<a href="javascript:alert()">Link</a>

<img src=X onerror="alert()">

<script>alert()</script>

Y así sucesivamente. Si has utilizado el primero, tienes que hacer clic en el Enlace para ejecutar la alerta.

¡¡Genial!!! Has completado con éxito el nivel 1. Ahora verás un botón para avanzar al siguiente nivel.

Segunda tarea : La persistencia es la clave

En esta tarea, tienes que ejecutar la alerta añadiendo un post. En este juego, es DOM XSS, pero cuando se pruebe en aplicaciones reales de chat/comentarios, será un XSS almacenado.

Ok echemos un vistazo a la fuente y al mensaje anterior también.

Al inspeccionar la fuente, puedes ver que el mensaje por defecto utiliza diferentes tipos de etiquetas html para darle estilo. Esa es nuestra clave.

Revisa la fuente para confirmarlo. Así es como se renderiza nuestro post

Puedes ver que el post no pasa por ningún filtro. Así que podemos utilizar cualquiera de los métodos mencionados anteriormente.

<a href="javascript:alert()">Link</a>

<img src=X onerror="alert()">

Y así sucesivamente.

Felicidades. Has completado el nivel 2. Ahora avanza al siguiente nivel.

Tarea 3 : Esa sensación de hundimiento

Esta es muy diferente de las 2 que hemos completado. Aquí, tenemos que aprender sobre window.location.hash. Es la parte que viene después del símbolo # y se utiliza para la navegación en la página. Es una característica del navegador y funcionará incluso sin JavaScript.

Inspeccionemos el código fuente de éste.

La parte interesante en el código es

var html = "Image " + parseInt(num) + "<br>";
html += "<img src='https://medium.com/static/level3/cloud" + num + ".jpg' />";

num contiene el valor de window.location.hash y se utiliza en 2 lugares. En primer lugar, se utiliza dentro de la función parseInt por lo tanto nuestra carga útil no funcionará allí. Pero en la siguiente línea, se utilizan los datos en bruto. Ahí es donde vamos a inyectar nuestra carga útil.

Así que tenemos que cerrar una sola cuota ' allí y tenemos que inyectar nuestra carga útil.

Puedes probar cualquier payload dentro de ' ' Después de #

Intenta poner cualquiera de los siguientes después de # y visita la url.

1' onerror='alert()

1'><img src=X onerror="alert()">'

1'><script>alert()</script>'

1'><a href="javascript:alert()">Link</a>'
Y así sucesivamente.

Genial. Ahora podemos avanzar al siguiente nivel.

Tarea 4 : El contexto importa

Tenemos un espacio para introducir la duración del temporizador. Ahí es donde vamos a explotar.

Revisemos el código fuente.

En timer.html, podemos ver esta línea

<img src="https://medium.com/static/loading.gif" onload="startTimer('{{ timer }}');" />

Tenemos que explotar en la expresión {{ timer }} Pero está colocada dentro de una función startTimer(''); que es un manejador del evento onload. El punto principal a tener en cuenta es que el atributo de controlador de eventos en HTML aceptar múltiples funciones de devolución de llamada.

Así que tenemos que cerrar la función y ejecutar nuestra alerta allí. Tenga en cuenta que, el valor no pasó a través de una función parseInt en lugar de los datos en bruto se utiliza. Así que podemos cerrar la función añadiendo un '); y luego inyectar nuestro alert. Dado que se utiliza como inline, no podemos inyectar alert(); allí porque romperá las cosas. La declaración se convertirá en onload="startTimer('3'); alert();')" y no funcionará.

Así que tenemos que añadir un patrón que mantenga el patrón sin romper.
Añade alert(' y es suficiente.

Así que nuestro payload será

3');alert('

Pulsando el botón de inicio del temporizador se ejecutará la alerta y habremos terminado este nivel.

Avanzar a la siguiente tarea.

Tarea 5 : Breaking Protocol

En la página de inicio, no tenemos forma de inyectar nada. Todo lo que tenemos es un enlace. Así que vamos a hacer clic en él.

Aquí, podemos ver 2 lugares para inyectar nuestro payload. uno en la propia url y otro en el cuadro de entrada. El cuadro de entrada es un lugar para introducir el correo electrónico y esperar que no se refleje en otro lugar. Así que vamos a la primera. En la url.

Inspecciona el código fuente de la página actual, que es signup.html y podemos ver la línea

<a href="{{ next }}">Next >></a>

Gran lugar para inyectar un payload. Nuestro payload se establecerá como el valor del atributo href en una etiqueta a. Si somos capaces de añadir javascript:alert() podremos ejecutar nuestro payload. Ahora vamos a ver cuál es el valor de next. No encontramos ninguno en la página. ¿Dónde lo buscamos?

Código Python al rescate. Revisa level.py y veremos

if "signup" in self.request.path:
self.render_template('signup.html',
{'next': self.request.get('next')})

Así que se utilizará el valor de next en la url.

Cambia el valor de next en la url de confirm a javascript:alert() y la url final quedará como

Now clicking on Next >> in the page will trigger our payload.

We now completed level 5. And 1 level remains.

Task 6 : Follow the 🐇

There is a path to a js file in the url.

Let’s inspect the source code. In page index.html, you can see a function includeGadget y dentro del cuerpo de la función, puedes ver el siguiente código.

var scriptEl = document.createElement('script');

Así que podemos cargar archivo js externo pero no desde una url http o https.

Aquí, vamos a probar con las urls data.

Las urls de datos tienen la forma data:{type},content

Así que cambia el valor después de # a

data:application/javascript,alert()

o a

data:text/plain,alert() y podremos ejecutar el alert.

Aquí tienes un vídeo de resolución del Juego.