viernes, 12 de mayo de 2017

WannaCry WCry WCrypt

De que hoy anda suelto un ransomware que está haciendo de las suyas, no creo que haga falta hablar.

Sólo unos cuantos enlaces:

Un mapa (malwareTech) en el que puedes ver cómo está la cosa y como ha venido estando. Es el que sale en todas las noticias. Pero aquí lo tienes en tiempo real.

Una cuenta de Twitter (MalwareHunterTeam) con información.

Una hashtag de las que tratan sobre este tema, #WCry

Un repositorio en GitHub con muuuucha información.


Y tu periódico preferido que te contará las cosas de las que se vayan enterando. Espero que de forma correcta

Refbase: Ejecución de código PHP arbitrario

Ésta de la que hablo hoy es una de las vulnerabilidades que menos tiempo me llevó encontrar. Exceptuando aquellas que son obvias, claro está.

Y tan fácil como fue, supongo que no habré sido el primero, ni seré el último en dar con ella.

Ahí va la historia. Voy a tardar más en contarla de lo que me llevó hacerlo:

Preparativos

Uno de los indicios del grado en que se ha tenido en cuenta la seguridad a la hora de diseñar y programar una aplicación es, en mi opinión, el número de veces que en ella se usa la compilación o interpretación de código generado en tiempo de ejecución.

Para decirlo en pocas palabras, si hablamos de PHP o de JavaScript, cuántas veces se usa "eval".

Y lo bueno es que es algo fácil de determinar. Si, como a mí, te gusta la línea de comandos de Linux, puedes usar una combinación de "find", "grep" y "wc". Pero por ahora utilizaremos un editor de textos potente, como Notepad++ o Kate, que ofrezca la capacidad de buscar en todos los ficheros de un directorio y sus subdirectorios.

El que tengo instalado en mi equipo actual es el primero de ellos así que... ahí va lo que hice.

Abrí la ventana de "Buscar" y activé la pestaña de "Buscar en archivos". Allí marqué la opción de buscar como "Expresión regular" y dije que quería buscar dentro de la carpeta de refbase la cadena "eval" seguida de cualquier número de espacios (o quizá ninguno) y, finalmente, un paréntesis:
Imagen 1 - Busca
De los resultados obtenidos, la mayor parte eran del lado del cliente (JavaScript). Pero el último prometía:
Imagen 2 - Encuentra

Haciendo doble clic sobre el resultado se me abrió en la parte superior el fichero con el cursor colocado en la correspondiente línea
Imagen 3 - El punto en que todo se convierte en problemas

O sea: desactivando la salida de las instrucciones (con "ob_start" y "ob_end_clean"), se  lee un fichero cuyo nombre viene dado por $f, se coloca el resultado dentro de una cadena de texto... y se hace un eval de ésta. Un poco antes aparece cómo se determina la ruta del fichero a abrir. Se trata del fichero de adaptación de idioma:
Imagen 4 - El punto del que proceden los problemas
Estaba claro por el contexto, y por un listado de la carpeta "locales" que "$locale" contendría el nombre abreviado del idioma usado por el usuario actual:

Imagen 5 - Los "locales"
Necesitaba encontrar dónde se le asignaba valor a $locale, de modo que usé Notepad++ para buscar en todos los archivos de la carpeta la expresión regular
\$locale\s*=

 Y me encontró la siguiente línea en el fichero "includes/locales.inc.php":
$locale = getUserLanguage(); // function 'getUserLanguage()' is defined in 'include.inc.php'

Miré, pues, la definición de "getUserLanguage()" en "includes/include.inc.php".  La línea en la que se obtenían los valores hacía referencia a otra función:
$userLanguagesArray = getLanguages($loginUserID);

Para encontrar la definición de getLanguages usé la expresión regular
function\s+getLanguages

... Y la encontré en el mismo fichero. El dato lo tomaba de una consulta SQL:
$query = "SELECT language AS language_name FROM $tableUsers WHERE user_id = " . quote_smart($userID);

Pero ¿cómo se metían los datos ahí? Para averiguarlo, localicé los sitios en los que se actualiza la tabla buscando:
update\s\$tableUsers

Y, entre los resultados, encontré varios del fichero "user_options_modify.php", cuyo nombre suena a modificaciones de las opciones de usuario. Tuve suerte con el primero de ellos:
$queryArray[] = "UPDATE $tableUsers SET " 
    . "language = " . quote_smart($formVars["languageName"]) . " "
    . "WHERE user_id = " . quote_smart($userID);

La variable $formVars se rellenaba con los parámetros POST recibidos por el script, sin más comprobaciones:
foreach($_POST as $varname => $value)
        $formVars[$varname] = $value;

La cosa tenía mala pinta. Mala para la seguridad, quiero decir. Busqué la función "quote_smart" (sí: con la expresión regular "function\s+quote_smart") y su código, contenido en el fichero "includes/include.inc.php", parecía prestar atención sólo a temas relacionados con SQL injection y de formato:
function quote_smart($value)
    {
        // Remove slashes from value if 'magic_quotes_gpc = On':
        $value = stripSlashesIfMagicQuotes($value);

        // Remove any leading or trailing whitespace:
        $value = trim($value);

        // Quote & escape special chars if not a number or a numeric string:
        if (!is_numeric($value))
        {
            $value = "\"" . escapeSQL($value) . "\"";
        }
        // Quote numbers with leading zeros (which would otherwise get stripped):
        elseif (preg_match("/^0+\d+$/", $value))
        {
            $value = "\"" . $value . "\"";
        }

        return $value;
    }

