viernes, 29 de marzo de 2019

Arbitrary File Download: el hermano menor del LFI.

¡Hola, muy buenas!

En esta ocasión les vengo a comentar sobre una vulnerabilidad a nivel web bastante frecuente, y a su vez, poco conocida. Se denomina Arbitrary File Download, y de ahora en más, AFD.

(fig 1. Arbitrary File Download).
A menudo es una vulnerabilidad que se confunde con la ya conocida Local File Inclusion, o LFI. Estás perdonado si alguna vez las confundiste, pues las similitudes que tiene son casi todas, a excepción de la metodología de trabajo. En esta entrada, me dispongo a intentar solventar todas las dudas que pueda existir sobre la diferencia de ambas vulnerabilidades.

Apéndice I: El código en PHP

Para entender más claramente las diferencias, analizaremos los códigos PHP vulnerables utilizados en ambas vulnerabilidades.

  1. <?php
  2. include($_GET['page']);
  3. // Otras funciones: include_once(), require(), require_once().
  4. ?>
(Código 1. Local File Inclusion).

Es posible combinar LFI con técnicas como Log poisoning, /proc/self/environ, phpinfo(), etc. para conseguir RCE en el servidor.


  1. <?php
  2. $file = $_GET['file'];
  3. header('Content-Type: application/octet-stream');
  4. header('Content-Disposition: attachment; filename="' .basename($file) .'"');
  5. header('Content-Length: ' . filesize($file));
  6. readfile($file);
  7. ?>
(Código 2. Arbitrary File Download).

El uso de readfile() es utilizado a lo largo de muchas páginas web para las secciones de "descarga de contenido". Esto significa que un único archivo php (llámese download.php) es el encargado de descargar los ficheros del servidor.

Apéndice II: Post-análisis del código

Luego de analizar ambos códigos, llegamos a la conclusión de que LFI permite incluir ficheros locales del servidor, y en cambio, AFD permite descargar esos ficheros.
La gran diferencia entre ambas vulnerabilidades, es que AFD no permite obtener RCE mediante técnicas como log poisoning o /proc/self/environ.

Si, muchos dirán "si es menos útil que LFI, ¿para qué la quiero?". LFI es una vulnerabilidad que poco a poco se hizo conocida y los desarrolladores tienen especial cuidado con ella. En cambio, AFD es una vulnerabilidad muy "precaría" aún, y es usual encontrarla en 7 de cada 10 sitios (vamos, que un sencillo dork en Google da toda la información).

Apéndice III: Usos de AFD

Sin menospreciar a AFD, a continuación daré una lista de usos posibles que se me han ocurrido. Todos ellos intentan garantizar conseguir una shell en el servidor victima.

  • Leer archivos de configuración MySQL. Si la página web cuenta con algún panel de administrador MySQL (phpMyAdmin, Adminer, phpLitleAdmin, etc.), es posible loguearse a dicho panel y subir un archivo a través de consultas MySQL.
  • Desde el mismo phpMyAdmin, listar los usuarios admin y sus contraseñas de un panel admin, así conseguir acceso a dicho panel, que tal vez contenga algún Unrestricted File Upload.
  • A veces, el servidor MySQL es remoto, pudiendo conectarse desde cualquier cliente MySQL. Por ejemplo, phpMyAdmin.co.
  • Leer archivos de sesión PHP. Alguna de esas sesiones, de seguro será admin.
  • Contraseñas admin hardcodeadas en el login. Es poco frecuente, pero sorprendente de cuantos programadores hardcodean las contraseñas.
  • Mucho más... Los límites son tu imaginación.
 

 Apéndice IV: Análisis final

En conclusión podemos decir que AFD tiene "más limitaciones" que LFI, pero a su vez es más frecuente, lo que lo convierte en una vulnerabilidad importante. Ambas técnicas necesitan ser combinadas con otras para conseguir un resultado útil.

Hago una pausa aquí para aclarar una cosilla. Si no lo han descubierto aún, LFI no permite leer el contenido de archivos PHP (al menos no es posible sin utilizar otra técnica, /proc/...), en cambio, AFD si permite leer el contenido de esos ficheros.

En esta parte de la entrada pensé en listar una serie de "soluciones" a esta vulnerabilidad, pero confío en la mente del lector perspicaz y ágil que logrará resolverlo por si mismo. Recuerdo una frase muy importante: Never trust the user input.

Apéndice V: Ejemplo práctico

Como toda buena entrada sobre hacking y vulnerabilidades, hay que finalizar poniendo en práctica lo recién aprendido. En este apéndice me centraré en conseguir acceso a una página web aleatoría (si, Google Dorking), utilizando AFD y en combinación de otras técnicas.

