CVE-2019-17059: Preauth-RCE en el Cyberoam de Sophos explicado

Hemos estado trabajando duro con investigadores de seguridad internos y externos aquí en TheBestVPN para descubrir lagunas serias explotables de forma remota en VPN SSL y cortafuegos como Cyberoam, Fortigate y Cisco VPN. Este artículo es un recurso técnico sobre una vulnerabilidad crítica parcheada que afecta a Cyberoam SSL VPN, también conocida como CyberoamOS.

Este exploit de Cyberoam, denominado CVE-2019-17059, es una vulnerabilidad crítica que permite a los atacantes acceder a su dispositivo Cyberoam sin proporcionar ningún nombre de usuario o contraseña. Además de eso, el acceso otorgado es el nivel más alto (raíz), que esencialmente le otorga a un atacante derechos ilimitados en su dispositivo Cyberoam.

En la mayoría de los entornos de red, los dispositivos Cyberoam se usan como firewalls y puertas de enlace VPN SSL. Esto le da a un atacante potencial un fuerte punto de apoyo en una red. Hace que sea más fácil atacar hosts dentro de la red, y dado que los dispositivos Cyberoam generalmente son confiables en la mayoría de los entornos, esto le da a los posibles atacantes una ventaja adicional.

Según Shodan (un motor de búsqueda de dispositivos conectados a Internet), hay más de 96,000 dispositivos Cyberoam con conexión a Internet de todo el mundo. La mayoría de estos dispositivos se instalan en empresas, universidades y algunos en bancos de renombre mundial. Esto lleva a que los ataques tengan un gran impacto en estos entornos..

Trabajar con el equipo de seguridad de Sophos ha sido una gran delicia, ya que actuaron rápidamente al reconocer y lanzar parches solo unos días después de nuestro informe inicial. Felicitaciones a ellos! (¡juego de palabras!)


detectar Cyberoam

Y dado que la mayoría de estas entidades son objetivos atractivos para los atacantes, hace que los errores sean más críticos.

Ejecución remota de comandos raíz no autenticados de CyberoamOS

CyberoamOS es un sistema operativo modificado basado en Linux para dispositivos Cyberoam. Este sistema operativo tiene una interfaz de configuración basada en la web y un portal SSLVPN.

La interfaz web se divide en dos partes principales:

  • Una interfaz escrita en Java
  • Un backend que usa una combinación de C y Perl

No profundizaremos en las partes internas del código de front-end o back-end, principalmente para ahorrar tiempo y limitar la cantidad de información revelada. Pero discutiremos brevemente cómo se activa el error.

Tanto la configuración como las interfaces SSLVPN tienen un servlet que maneja las operaciones principales. Estas operaciones se definen usando un parámetro llamado "modo".

La mayoría de estos están autenticados. Pero hay algunas operaciones a las que podemos acceder sin autenticación (como inicio de sesión).

Los errores que hemos encontrado se encuentran en el módulo de correo electrónico antivirus / antispam. El modo de solicitud para este punto final (módulo, op) es 458.

Una cosa a tener en cuenta es que los códigos de operación se asignan a sus nombres en la base de datos de Cyberoam (base de datos interna Postgres). Al buscar 458, podemos averiguar cuál es el nombre de este código de operación.

Aquí hay una línea del script SQL de inicialización de la base de datos que muestra el nombre opcode 458:

insertar en tblcrevent (código de operación, descripción, modo, tipo de solicitud)
valores ('RELEASEQUARANTINEMAILFROMMAIL', 'RELEASE CUARANTINE MAIL FROM MAIL', '458', 2);

Las funciones del código de operación se almacenan en el directorio / _conf / csc / cscconf /. No revelaremos el código completo de la función vulnerable, pero proporcionaremos algunos fragmentos que muestran dónde y cómo se produce el error.

Un código de la interfaz Java que maneja el código de operación 458:

if ((jsonObject.getString ("hdnSender") .equals ("") ||
validateEmail (jsonObject.getString ("hdnSender"))) &&
validateEmail (jsonObject.getString ("hdnRecipient")) &&
isSafeFilePath (jsonObject.getString ("hdnFilePath")) && b) {
httpServletResponse.setContentType ("texto / html");
CyberoamLogger.debug ("Antivirus / AntiSpam", "Valor constante de CSC " +
CSCConstants.isCCC);

Como puede ver arriba, se verifican la validez de algunos parámetros. Si son valores válidos, sucede lo siguiente:

eventBean final eventByMode = EventBean.getEventByMode (363);
... redactado.
final int sendWizardEvent = cscClient.sendWizardEvent (eventByMode, hashMap, sqlReader);

Como podemos ver arriba, tenemos un nuevo código de evento (363) que se enviará al backend. El error que hemos descubierto está en el código que maneja esto en el backend.

El código de operación se llama sendmail, y para evitar la explotación de este error, eliminaremos la mayor parte del código del siguiente código.

El manejador de código de operación para send_mail.

...redactado ...

$ param = $ solicitud->{lanzamiento};
param = DLOPEN (base64_decode, param)
LOG applog " Valores de decodificación :: $ param \ n"
% requestData = split (/ [&=] /, $ param);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestData {hdnSender};
$ mailTo = $ requestData {hdnRecipient};
$ archivo = $ QUARANTINE_PATH."/ /".$ requestData {hdnFilePath};

$ mailfile = $ requestData {hdnFilePath};
$ validate_email ="falso";
my $ email_regex = '^ ([\.]? [_ \ - \! \ # \ {\} \ $ \% \ ^ \&\ * \ + \ = \ | \? \ '\\\\\\ / a-zA-Z0-9]) * @ ([a-zA-Z0-9] ([-]? [a-zA- Z0-9] +) * \.) + ([A-zA-Z0-9] {0,6}) $ ';
if ($ requestData {hdnRecipient} = ~ / $ email_regex / && ((definido $ requestData {hdnSender} && $ requestData {hdnSender} eq '') || $ requestData {hdnSender} = ~ / $ email_regex /) && index ($ requestData {hdnFilePath}, '.. /') == -1) {
$ validate_email ="cierto";
}
.... redactado....

Como podemos ver arriba, el código pseudo-Perl nos muestra cómo el backend recibe información del frontend ($ requestData) y cómo intenta verificar algunos de los parámetros que enviamos.

Después de la verificación, si nuestros parámetros son válidos, se ejecuta el siguiente código:

% mailreq = ("mailaction"=>"$ MAIL_FORWARD","tema"=>"$ strSubject","al correo electrónico"=>"$ mailTo","archivo adjunto"=>"$ archivo","smtpserverhost"=>"$ mailServerHost","de la Dirección"=>"$ mailDe");

out = OPCODE mail_sender json% mailreq

El código anterior establece nuestros parámetros de solicitud en la variable mailreq y llama a la función mail_sender (OPCODE). Veremos cómo se ejecuta este código de operación y dónde ocurre exactamente el RCE:

#mailaction 0 = mail_with_var, 1 = mail_forward, 2 = mail_attachment
$ mailaction = $ solicitud->{mailaction};
$ subject = $ solicitud->{tema};
$ mailbody = '';
$ archivos adjuntos = $ solicitud->{archivo adjunto};
$ toEmail = $ solicitud->{al correo electrónico};

# cuerpo del correo
SI("$ pedido definido->{mailbody} && '' ne $ solicitud->{mailbody}") {
$ mailbody = $ solicitud->{mailbody};
}
# Host del servidor SMTP
SI("$ pedido definido->{smtpserverhost} && '' ne $ solicitud->{smtpserverhost}") {
$ smtpserverhost = $ solicitud->{smtpserverhost};
}MÁS{
resultado = CONSULTA "seleccione servicevalue de tblclientservices donde servicekey = 'MailServer'"
SI("$ resultado definido->{salida}->{valor de servicio} [0] && '' ne $ resultado->{salida}->{valor de servicio} [0]") {
$ smtpserverhost = $ resultado->{salida}->{valor de servicio} [0];
}MÁS{
$ smtpserverhost ="127.0.0.1";
}
}

# Puerto del servidor SMTP
SI("$ pedido definido->{smtpserverport} && '' ne $ solicitud->{smtpserverport}") {
$ smtpserverport = $ solicitud->{smtpserverport};
}MÁS{
resultado = CONSULTA "seleccione servicevalue de tblclientservices donde servicekey = 'MailServerPort'"
SI("$ resultado definido->{salida}->{valor de servicio} [0] && '' ne $ resultado->{salida}->{valor de servicio} [0]") {
$ smtpserverport = $ resultado->{salida}->{valor de servicio} [0];
}MÁS{
$ smtpserverport ="25";
}
}