De modo que la ruta de fichero no es objeto de más comprobaciones de seguridad que las que tratan de evitar la inyección de SQL. Las puertas están abiertas a un Local File Include gracias a la llamada a la función eval.

Ataque

Impaciente como soy, no pude esperar más. Entré en refbase como administrador (recuerda que las credenciales por defecto son "user@refbase.net" / "start") ...

Imagen 6 - Nótense las opciones para gestionar cuentas de usuario

... y creé una cuenta. Inmediatamente, cerré la sesión y me pregunté ¿qué podría hacer este nuevo usuario de tener malas intenciones?

Imaginemos que puede subir ficheros a un directorio, cosa que de hecho refbase permite. Pero que el programa rechaza aquellos que tienen extensión PHP. Y supongamos que no está en condiciones de explotar la vulnerabilidad de refbase de la que hablamos en "Sube que te sube".

Sea, pues, "c:\xampp\htdocs\otro" una carpeta en la que este atacante puede subir sus ficheros. Y sigamos.

Tras iniciar sesión con esta nueva identidad...
Imagen 7 - Sin opciones de gestión de usuarios
... ya no tenía las opciones propias de un adminitrador. Era sólo un simple usuario. Por ahora.

Ya como usuario de a pie, hice clic en el enlace "Options" de la parte superior de la página para configurar mis preferencias.

Imagen 8 - Mis opciones

Hice clic en el botón a la derecha de "Display Options" para modificar los ajustes.
Imagen 9 - Cambiando opciones
Usando las herramientas para desarrolladores (las de F12), seleccióné el desplegable donde se elige el idioma y, con la tecla F2, procedí a modificar su contenido, dejándolo con una única opción:

Imagen 10 - Extraño idioma
En cuanto hube terminado con el cambio, hice clic en otra etiqueta del código y vi el efecto causado
Imagen 11 - Cambio realizado


Sólo quedaba enviar el formulario con el botón "Submit" de su parte inferior. Con esta extraña lengua se consigue que la aplicación tome el fichero de idiomas, que recordemos que contiene código PHP, de un directorio seleccionado por el atacante. Dentro de él la aplicación buscará, dependiendo de si se usa codificación UTF8 o no, un fichero llamado "common_utf8.inc" o "common.inc" (ver Imagen 4).

Recordemos por otro lado, que el código a evaluar se generaba mediante una instrucción del tipo
$s = "\$loc=array(".ob_get_contents().");";
Y también que este código es ejecutado entre una instruccion "ob_start()" y una "ob_end_clean()" que impiden que se muestre cualquier salida producida mediante instrucciones "print"  y similares.

De modo que podríamos pensar en crear un fichero "common.inc" (o "common_utf8.inc") con el mismo contenido del que trae refbase para el idioma inglés y añadirle al final unas cuantas líneas:
 un contenido como el siguiente
);

ob_end_clean();
print "La cuenta de admin es: " .
    $adminLoginEmail . "<br>";

$_SESSION["loginEmail"] = $adminLoginEmail;

$___dbconfig = file_get_contents("initialize/db.inc.php");

preg_match_all(
    '/(hostName|databaseName|username|password)\s*=.*;/',
    $___dbconfig,
    $___match
);

print "<br>Datos de conexi&oacute;n:<br>";
foreach ($___match[0] as $___dato) {
    print "&nbsp;&nbsp;" .
        $___dato . "<br>";
}
print "<hr>";

ob_start(

Imagen 12 - Líneas añadidas
A poco que se lea, se ve lo que hace: muestra el identificador de la cuenta de administración de refbase, modifica la cuenta del usuario actual almacenada en las variables de sesión y muestra los datos de conexión a la base de datos. Para verlo en acción, basta con cargar una página de la aplicación:
Imagen 13 - Primera ronda

Los datos de cuenta de administración y conexión a la base de datos aparecen en la nueva cabecera que hemos añadido. Pero parece que no han cambiado las acciones que puede realizar el usuario. No hay problema: damos a volver a cargar la página y...
Imagen 14 - Segunda ronda


De todos modos, esto de obtener permisos de administración de refbase es, a estas alturas, poco relevante. Teniendo los datos de conexión a la base de datos, es posible... conectarse a ella. Y después, claro, consultar, modificar o borrar cualquier dato.

 Pero yo soy de los buenos, de modo que aquí paro.

Conclusiones

Creo que hablar a estas alturas de que hay que validar las entradas del usuario en los formularios y aceptar sólo aquellos valores que son razonables... es repetir demasiado las cosas. Pero, sin embargo, siempre hay quien no lo hace.

Por lo demás, hay otra moraleja: "Un fichero de configuración ejecutable es más peligroso que un sable".

Que una definición de idioma, una plantilla o cualquier otra cosa que sólo debería afectar a la  apariencia contenga código PHP es cosa para aficionados al riesgo: "¿Que no tienes la versión en español de refbase? Pues de aquí te puedes descargar los ficheros de idioma. Y van con un regalito".

Pronto, espero, más.







jueves, 11 de mayo de 2017

Vulnerabilidades en el instalador de refbase... cuando funciona

Arreglando el instalador de refbase

Entre los últimos cambios introducidos en refbase se cuenta la compatibilidad con PHP 7. Ciertamente, es bueno saber que los desarrolladores de un producto se preocupan de que éste funcione con las versiones más recientes de su entorno de ejecución. Pero... hay un problema con el instalador.

Para inicializar la base de datos y otros elementos de refbase se utiliza el script "install.php". Y resulta que "install.php" utiliza la extensión "MySQL original". La "de siempre", con funciones o métodos como mysql_connect, mysql_query, etc.), que resulta estar declarada obsoleta a partir de PHP 5.5.0 y eliminada en PHP 7.0.0. De modo que, aunque la aplicación funcione con PHP 7, el instalador no.

