CVE-2019-17059: Preauth-RCE in Sophos ‘Cyberoam erklärt

Wir haben hier bei TheBestVPN intensiv mit internen und externen Sicherheitsforschern zusammengearbeitet, um schwerwiegende Sicherheitslücken in SSL-VPNs und Firewalls wie Cyberoam-, Fortigate- und Cisco-VPNs aufzudecken. Bei diesem Artikel handelt es sich um eine technische Einführung in eine korrigierte kritische Sicherheitsanfälligkeit, die Cyberoam SSL VPN, auch bekannt als CyberoamOS, betrifft.


Dieser Cyberoam-Exploit, CVE-2019-17059 genannt, ist eine kritische Sicherheitsanfälligkeit, mit der Angreifer ohne Angabe eines Benutzernamens oder Kennworts auf Ihr Cyberoam-Gerät zugreifen können. Darüber hinaus ist der gewährte Zugriff die höchste Ebene (Root), die einem Angreifer im Wesentlichen uneingeschränkte Rechte auf Ihrem Cyberoam-Gerät gewährt.

In den meisten Netzwerkumgebungen werden Cyberoam-Geräte als Firewalls und SSL-VPN-Gateways verwendet. Dies gibt einem potenziellen Angreifer einen starken Halt in einem Netzwerk. Dies erleichtert das Angreifen von Hosts innerhalb des Netzwerks. Da Cyberoam-Geräte in den meisten Umgebungen als vertrauenswürdig eingestuft werden, bietet dies einem potenziellen Angreifer einen zusätzlichen Vorteil.

Laut Shodan (einer Suchmaschine für internetfähige Geräte) gibt es weltweit mehr als 96.000 internetfähige Cyberoam-Geräte. Die meisten dieser Geräte werden in Unternehmen, Universitäten und einigen weltweit bekannten Banken installiert. Dies führt dazu, dass die Angriffe große Auswirkungen auf diese Umgebungen haben.

Die Zusammenarbeit mit dem Sicherheitsteam von Sophos war eine große Freude, da das Team bereits wenige Tage nach dem ersten Bericht an das Sicherheitsteam Patches bestätigte und einführte. Ein großes Lob an sie! (Wortspiel beabsichtigt!)

Cyberoam erkennen

Und da die meisten dieser Einheiten attraktive Ziele für Angreifer sind, sind die Bugs umso kritischer.

CyberoamOS Remote-Ausführung nicht authentifizierter Root-Befehle

Das CyberoamOS ist ein modifiziertes Linux-basiertes Betriebssystem für Cyberoam-Geräte. Dieses Betriebssystem verfügt über eine webbasierte Konfigurationsoberfläche und ein SSLVPN-Portal.

Das Webinterface ist in zwei Hauptteile unterteilt:

  • Ein in Java geschriebenes Frontend
  • Ein Backend, das eine Kombination aus C und Perl verwendet

Wir werden nicht tief in die Interna des Front- oder Back-End-Codes eintauchen, hauptsächlich um Zeit zu sparen und die Menge an Informationen zu begrenzen. Wir werden aber kurz diskutieren, wie der Fehler ausgelöst wird.

Sowohl die Konfigurations- als auch die SSLVPN-Schnittstelle verfügen über ein Servlet, das die Hauptoperationen abwickelt. Diese Operationen werden mit einem Parameter namens "mode" definiert..

Die meisten davon sind authentifiziert. Aber es gibt ein paar Operationen, auf die wir ohne Authentifizierung zugreifen können (wie Login).

Die gefundenen Fehler liegen im E-Mail-Antivirus- / Antispam-Modul. Der Anforderungsmodus für diesen Endpunkt (Modul, op) ist 458.

Zu beachten ist, dass die Opcodes ihren Namen in der Cyberoam-Datenbank (interne Datenbank Postgres) zugeordnet sind. Wenn wir nach 458 suchen, können wir herausfinden, wie dieser Opcode heißt.

Hier ist eine Zeile aus dem SQL-Skript zur Datenbankinitialisierung mit dem Namen opcode 458:

in tblcrevent einfügen (Opcode, Beschreibung, Modus, Anfragetyp)
Werte ('RELEASEQUARANTINEMAILFROMMAIL', 'RELEASE QUARANTINE MAIL FROM MAIL', '458', 2);

Die Opcode-Funktionen werden im Verzeichnis / _conf / csc / cscconf / gespeichert. Wir werden nicht den gesamten Code der anfälligen Funktion enthüllen, aber wir werden ein paar Schnipsel bereitstellen, die zeigen, wo und wie der Fehler auftritt.

