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.

No hay comentarios:

Publicar un comentario