Y, claro, no puedes utilizar una aplicación si antes no la instalas.

Por fortuna para quienes quieran actualizar refbase desde una versión anterior, la estructura de la base de datos no cambia. Basta con copiar los nuevos scripts, quizá tocar algún fichero de configuración y... todo listo y funcionando. Supongo que esto es lo que habrán hecho los desarrolladores a la hora de poner en marcha y probar las nuevas versiones. De ser así, "install.php" no les habría hecho falta y, por tanto, nadie se fijó en él y no fue objeto de pruebas.

Carecer de unos procedimientos de gestión que permitan determinar todas las dependencias entre módulos del sistema y de éstos con el entorno de ejecución es, en sí mismo, una segunda "vulnerabilidad administrativa" a añadir a la de ayer. Cosa que no pruebas, error que no pillas. Pero dejémonos de burocracia y vayamos al lado divertido de la tecnología.

Para empezar, a mí no me funcionó el instalador ni siquiera usando PHP 5.6.30. De modo que, por ser constructivos, ahí van los cambios que tuve que hacer en "install.php" para arreglarlo:

1.- Cambiar todas las veces que aparece  "mysql_" por "mysqli_"

2.- Cambiar todas las veces que aparece "mysqli_errno()" por "mysqli_errno($connection)"

3.- Cambiar "mysqli_select_db($adminDatabaseName, $connection)" por "mysqli_select_db($connection, $adminDatabaseName)"

4.- Cambiar el orden de los dos parámetros en todas las llamadas a "mysqli_query". Para ello se puede utilzar un editor de texto avanzado, como Notepad++ o Kate, y realizar una sustitución global de la expresión regular "mysqli_query\s*\(([^,]+),([^\)]+)\)" por "mysqli_query\(\2,\1\)". Y, si no lo ves claro, siempre puedes hacerlo "a mano".

Para los siguientes ejemplos se descargaron las últimas versiones "trunk" y "bleeding edge" del repositorio SVN:

Repositorio SVN





Instalar refbase

La verdad es que instalar refbase, una vez tienes el entorno apropiado y el instalador arreglado, debería ser bastante fácil. Vayamos a ello:
El instalador. Si no ves en él nada raro...


Es buena cosa que se recomiende modificar los parámetros de conexión a la base de datos indicados en el fichero "initialize/db.inc.php". En él aparecen unas variables cuyos nombres son bastante explicativos, aparte de que los comentarios del fichero lo dejan todo muy claro si sabes inglés. Estas variables y sus valores por defecto son:

$hostName = "localhost";
$databaseName = "literature";
$username = "litwww";
$password = "%l1t3ratur3?";

No hace falta que la base de datos ni la cuenta de acceso existan. De eso se encargará el instalador. Lo malo es que, si MySQL (o MariaDB) está instalado en el mismo equipo que el servidor web, se puede realizar la instalación sin cambiar estos parámetros de configuración. Y, ya se sabe, los valores por defecto suelen hacer que todo funcione, pero no siempre de forma optimizada o segura.

No es bueno usar credenciales por defecto y las aplicaciones no deberían tenerlas. Mejor preguntarlas a quien realiza la instalación.

Es hora de rellenar el formulario. Para empezar, unas credenciales para acceder al servidor de bases de datos. Debe tratarse de una cuenta con permisos de administración pues con ella se creará la base de datos y la cuenta de usuario, se asignarán permisos, etc.

Después va la ruta del programa de línea de comandos que permite interactuar con la base de datos, típicamente "mysql.exe" o "mysql". Y le sigue la ruta de un fichero con los comandos SQL que crean las tablas y les añaden sus primeras filas. Paro aquí y no sigo porque el resto carece de relevancia para las pruebas que estoy realizando. Y te dejo tiempo para que vuelvas a leer este párrafo.

Sí. Has leído y entendido bien. No es que haya un problema de vulnerabilidad de inyección de comandos de sistema operativo ni otra de SQL injection. Es que ambas cosas forman parte del propio diseño del procedimiento de instalación. Y, sí, ésta es una de las cosas que les comentaba hace año y pico a los desarrolladores.