# Bandera de autenticación SMTP
$ smtpauthflag ="0 0";
SI("$ pedido definido->{smtpauthflag} && '' ne $ solicitud->{smtpauthflag}") {
$ smtpauthflag = $ solicitud->{smtpauthflag};
}MÁS{
resultado = CONSULTA "seleccione servicevalue de tblclientservices donde servicekey = 'SMTPAuthenticationFlag'"
SI("$ resultado definido->{salida}->{valor de servicio} [0] && '' ne $ resultado->{salida}->{valor de servicio} [0]") {
$ smtpauthflag = $ resultado->{salida}->{valor de servicio} [0];
}
}

SI("$ smtpauthflag == 1") {
SI("$ pedido definido->{mailusername} && '' ne $ solicitud->{mailusername}") {

$ mailusername = $ solicitud->{mailusername};
$ mailpassword = $ solicitud->{mailpassword};

}MÁS{
resultado = CONSULTA "seleccione servicevalue de tblclientservices donde servicekey = 'MailServerUsername'"
$ mailusername = $ resultado->{salida}->{valor de servicio} [0];
resultado = CONSULTA "seleccione servicevalue de tblclientservices donde servicekey = 'MailServerPassword'"
$ mailpassword = $ resultado->{salida}->{valor de servicio} [0];
}
}MÁS{

$ mailusername = "";
$ mailpassword = "";

}
SI("$ pedido definido->{de la Dirección} && '' ne $ solicitud->{de la Dirección}") {
$ fromaddress = $ solicitud->{de la Dirección};
}MÁS{
resultado = CONSULTA "seleccione servicevalue de tblclientservices donde servicekey = 'FromAddress'"
$ fromaddress = $ resultado->{salida}->{valor de servicio} [0];
}

#Modo de seguridad
SI("$ pedido definido->{smtpsecurity} && '' ne $ solicitud->{smtpsecurity}") {
$ smtpsecurity = $ solicitud->{smtpsecurity};
}MÁS{
resultado = CONSULTA "seleccione servicevalue de tblclientservices donde servicekey = 'smtpsecurity'"
$ smtpsecurity = $ resultado->{salida}->{valor de servicio} [0];
}

$ smtpsecuritymode = 0;
SI("$ smtpsecurity eq 'STARTTLS'") {
$ smtpsecuritymode = 1;
} MÁS SI ("$ smtpsecurity eq 'SSL / TLS'") {
$ smtpsecuritymode = 2;
}

# Certificado SMTP

$ smtpcertificate = '';
$ certpassword = '';

SI("$ smtpsecuritymode! = 0") {
SI("$ pedido definido->{smtpcertificate} && '' ne $ solicitud->{smtpcertificate}") {
resultado = CONSULTA "seleccione certname, contraseña de tblvpncertificate donde certid = $ request->{smtpcertificate}"
}MÁS{
resultado = CONSULTA "seleccione certname, contraseña de tblvpncertificate donde certid = (seleccione servicevalue :: int de tblclientservices donde servicekey = 'smtpcertificate')"
}

$ smtpcertificate = $ resultado->{salida}->{certname} [0];
$ certpassword = $ resultado->{salida}->{contraseña} [0];

}

#De dirección con nombre
SI("$ pedido definido->{fromaddresswithname} && '' ne $ solicitud->{fromaddresswithname}") {
$ fromaddresswithname = $ solicitud->{fromaddresswithname};
}MÁS{
$ fromaddresswithname = $ OEMNAME . " <" . $ fromaddress . ">";
}

El código anterior hace lo mismo que el otro código operativo cuando se inicia. Inicializa variables (algunas de nosotros o del dispositivo si no se especifica).

Después de asignar las variables, se ejecuta el siguiente bloque de código.

fuera = EXECSH "/ bin / cschelper mail_send '$ fromaddress' '$ fromaddresswithname' '$ toEmail' '$ toEmail' '$ subject' '$ mailbody' '$ smtpserverhost' '$ smtpserverport' '$ mailusername' '$ mailpassword' '$ mailaction' ' $ smtpsecuritymode '' $ smtpcertificate '' $ certpassword '' 1 '' $ attachfile '"

Y ahí está, la ejecución del comando. Ahora la llamada aquí es EXECSH que llama / bin / sh -c "ARGUMENTOS". Con la ejecución que ocurre usando los valores que controlamos, podemos lograr fácilmente la ejecución remota de comandos, todo sin autenticación.

Lanzaremos un informe completo y la Prueba de concepto con los esquemas adecuados en unos pocos meses..

Actualizar: Esta investigación fue cubierta primero en TechCrunch, lea más aquí.

Brayan Jackson
Brayan Jackson Administrator
Sorry! The Author has not filled his profile.
follow me