domingo, 23 de octubre de 2011

phpLDAPadmin 0.9.4b DoS

Ayer se hizo pública, en exploit-db, una vulnerabilidad bastante gorda en phpLDAPadmin (una aplicación web para administrar fácilmente un directorio LDAP). Se trataba de un error que permitía ejecutar código PHP arbitrario. El exploit, aprovechaba ese error para conseguir una shell remota y ejecutar comandos en el servidor.

Bién, hace mucho que no veía un RCE, este tipo de fallos no son tan comunes en la web. Así que se puede decir que me inspiró. Me bajé una versión algo vieja de phpLDAPadmin, pero que aún es usada en algunas páginas web y me puse a buscar errores en el código. Al cabo de un tiempo, esto fue lo que encontré.

if( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) {
 // get the languages which are spetcified in the HTTP header
 $HTTP_LANGS1 = preg_split ("/[;,]+/", $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
 $HTTP_LANGS2 = preg_split ("/[;,]+/", $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
 foreach( $HTTP_LANGS2 as $key => $value ) {
   $value=preg_split ("/[-]+/", $value );
   $HTTP_LANGS2[$key]=$value[0];
 }

 $HTTP_LANGS = array_merge ($HTTP_LANGS1, $HTTP_LANGS2);
 foreach( $HTTP_LANGS as $HTTP_LANG) {
  // try to grab one after the other the language file
  if( file_exists( realpath( "lang/recoded/$HTTP_LANG.php" ) ) &&
   is_readable( realpath( "lang/recoded/$HTTP_LANG.php" ) ) ) {
   ob_start();
   include realpath( "lang/recoded/$HTTP_LANG.php" );
   ob_end_clean();
   break;
  }
 }
}

El código anterior es parte del fichero "common.php" de phpLDAPadmin. Se encarga de definir el idioma en el que se mostrará la aplicación. Para ello, como es usual, hace un include de un fichero con el nombre abreviado del idioma. Por ejemplo: para el español sería "es.php", para el ingles "en.php", para el alemán "de.php", etc. En esos ficheros se definen los mensajes de la aplicación en el idioma correspondiente.

Para obtener el idioma del cliente, phpLDAPadmin, busca en la cabecera "Accept-Language" del protocolo HTTP. Esta cabecera es enviada automáticamente por el navegador y en ella se especifican los idiomas aceptados por el cliente. Por ejemplo:

Accept-Language: es,es-ar;q=0.8,en-us;q=0.5,en;q=0.3

El problema está en que el valor de la cabecera "Accept-Language" no es validado correctamente y se puede manipular para conseguir que la aplicación haga un "include" de cualquier otro fichero php.

Nota para h4x0r5: Sí, como estarás imaginando, no necesariamente debería ser un fichero "php" si usamos el null byte (0x00) para anular la extención. Pero bueno, he probado localmente esa posibilidad y no parece hacerle el más mínimo caso al null byte. Supongo que se debe a que el LFI está en un header HTTP y no en variables enviadas por GET o POST.

Así que se me ocurrió que podría explotar esto para conseguir una denegación de servicio. La idea es conseguir que se haga un include de "common.php" para que la aplicación caiga en inclusiones recursivas de si misma con el consecuente aumento de consumo de CPU y memoria.

Para conseguir esto, vasta con enviar una solicitud HTTP como esta:

GET /phpldapadmin/common.php HTTP/1.1
Host: www.example.com
Accept-Language: ../../common
Connection: close

Luego el include quedará así:

include realpath("lang/recoded/../../common.php");

Lo probé en localhost y este fue el resultado:

Fig. 1 - Incremento del consumo del CPU.

Como se observa en la imagen uno de mis nucleos se dispara al 100% y luego de un momento el servidor responde con un error 500 (error interno del servidor) xD

Pero con eso no basta para tirar un servidor. Los servidores de verdad tienen muchísimos más núcleos que mi dual core. Así que lo siguiente fue programar un exploit que envié varias de estas solicitudes en paralelo y repetidas veces para agotar toda la capacidad de procesamiento del servidor hasta finalmente conseguir que se cuelge.

El exploit lo pueden encontrar en exploit-db ;)

http://www.exploit-db.com/exploits/18023/

Sí, está en java. Sé que algunos colegas dirán que con python hacía lo mismo en 10 lineas o menos pero es lo que hay. Además me quedó bastante fácil de entender :)

También lo probé contra mi PC, pero de ello no hay captura de pantalla... mi maquina se colgó xD

Bueno, es todo por ahora.

Un saludo.

No hay comentarios:

Publicar un comentario