En todo caso, debe señalarse que hay un factor que mitiga el riesgo. Por la forma de funcionar del instalador, si las credenciales de acceso a la base de datos proporcionadas no son válidas, o si la cuenta no puede seleccionar la base de datos "mysql", el proceso de instalación se detiene y no se ejecutan comandos ni del sistema operativo ni SQL. Además, se comprueba que las rutas se refieren a ficheros y que se tienen los permisos apropiados.

Pero una cosa es conocer unas credenciales válidas de administración de MySQL y otra es poder ejecutar comandos en el sistema operativo con la cuenta del servidor web. Como esta vez estaba usando XAMPP en "modo usuario", sin instalar servicios, me acordé de nuestra amiga la calculadora:
El formulario relleno y el efecto que causa al enviarlo


Además, el formulario tiene una vulnerabilidad de Cross Site Request Forgery. Esto permite explotar las vulnerabilidades presentes incluso si no se tiene acceso a la instancia de refbase a atacar. Bastaría con que alguien con malas intenciones (y sabiendo credenciales de adminsitración de MySQL) tuviera una página en su servidor como "http://malicioso.example.net/1/index.html" con un código como el siguiente:
Código fuente de la página maliciosa


Como puede observarse, es un formulario de instalación ya relleno que es enviado de forma automática al servidor de la instancia de refbase y cuyos valores fuerzan la ejecución de comandos en el servidor web. Si ahora consiguiera que alguien que sí tenga acceso a la aplicación visitara la página maliciosa...

A lo del fichero SQL no le dedico mayor espacio. A todo lo dicho habría que añadir que quien tenga ya las credenciales de adminsitración de MySQL posiblemente encuentre, o haya encontrado, formas de hacer lo que quiera y no necesite andar jugando con el instalador de refbase. De todos modos, casos habrá en que éste sea de utilidad.

Instalando ya refbase. Esta vez, de verdad

Bueno, ha llegado la hora de instalar refbase. Relleno los campos bien y envío y...
Instalado




Al acabar la instalación, de nuevo, la aplicación da buenos consejos. Me dice que cambie la cuenta de administración de refbase (por defecto "user@refbase.net" con contraseña "start") y que, ya que no me va a hacer más falta, elimine el script "install.php". No sea que alguien lo utilice para volver a instalar la aplicación y hacer tabla rasa con todos los datos que pudiera contener.

Algún "install.php" me he encontrado usando Google. ¿Y cuántos habrá en Internet no indexados, pero que están "al ladito" de instalaciones de refbase que sí aparecen en el buscador? Iba a poner un ejemplo llamativo, pero mejor me paro un poquito...

De este tema hablé también con los autores de refbase. Y me alegra ver que en la nueva versión, la página principal de la aplicación´se niega a prestarnos servicio en tanto exista el fichero "install.php" (y también "update.php", utilizado para actualizaciones desde versiones muy antiguas).
Si no eliminas los scripts de instalación, no te hago caso

Eso sí, si te sabes algunas URLs, otras funcionalidades no cuentan con esta protección. Como se dice por aquí, nos van dando "una de cal y otra de arena". Una cosa buena y otra mala. Además, algunas de estas funcionalidades en mi caso muestran muchos mensajes de error:
Errores a gogo

De eso también les hablaba en el informe que envié en su día a los desarrolladores de refbase. Que si era conveniente deshabilitar los mensajes de error, que si éstos podrían proporcionar información a un potencial atacante... La respuesta fue que esto no era problema de refbase. Que bastaba con configurar el servidor PHP, con "display_errors=Off" en el "php.ini", para que no mostrara los mensajes y listo.

¡Ay! ¡Costumbre peligrosa, la de dejar que sean otros los que corrijan algo que uno podría haber dejado bien! ¡Y mira que les habría bastado con poner un "error_reporting(0);" al inicio de unos cuantos ficheros! Pues ni por esas.

Bueno. Elimino "install.php" y "update.php", configuro mi servidor para que no muestre errores y lo reinicio. Todo mejor.
Esto ya parece un programa

Una pregunta que me hago

Digo yo: El instalador te pide que le indiques mediante el formulario las rutas del fichero con sentencias SQL a instalar y del ejecutable de la interfaz de línea de comandos de MySQL. Y tienes que tocar ficheros PHP para indicar los parámetros de conexión y el nombre de la cuenta de administración.

En todo caso... ¿no sería preferible que fuera al revés? Que lo que estuviera configurado mediante ficheros PHP fueran las rutas del ejecutable y el fichero SQL. Que el formulario solicitara los parámetros de conexión y la cuenta de administración.

Supongo que pensarían: "A ver dónde va a poner el instalador las credenciales de conexión y otras cosas por estilo. Porque si es en un fichero de texto o similar alguien podría descargarlo y ver su contenido. Y usar los valores para generar código PHP de forma automática... da un poco de mal rollo. No sea que alguien averigüe cómo inyectar código PHP en alguno de los parámetros y nos la líe parda".

Pero no es éste un tema del que deberían preocuparse demasiado.