Ein Code aus dem Java-Frontend, der den Opcode 458 verarbeitet:

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

Wie Sie oben sehen können, werden einige Parameter auf Gültigkeit überprüft. Wenn es sich um gültige Werte handelt, geschieht Folgendes:

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

Wie wir oben sehen können, haben wir einen neuen Event-Code (363), der an das Backend gesendet wird. Der Fehler, den wir entdeckt haben, befindet sich im Code, der dies im Backend behandelt.

Der Opcode heißt sendmail, und um die Ausbeutung dieses Fehlers zu vermeiden, werden wir den größten Teil des Codes aus dem folgenden Code redigieren.

Der Opcode-Handler für send_mail.

...überarbeitet ...

$ param = $ request->{Freisetzung};
param = DLOPEN (base64_decode, param)
LOG Applog " Dekodiere Werte :: $ param \ n"
% requestData = split (/ [&=] /, $ param);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestData {hdnSender};
$ mailTo = $ requestData {hdnRecipient};
$ file = $ QUARANTINE_PATH."/".$ requestData {hdnFilePath};

$ mailfile = $ requestData {hdnFilePath};
$ validate_email ="falsch";
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 / && ((defined $ requestData {hdnSender} && $ requestData {hdnSender} eq '') || $ requestData {hdnSender} = ~ / $ email_regex /) && index ($ requestData {hdnFilePath}, '.. /') == -1) {
$ validate_email ="wahr";
}
.... redigiert....

Wie wir oben sehen können, zeigt uns der Pseudo-Perl-Code, wie das Backend Eingaben vom Frontend ($ requestData) empfängt und wie es versucht, einige der von uns gesendeten Parameter zu überprüfen.

Nach der Überprüfung wird der folgende Code ausgeführt, wenn unsere Parameter gültig sind:

% mailreq = ("mailaction"=>"$ MAIL_FORWARD","Gegenstand"=>"$ strSubject","eine E-Mail schicken"=>"$ mailTo","Anhangsdatei"=>"$ file","smtpserverhost"=>"$ mailServerHost","von der Adresse"=>"$ mailFrom");

out = OPCODE mail_sender json% mailreq

Der obige Code setzt unsere Anforderungsparameter in die Variable mailreq und ruft die Funktion mail_sender (OPCODE) auf. Wir werden sehen, wie dieser Opcode ausgeführt wird und wo genau der RCE passiert:

#mailaction 0 = mail_with_var, 1 = mail_forward, 2 = mail_attachment
$ mailaction = $ request->{mailaction};
$ subject = $ request->{Gegenstand};
$ mailbody = '';
$ attachmentfile = $ request->{Anhangsdatei};
$ toEmail = $ request->{eine E-Mail schicken};

#mail body
WENN("definierte $ Anfrage->{mailbody} && '' ne $ Anfrage->{mailbody}") {
$ mailbody = $ request->{mailbody};
}
#SMTP-Serverhost
WENN("definierte $ Anfrage->{smtpserverhost} && '' ne $ Anfrage->{smtpserverhost}") {
$ smtpserverhost = $ request->{smtpserverhost};
}SONST{
Ergebnis = QUERY "Wählen Sie servicevalue von tblclientservices aus, wobei servicekey = 'MailServer' ist."
WENN("definiertes $ Ergebnis->{Ausgabe}->{servicevalue} [0] && '' ne $ ergebnis->{Ausgabe}->{servicevalue} [0]") {
$ smtpserverhost = $ result->{Ausgabe}->{servicevalue} [0];
}SONST{
$ smtpserverhost ="127.0.0.1";
}
}

#SMTP-Serverport
WENN("definierte $ Anfrage->{smtpserverport} && '' ne $ Anfrage->{smtpserverport}") {
$ smtpserverport = $ request->{smtpserverport};
}SONST{
Ergebnis = QUERY "Wählen Sie servicevalue von tblclientservices aus, wobei servicekey = 'MailServerPort' ist."
WENN("definiertes $ Ergebnis->{Ausgabe}->{servicevalue} [0] && '' ne $ ergebnis->{Ausgabe}->{servicevalue} [0]") {
$ smtpserverport = $ result->{Ausgabe}->{servicevalue} [0];
}SONST{
$ smtpserverport ="25";
}
}