Evitaré sacar capturas de los pasos innecesarios, pero aún así los listaré:

  1. Conseguir leer el archivo "index.php", usualmente tiene mucha información útil. En este caso, tenía un require() a un archivo "mysql.inc.php"
(fig 2. Fichero mysql.inc.php).

Logré leer el fichero de conexión MySQL, el cual contaba con la información confidencial que requería. En este caso no vemos información sobre el servidor MySQL, por lo cual podemos deducir que se trata de un localhost.

Mi siguiente paso fue intentar conseguir algún tipo de panel MySQL, para darle uso a los datos recién conseguidos.








(fig 3. Ingreso phpMyAdmin).


Afortunadamente la página web contaba con un panel phpMyAdmin en un subdominio (phpmyadmin.domain.tld), siendo posible el ingreso con los datos anteriormente obtenidos.






(fig 4. Datos administrativos).

 Al buscar entre todas las tablas, llegué a la que me interesaba a mi. El siguiente paso era claro: obtener el URL del panel admin. Afortunadamente a muchos programadores se les da por dejarle como /admin, o simplemente dejarlo en robots.txt.


(fig 5. Panel administrativo).

 ¡Y voilà! Ya hemos accedido al panel administrativo. Si mis intenciones fuesen malas, buscaría algún uploader y subiría una shell, pero como prueba de concepto, creo que debería detenerme aquí.







  

Hasta aquí la entrada de hoy. Empezaré a publicar contenido más seguido.😁😁😁

Be happy and never (never) trust the user input ;-)
Nobody.

Pssst: Recuerda seguirme en Twitter :-): https://twitter.com/n0bodysec

lunes, 25 de marzo de 2019

Iframe Injection - De Phishing a XSS

Muy buenas a todos,

hoy quería explicar un fallo de seguridad que encontré hace unos días, y que posible explotación tendría esta vulnerabilidad. Yo he llamado a esta vulnerabilidad como "Iframe Injection", ya que no se si tenía ya un nombre antes.



Esta vulnerabilidad ocurre cuando puedes modificar el source de un iframe a tu antojo, pudiendo cargar un contenido de una página maliciosa. En la POC partiremos de una aplicación no vulnerable a XSS. Os voy a dejar el código vulnerable aquí.

  1. <html>
  2. <head>
  3. <title>Mensaje de ayuda</title>
  4. </head>
  5. <body>
  6. <h1>Este es el menu de ayuda</h1>
  7. <?php
  8.         $mensaje_ayuda = htmlentities($_GET['ayuda']);
  9.        
  10.         $errors = array("javascript");
  11.        
  12.         foreach($errors as $error) {
  13.         $res = strpos($mensaje_ayuda, $error);
  14.         if ($res !== false){
  15.                         header('location: error.html');
  16.                 }
  17.         }
  18.         echo '<iframe src="' . $mensaje_ayuda  . '"></iframe>';
  19. ?>
  20. <form method="GET" action="ayuda.php">
  21. <p>NUMERO DE AYUDA</p>
  22. <input name="ayuda">
  23. <button type="submit">ENVIAR</button>
  24. </form>
  25. </body>
  26. </html>

Como vemos lo que tenemos es una supuesta página de ayuda, dependiendo de la página que queramos ver se enviará por parámetro y lo introducirá dentro de un iframe, así quedaría un ejemplo legítimo.


El problema surge cuando la aplicación no controla que el contenido introducido en el iframe pertezca a su propio dominio, el ejemplo más típico sería introducir la URL de nuestra página maliciosa donde tendríamos alojado un phishing para que el usuario introdujera sus datos.


A partir de aquí se podrían enviar correos electrónicos de Phishing más sofisticados ya que la URL introducida tendría el dominio legítimo.

Bypasseando filtros con diferentes URIS

Ahora vamos a imaginar que para evitar esta vulnerabilidad el programador pone algunos filtros que "evitan" que podamos introducir sources externos al dominio.

¿Que formas tenemos de introducir URIs completas para poder jugar con los diferentes filtros que pueda crear un programador?

  1. $errors = array("javascript", "http");
  • Podemos introducir la URL con o sin http indiferentemente, el navegador de ambas formas no lo interpretará como nosotros queremos.
  1. $errors = array("javascript", "http", "//");
  • Podemos usar los símbolos "/" y "\" indistintamente y cuantas veces queramos, el único requisito es que sean mínimo dos.


  • En caso de que la aplicación tenga una regex que busque los símbolos "\" y "/" seguido de "dominio.int" podemos añadir los caráctares ":@" o tan solo "@" al inicio del dominio.

 Jugando con otras URIS