Refbase ya tiene otras vulnerabilidades de ejecución de código PHP arbitrario.

La próxima vez os lo cuento.

miércoles, 10 de mayo de 2017

Vulnerabilidad de "Insufficient resources to accomplish the task"

Refbase es el nombre

En la última entrega hablaba de una aplicación vulnerable cuyo nombre no quería revelar. Estaba siendo objeto de cambios en su código fuente y prefería esperar a ver cómo quedaba al final. Ahora que la cosa se ha estabilizado, creo que es momento de dedicarle unos cuantos posts.

Muchos posts.

Vaya aquí el primero. Hace ya más de un año que me puse en contacto con los desarrolladores de "Web Reference Database", también llamado "refbase" para comunicarles algunos fallos de seguridad que le había encontrado. Y no había costado demasiado dar con ellos. Para quien no lo conozca, refbase es el software al que, sin nombrarlo, me referí en varias entregas de esta serie como en "El parque del oso" y "otros casos parecidos" o en "Más cosas de la web del oso". Y, sí, también en "Sube que te sube".

Tras intercambiar varios mensajes con ellos y esperar (esperar mucho), os cuento mi experiencia y mis reflexiones.

Vaya por delante que refbase es una aplicación muy compleja, con muchas funcionalidades, y que, si no tuviéramos en cuenta los aspectos relacionados con la seguridad, me parecería estupenda, pero...

Primer contacto


Pero me parece que no se diseñó con la seguridad en mente. Y, cuando el producto está hecho, cambiar sus especificaciones es complicado, de modo que la cosa se suele arreglar con parches, de esos que no suelen quedar "bonitos". Pero vayamos a la web de refbase y veamos qué ofrece:

New - Download refbase 0.9.6


Estamos de suerte. Hay una versión nueva, la 0.9.6 y se supone que ha corregido algunos problemas. Quizá... si no fuera porque esa misma versión ya era "nueva" hace unos tres años:

Not that new

Al hacer clic sobre este anuncio de nueva versión se inicia la descarga de refbase. Así procedí yo hace año y pico. Y cuando les envié un reporte de vulnerabilidades me señalaron que algunas de ellas ya estaban solucionadas y que lo comprobara en su repositorio de Subversion, donde hay una versión más actualizada.

A este respecto debo señalar que en su página principal tienen un enlace al mismo y que en alguna ocasión he encontrado recomendaciones de los propios desarrolladores para que se use la versión del SVN.

Espera, que hay versiones posteriores



La tecnología puede ser sexy y llamativa. Pero no siempre es lo más importante. Y, desde luego, no lo es en este caso. Porque si la versión 0.9.6 es muy vulnerable (que, serlo, lo es) y existen versiones más recientes (que, existir, existen)... yo me pregunto: "¿Por qué no se ofrece una versión más reciente en la página principal de la web?". Y se me ocurren dos respuestas:

- Porque no han considerado estable ninguna de las versiones posteriores a la 0.9.6.
- Porque no han actualizado la web.

Sea como sea, ahí está el mensaje. Colocado en una zona privilegiada de la página, de modo que habrá quien, como yo en su día, se limite a hacer clic en él y no siga leyendo.

Y aseguro que creo, quiero creer, que al equipo de desarrollo de refbase le preocupa la seguridad. De hecho, incluso he encontrado casos en que recomiendan a sus usuarios actualizar sus entornos de ejecución a versiones más recientes.

Buenos consejos


Pero es que es un equipo muy reducido. Dependiendo del momento, quizá dos... quizá 3... quizá lleguen a 5 miembros. Y muchos de ellos van y vienen: "los de siempre" parecen ser sólo dos. Que, además, parecen tener otras ocupaciones principales que, supongo, les dejarán poco tiempo libre.

Mientras tanto, sigue habiendo quien se descarga la versión antigua, supervulnerable, y la instala en producción, con los riesgos que  ello supone:

Sí, amigo. Instálate la 0.9.6, que verás que bien te lo pasas

Ahí dejo, pues, un ejemplo (uno más) de "vulnerabilidad administrativa". Por usar la forma de expresarse del Top 10 de OWASP supongo que podría denominarse: "Insufficient resources to accomplish the task". Y a la larga es de las graves. Más que un SQL injection. Porque mientras ésta puede corregirse puntualmente, la otra es una tendencia.

Quien no mire este tipo de cosas a la hora de seleccionar los proyectos de software a implantar, tanto libre como propietario, que después no se queje.

La próxima vez nos pondremos a ver si se arreglaron los problemas de seguridad de la aplicación. Que os adelanto que más bien no.

martes, 25 de abril de 2017

By Design (5)

Sube que te sube

Una página que permite subir un fichero a un servidor... ¿qué puede salir mal?

No quiero dar por ahora el nombre de la aplicación porque me consta que en estos días está siendo sometida a una importante "reforma" y quisiera antes ver cómo termina la cosa. Pero, sin decir el "pecador", sí voy a mencionar uno de sus muchos, y en ocasiones importantes, "pecados". De modo que en los ejemplos que siguen se mostrará un formulario que he creado aprovechando su código (se trata de software libre) y copiando su comportamiento.