#SMTP Auth Flag
$ smtpauthflag ="0";
WENN("definierte $ Anfrage->{smtpauthflag} && '' ne $ Anfrage->{smtpauthflag}") {
$ smtpauthflag = $ request->{smtpauthflag};
}SONST{
Ergebnis = QUERY "Wählen Sie servicevalue aus tblclientservices aus, wobei servicekey = 'SMTPAuthenticationFlag' ist."
WENN("definiertes $ Ergebnis->{Ausgabe}->{servicevalue} [0] && '' ne $ ergebnis->{Ausgabe}->{servicevalue} [0]") {
$ smtpauthflag = $ result->{Ausgabe}->{servicevalue} [0];
}
}

WENN("$ smtpauthflag == 1") {
WENN("definierte $ Anfrage->{mailusername} && '' ne $ Anfrage->{mailusername}") {

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

}SONST{
Ergebnis = QUERY "Wählen Sie servicevalue aus tblclientservices aus, wobei servicekey = 'MailServerUsername' ist."
$ mailusername = $ result->{Ausgabe}->{servicevalue} [0];
Ergebnis = QUERY "Wählen Sie servicevalue aus tblclientservices, wobei servicekey = 'MailServerPassword' ist."
$ mailpassword = $ result->{Ausgabe}->{servicevalue} [0];
}
}SONST{

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

}
WENN("definierte $ Anfrage->{von der Adresse} && '' ne $ Anfrage->{von der Adresse}") {
$ fromaddress = $ request->{von der Adresse};
}SONST{
Ergebnis = QUERY "Wählen Sie servicevalue aus tblclientservices aus, wobei servicekey = 'FromAddress' ist."
$ fromaddress = $ result->{Ausgabe}->{servicevalue} [0];
}

#Sicherheitsmodus
WENN("definierte $ Anfrage->{smtpsecurity} && '' ne $ Anfrage->{smtpsecurity}") {
$ smtpsecurity = $ request->{smtpsecurity};
}SONST{
Ergebnis = QUERY "Wählen Sie servicevalue aus tblclientservices aus, wobei servicekey = 'smtpsecurity' ist."
$ smtpsecurity = $ result->{Ausgabe}->{servicevalue} [0];
}

$ smtpsecuritymode = 0;
WENN("$ smtpsecurity eq 'STARTTLS'") {
$ smtpsecuritymode = 1;
} ELSE IF ("$ smtpsecurity eq 'SSL / TLS'") {
$ smtpsecuritymode = 2;
}

#SMTP-Zertifikat

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

WENN("$ smtpsecuritymode! = 0") {
WENN("definierte $ Anfrage->{smtpcertificate} && '' ne $ Anfrage->{smtpcertificate}") {
Ergebnis = QUERY "Wählen Sie den Zertifikatsnamen und das Kennwort aus tblvpncertificate aus, wobei certid = $ request ist->{smtpcertificate}"
}SONST{
Ergebnis = QUERY "Wählen Sie den Zertifikatsnamen und das Kennwort aus tblvpncertificate, wobei certid = (Wählen Sie servicevalue :: int aus tblclientservices, wobei servicekey = 'smtpcertificate')."
}

$ smtpcertificate = $ result->{Ausgabe}->{certname} [0];
$ certpassword = $ result->{Ausgabe}->{password} [0];

}

#Von Adresse mit Name
WENN("definierte $ Anfrage->{fromaddresswithname} && '' ne $ Anfrage->{fromaddresswithname}") {
$ fromaddresswithname = $ request->{fromaddresswithname};
}SONST{
$ fromaddresswithname = $ OEMNAME . " <" . $ fromaddress . ">";
}

Der obige Code macht dasselbe wie der andere Opcode, als er gestartet wurde. Es initialisiert Variablen (einige von uns oder vom Gerät, wenn nicht anders angegeben).

Nachdem die Variablen zugewiesen wurden, wird der folgende Codeblock ausgeführt.

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

Und da ist es, die Befehlsausführung. Jetzt heißt der Aufruf hier EXECSH und ruft / bin / sh -c "ARGUMENTS" auf. Wenn die Ausführung mithilfe von Werten erfolgt, die wir steuern, können wir die Ausführung von Fernbefehlen ohne Authentifizierung problemlos erreichen.

In wenigen Monaten werden wir einen vollständigen Bericht und den Proof of Concept mit den richtigen Umrissen veröffentlichen.

Aktualisieren: Diese Forschung wurde zuerst auf TechCrunch behandelt, lesen Sie hier mehr.

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