Además de "http" existen otros tipos de URIs con las que podemos jugar, aconsejo mirar aquí y ver si hay algo que pueda resultar interesante, yo voy a mostrar aquí un par de ideas.

  • Se podría abrir el correo electrónico con la URI mailto, encargada de enviar correos electrónicos de la siguiente forma: "mailto:correo@electronico?body=mensaje"

  • Se podría ejecutar código JavaScript gracias a la URI data, la cual simplemente responde con el contenido especificado en la propiar URI, podríamos hacerlo de la siguiente forma: data:text/html,<script>alert("XSS")</script> 


NOTA: Si se introduce JavaScript dentro del servidor Web malicioso no se podrá interactuar con el padre por las CORS, que es lo que nos interesa para poder robar cookies o realizar otros ataques, de esta forma el código si será ejecutado en el padre.
Para entender un poco mejor las CORS aconsejo leer este post https://www.whateversec.com/2019/03/jugando-con-xss-cookies-y-cors.html

Por hoy ya he terminado, podeis seguir jugando con tras URIs diferentes que seguro que sale algo interesante, para cualquier duda o búsqueda de más información podeis comentar.

También me podéis seguir en Twitter para ver nuevos Posts y así echarme de paso una manita.

Saluti.

Lah vulnerabilidadeh de cliente molan tela.

lunes, 18 de marzo de 2019

Jugando con XSS, Cookies y CORS

Muy buenas a todos,

el otro día estaba discutiendo con alguien como de peligrosa puede llegar a ser una XSS, a donde ese "alguien" argumentaba que en caso de ser una aplicación sin usuarios el riesgo de una XSS no será ninguno.

A esto tengo que decir que no es del todo cierto y voy a explicar por qué, este post será tan solo teórico para explicar algunos conceptos y entenderlos bien, pero no haré una prueba de concepto como suelo hacer para que podáis jugar.

El caso en el que me enfocaba yo para poder decir que una XSS en un lugar sin usuarios es el caso de que existan subdominios que si tuvieran usuarios (lo cual es algo muy común).



Para entender como podrías atacar a un subdominio a través de una XSS en el dominio principal hace falta saber en que consisten los siguientes dos valores de las cookies:

  • HTTPOnly: Este valor indica si JavaScript puede o no interactuar con una cookie, es el valor que indica si podremos hacer un robo de sesión a través de una XSS o no.
  • Domain: Este valor indica el domio de la cookie en cuestión. Cuando un subdomio crea una nueva cookie tiene la opción de hacerlo como "subdominio.dominio.int" o como ".dominio.int"
En el caso de que el el flag del dominio apunte a ".dominio.int", cualquier parte del dominio entero podría acceder a ella, de esta forma sería posible robarla en caso de tener el flag "HTTPOnly" desactivado con una XSS en una parte del dominio sin autenticación.

Además de esto existiría otro vector de ataque, este sería a través de peticiones "XMLHttpRequest" en AJAX.

Esto es una explotación ya conocida en las XSS, el ataque consistiría en obtener la respuesta de una petición, por ejemplo "modificarPerfil.html", obtener el token CSRF, y una vez con este enviar otra petición a "modificarPerfil.php" para poder evadir esta medida de seguridad.

Para evitar que esto se pudiera hacer desde un dominio malicioso se crearon las CORS, que son unas cabeceras del servidor que le dicen a tu navegador si el tratamiento de estas peticiones se debe o no hacer dependiendo de donde provenga esta petición.


En principio, si el servidor no indica nada no se podrán realizar estas peticiones (ya sea desde un dominio externo o un subdominio), la cuestión es que pueden estar implementadas varias cabeceras que indican desde donde se podrían realizar estas peticiones.

  • Access-Control-Allow-Origin: Indica desde que dominio se pueden realizar peticiones de tipo XMLHttpRequest.
  •  Access-Control-Allow-Credentials: Esta cabecera indica si se puede o no enviar las cookies a la hora de realizar estas peticiones.


Como veis es necesario que se especifique que se pueden realizar peticiones desde este dominio, sin embargo no es extraño encontrarse estas cabeceras, ya que al ser un dominio del que también se tiene control se trata como un dominio seguro.


Por hoy ya he terminado, ha sido una explicación un poco superficial pero espero que hayan quedado claros los conceptos, para cualquier duda o búsqueda de más información podeis comentar.

También me podéis seguir en Twitter para ver nuevos Posts y así echarme de paso una manita.

Saluti.

Ci no configurah vien lah cosah po te jaqueo.