La idea es que el usuario sube un fichero y la aplicación lo almacena en cierto directorio. El nombre con el que el fichero es guardado se determina teniendo en cuenta el valor de una variable de configuración:
  • Si el valor de ésta es verdadero, se usa un nombre predeterminado y se le pone como extensión la del fichero original. Esta extensión se obtiene tomando los caracteres que sigan al último carácter de punto (.). Esta es la opción por defecto.
  • Si es falso, se usa el nombre y la extensión del fichero original.
El primer error de diseño, aunque es algo que no siempre es posible evitar, es que por defecto el directorio en el que se copian los ficheros subidos es un subdirectorio de la propia aplicación web. Peligroso. Muy peligroso. Pero no todo está perdido (¿o sí?): los desarrolladores implementan un control de las extensiones de archivo permitidas con objeto de impedir que alguien cuele algo dañino:

if (preg_match("#\.(exe|com|bat|zip|php|phps|php3|phtml|phtm|cgi)$#i", $uploadFile["name"]))
  // file name has an invalid file name extension (adjust the regex pattern if you want more relaxed
  //file name validation)
   $errors["uploadFile"] = "You cannot upload this type of file!";
  // file name must not end with .exe, .com, .bat, .zip, .php, .phps, .php3, .phtml, .phtm or .cgi

El resultado es que si, por ejemplo, se intenta subir un fichero PHP, la aplicación se niega a obedecer:
Imagen 1 - No puedes subir este tipo de fichero


Así que nada de ".exe, .com, .bat, .zip, .php, .phps, .php3, .phtml, .phtm or .cgi" ¿verdad?

Blanco. Blanco como la nieve

Cuando de medidas de seguridad se trata, es más fácil terminar arrepentiéndose de haber usado una lista negra que de usar una lista blanca.

Y, para muestra, un botón. Porque mirando esas extensiones me pregunto: ¿y si, por ejemplo, la aplicación estuviera corriendo en un servidor Apache que tuviera instalados módulos como mod_mono, que permite la ejecución de páginas ASP.NET? ¿Y si, entonces, alguien subiera un fichero con extensión .ASPX?

Sin necesidad de ir tan lejos, lo que más a mano tenía yo para hacer pruebas era un servidor XAMPP sobre Windows. Y... XAMPP trae Perl activado. Así que probé a subir un fichero con extensión ".PL":
Imagen 2 - Subiendo CGI en Perl
Et voilà:
Imagen 3 - Ejecutando el CGI

Lo mejor es que si se cambia el shebang (eso que empieza por #! en la primera línea) se puede invocar otros programas para interpretar el programa. Eso sí, teniendo que lidiar "a mano" con las complejidades del CGI. Que, por otro lado, tampoco son tantas ni tan grandes. Por ejemplo, ahí va PHP:
Imagen 4 - CGI escrito en PHP


O, puesto que estoy ejecutando Apache como usuario (no como servicio) ¿por qué no acordarnos de nuestra gran amiga, la calculadora?
Imagen 5 - La calculadora es buena. La calculadora es tu amiga

También me llama la atención que, aunque se prohíbe la subida de ficheros .EXE, no se dice nada de los PS1 de Powershell, los .VBS y los .JS de Windows Scripting Host, etc., que pueden proporcionar funcionalidades similares.

Todo ello por no pensar en que alguien suba un fichero HTML y tenga su XSS bien asentadito. O su tienda ilegal de fármacos o de falsificaciones de prendas de moda.

Es lo que tienen las listas negras: o estás al tanto de todas las posibilidades y sus consecuencias y lo haces todo a la perfección o después toca lamentarse.

Pero aún hay más. Hagamos borrón y cuenta nueva y exploremos otro camino.

Regular. O sea: ni bueno ni malo

Las expresiones regulares facilitan mucho las cosas a los programadores. Son potentes y sencillas... pero no siempre fáciles.

Quizá sea una trivialidad, pero resulta que para resolver un problema usando expresiones tienes que dominar dos cosas:
  • El problema que quieres resolver y sus condicionantes
  • Las expresiones regulares
Y cuando todo sale mal, muchas veces no sabes en cuál de ellas se falló. Como dije antes, yo estaba usando XAMPP sobre Windows. Uno de los muchos entornos en los que la aplicación puede ser desplegada. Y, como cada uno de ellos, con sus características propias.

En este caso, basta con fijarse en una de ellas: cuando en Windows creas un fichero cuyo nombre tiene espacios al final, dichos espacios son ignorados. Como una imagen vale más que mil palabras:
Imagen 6 - Espacio

 De modo que, si se intenta subir un fichero PHP...
Imagen 7 - Subiendo PHP


... y se intercepta la petición usando un proxy como ZAP y se modifica el nombre del fichero, añadiendo un espacio al final (y también el tamaño de la petición, que habrá que incrementar en uno como consecuencia de lo anterior)...
Imagen 8 - Modificando la petición

 ... El resultado será
Imagen 9 - Subido...

 Y, si se conoce en qué directorio ha sido colocado, el fichero será de lo más "aprovechable"

Imagen 10 - ...Y funcionando

Podría ser aún peor. Porque si se hubiera configurado la aplicación para no renombrar archivos, en lugar del espacios al final del nombre también valdría con uno o varios puntos:
Imagen 11 - Por si fuera poco

Por ir acabando

Menos mal que la aplicación hace otras comprobaciones y no deja que el nombre del fichero contenga cosas rarunas, como la barra  de directorio o la barra invertida. En realidad, ahí se hace un buen diseño y se limita los caracteres válidos, tanto para ficheros como para directorios, a un conjunto muy preciso: "a-zA-Z0-9+_.-" para los primeros y "a-zA-Z0-9+_-" para los segundos.

Lástima que las comprobaciones se hacen sólo para la parte del "nombre de archivo" y no para la de la extensión.

Por si a alguien le cabía duda: lo del upload era sólo la anécdota. Lo que realmente quería decir con este post era:
  • Eso de que los ficheros subidos vayan a un directorio que está publicado por el servidor web es muy, muy, muy mala idea.
  • En general, para esto de la seguridad: Lista negra= caca. Lista negra= problemas. Lista negra = quebraderos de cabeza.
  • Las expresiones regulares son como las cerillas: son algo bueno, pero tienes que ser responsable y saber lo que estás haciendo antes de usarlas. No hacen magia. No resuelven tus problemas. Sólo son una herramienta rápida para que tú los soluciones. Si tú te equivocas, las expresiones regulares te ayudarán a equivocarte más rápido.
No es éste, el de la subida de ficheros, el único problema de seguridad de la aplicación. Ésa cuyo nombre por ahora callo pero que alguien seguro que intentará, y posiblemente logrará, localizar. Que para eso están los buscadores.

Tiene tantos como para dedicarle un blog entero.

Lo bueno es que de los errores se aprende. Y mejor que sea de los ajenos.
(Continuará...)

sábado, 11 de febrero de 2017

Biometría y ataques de fuerza bruta

Los aspectos legales de los mecanismos biométricos para la seguridad son, cuando menos, sorprendentes. Hace algún tiempo, en un post llamado "Biometría: Identificación, Autenticación o Autorización", planteaba mis dudas sobre el estado actual de la tecnología biométrica y, de paso, dejaba caer que, en los Estados Unidos, las autoridades policiales y judiciales no pueden forzar a un acusado a entregar su contraseña pero sí a poner el dedo sobre el lector de huellas que desbloquee un equipo.

Y eso es lo que pasó en el caso de "el Estado de Minnesota contra Matthew Vaughan Diamond". Se forzó al acusado a desbloquear su teléfono y se dictaminó que eso no iba en contra de la "quinta enmienda". Esa que, entre otras cosas, dice que un acusado no puede testificar contra sí mismo. Y es que "hacer algo", como desbloquear un teléfono, no se considera prestar testimonio.

Pero, según me entero al oir un episodio del podcast Security Now...hubo apelación. Basada en que la policía no indicó al acusado qué dedo debía usar, sino que le ordenó usar "el que desbloqueara el teléfono". Y, como no, a alguien se le ocurrió que eso sí era forzar a testificar, a decir qué dedo había que usar.

No sé cómo terminarán estas cosas, pero a las autoridades les habría bastado con un ataque de fuerza bruta. Al fin y al cabo, sólo hay diez dedos a probar.

Me pongo a pensar en como elevar el número de posibilidades y me pregunto: ¿contratarán los ricos a gente para que les desbloqueen los teléfonos con datos más sensibles? ¿tendrán huellas dactilares los dedos de los pies?

Y mejor que me deje de preguntas, que ya habrá por ahí quien esté pensando en otras partes del cuerpo con las que incrementar el "espacio de claves".

martes, 6 de septiembre de 2016

El mercado y el mercadeo del typosquatting (4)

¿Cómo protegerse?

El typosquatting puede terminar derivando en phishing, usos de tu imagen fraudulentos o que pudieran atentar contra ella, envío de visitas a tu competencia,...  Pero... ¿Cómo te proteges de todo esto?

Todo depende de en qué momento decidas actuar y de lo que otros hayan hecho ya al respecto. Vamos por partes:

Mejor prevenir que curar

Si el dominio que pudiera ser usado contra tí está libre... lo mejor sería que lo adquirieras. Por lo general, el coste anual no tendrá más allá de dos cifras (decimales al margen, claro) y en muchos casos puede que sea sólo una.

El problema aquí es que hay que imaginar. Prever qué dominios pudieran causarte problemas. Y seguro que no son pocos. Por poner un ejemplo, para "blogspot.com", donde nos estamos viendo, habría cosas como "wwwblogspot.com", "www-blogspot.com", "blogpot.com", "blogsppt.com", etc.

Unos serán más probables que otros. Quizá prefieras registrar sólo estos. Pero entonces...

Vigila

Sí. Vigila aquellos nombres de dominios que, sin ser tuyos, podrían confundirse contigo. Porque aunque hoy no estén registrados o tengan contenidos inofensivos, mañana todo puede haber cambiado.

Quizá cambien de propietario. Quizá el propietario cambie de ideas o lo aparque o alquile. Sea como sea, entonces sí será problema tuyo.

Así que comprueba el contenido de sus páginas, si es posible desde distintas ubicaciones (quizá te interese utilizar herramientas del tipo Browserling o BrowserStack), y también los resultados que puedan aparecer en las páginas de buscadores. Y, dado que lo más probable es que se protejan de la indexación mediante ficheros "robots.txt", si puedes irles echando un vistazo de vez en cuando tampoco te hará daño.

Vigilancia 24 x 7. Algo que en otras áreas no es (o no debería ser) tan raro de encontrar.

Cuando ya no puedas prevenir...

Si llegas cuando ya hay una campaña de phishing utilizando un domino, actúa.

Actúa tanto si eres el responsable del servicio como si eres un usuario. Aparte de las denuncias policiales y/o judiciales que corresponda poner, todo irá mejor si les ponemos las cosas difíciles a los phishers.

Si el dominio malicioso es un ".es", se puede realizar una notificación enviando un correo al CERT de Seguridad e Industria, dependiente del INCIBE, tal y como se cuenta en la página de dominios.es. En pocas palabras: manda un correo electrónico a incidencias@certsi.es. Si quieres más información, haz clic aquí. Otros TLD podrían tener cosas parecidas.

Para los ".com" y otros dominios habituales gestionados por ICANN, es cuestión de mirar los datos de Whois. Los agentes registradores dan datos de contacto para la notificación de cualquier abuso que se pueda encontrar. Busca una etiqueta que ponga "Registrar abuse contact email" o algo parecido y al lado tendrás una dirección de correo electrónico. 

Una vez sepas a quién, envía ese mensaje. Que el texto sea clarito y que tenga capturas de pantalla del sitio legítimo y el del phishing si es posible. Pero no corras riesgos inútiles: cuando se trate de algo en lo que no confíes, usa un servicio de los que te dejan usar un navegador durante un rato o hacen capturas de cómo se mostraría el sitio.

¿Que si funciona? Cuando la cosa está clara, normalmente sí. En cuestión de horas.

Y si no sabes qué hacer... cuenta con Google, que tiene también una página para reportar phishing.

Recuperar lo que no tuviste

Si el dominio está registrado pero no lo usan para nada raro... aparte de vigilarlo puedes actuar.

Para apoderarte del dominio que te tiene con la mosca detrás de la oreja puedes irte a los juzgados. Pero posiblemente sea algo costoso y lento. También, dependiendo del TLD del que estemos hablando, puede existir un procedimiento extrajudicial denominado "recuperación". Y que lo de recuperar no te lleve a engaño: no hace falta haber sido antes propietario del dominio.

Si se trata de un dominio ".es", te propongo un poco de lectura. Y por si prefieres que te lo resuma, ahí voy:
  • Tienes que tener un dominio ".es" registrado para poder iniciar un procedimiento de recuperación.
  • Existen una serie de "proveedores de resolución extrajudicial de conflictos" ante los que puedes interponer la demanda. Actualmente son:
    • (Adigital), Asociación Española de la Economía Digital
    • (Autocontrol), Asociación para la Autorregulación de la Comunicación Comercial.
    • Consejo Superior de Cámaras de Comercio, Industria y Navegación de España.
    • Centro de Arbitraje y Mediación de la Organización Mundial de la Propiedad Intelectual.

  • En la demanda debes justificar:
    • Que el nombre del dominio se parece demasiado a tu marca o nombre de dominio legítimo.
    • Que el propietario del dominio "raruno" no los tiene.
    • Que el registro o el uso posterior del dominio denota mala fe. O sea, que se registró o utilizó pensando en tí.
Si tienes razón... te darán el dominio en litigio y una cosa menos de la que preocuparte.

Eso sí. Todo tiene un lado malo. El coste por procedimiento, que tendrás que pagar TÚ, es de 1.400 euros. Mil cuatrocientos, por si alguien se lía con eso de los puntos y las comas. Si no me equivoco, más el correspondiente IVA. Y, por supuesto, añádele lo que corresponda si contratas a alguien para que te lleve estos papeles.

Cuando hablamos de euros y de cuatro cifras...

Si te interesa, puedes consultar los procedimientos que se abrieron en el pasado y sus resoluciones aquí, visitando la pestaña "Resoluciones dictadas". Algunas cosas curiosas encontrarás, como el caso de "facebook.es" del 2009 o el de "viajescarrefour.es" en el 2010. Nombres que habrían confundido  incluso a un experto.

Para dominios dependientes del ICANN también tienes una referencia que consultar. En este caso los proveedores de resolución aparecen listados en esta página. Sólo comentarte que la "WIPO" es lo mismo que la "OMPI" (siglas en inglés las primeras y en español las segundas). Y que la principal diferencia con las normas para los dominios ".es" es que, en el caso de los dependientes de ICANN eso de "el registro O el posterior uso denote mala fe" se cambia por un más restrictivo "el registro Y posterior uso denoten mala fe". Deben darse ambas circunstancias.

Por lo demás, tampoco es barato. De modo que vuelvo a lo que decía al principio de este post. Mejor prevenir que curar.