CVE-2019-17059: Preauth-RCE in Sophos ’Cyberoam Explained

We hebben hard gewerkt met interne en externe beveiligingsonderzoekers hier bij TheBestVPN om serieuze op afstand exploiteerbare mazen in SSL VPN's en firewalls zoals Cyberoam, Fortigate en Cisco VPN's aan het licht te brengen. Dit artikel is een technisch onderwerp over een gepatchte kritieke kwetsbaarheid die Cyberoam SSL VPN treft, ook bekend als CyberoamOS.

Dit Cyberoam-exploit, CVE-2019-17059 genoemd, is een kritieke kwetsbaarheid waarmee aanvallers toegang krijgen tot uw Cyberoam-apparaat zonder een gebruikersnaam of wachtwoord op te geven. Bovendien is de verleende toegang het hoogste niveau (root), wat in wezen een aanvaller onbeperkte rechten op uw Cyberoam-apparaat geeft.

In de meeste netwerkomgevingen worden Cyberoam-apparaten gebruikt als firewalls en SSL VPN-gateways. Dit geeft een potentiële aanvaller een sterke positie in een netwerk. Het maakt het eenvoudiger om hosts binnen het netwerk aan te vallen, en omdat Cyberoam-apparaten meestal in de meeste omgevingen worden vertrouwd, geeft dit een potentiële aanvaller extra voorsprong.

Volgens Shodan (een zoekmachine voor apparaten met internetverbinding) zijn er meer dan 96.000 internetgerichte Cyberoam-apparaten van over de hele wereld. De meeste van deze apparaten worden geïnstalleerd in ondernemingen, universiteiten en sommige in wereldberoemde banken. Dit heeft tot gevolg dat de aanvallen grote gevolgen hebben voor deze omgevingen.

De samenwerking met het beveiligingsteam van Sophos was een groot genoegen omdat ze snel reageerden door patches te herkennen en uit te rollen slechts enkele dagen na ons eerste rapport aan hen. Een pluim voor hen! (woordspeling bedoeld!)

Cyberoam detecteren

En omdat de meeste van deze entiteiten aantrekkelijke doelwitten zijn voor aanvallers, worden de bugs des te kritischer.

CyberoamOS Remote Niet-geverifieerde uitvoering van rootopdrachten

De CyberoamOS is een aangepast op Linux gebaseerd besturingssysteem voor Cyberoam-apparaten. Dit besturingssysteem heeft een webgebaseerde configuratie-interface en een SSLVPN-portal.

De webinterface is verdeeld in twee hoofddelen:

  • Een frontend geschreven in Java
  • Een backend die een combinatie van C en Perl gebruikt

We zullen niet diep ingaan op de binnenkant van de front- of back-end code, vooral om tijd te besparen en de hoeveelheid onthulde informatie te beperken. Maar we zullen kort bespreken hoe de bug wordt geactiveerd.

Zowel de configuratie als SSLVPN-interfaces hebben een servlet die de hoofdbewerkingen afhandelt. Deze bewerkingen worden gedefinieerd met behulp van een parameter met de naam "modus".

De meeste hiervan zijn geverifieerd. Maar er zijn een paar operaties waartoe we toegang hebben zonder authenticatie (zoals inloggen).

De gevonden bugs liggen in de e-mail antivirus / antispam-module. De verzoekmodus voor dit eindpunt (module, op) is 458.

Een ding om op te merken is dat de opcodes zijn toegewezen aan hun namen in de Cyberoam-database (interne database Postgres). Door 458 op te zoeken, kunnen we ontdekken wat de naam van deze opcode is.

Hier is een regel uit het SQL-script voor initialisatie van de database met de naam opcode 458:

invoegen in tblcrevent (opcode, beschrijving, modus, verzoektype)
waarden ('RELEASEQUARANTINEMAILFROMMAIL', 'RELEASE QUARANTINE MAIL VAN MAIL', '458', 2);

De opcode-functies worden opgeslagen in de map / _conf / csc / cscconf /. We zullen niet de hele code van de kwetsbare functie onthullen, maar we zullen een paar fragmenten geven die laten zien waar en hoe de bug optreedt.

Een code van de Java-frontend die de opcode 458 verwerkt:

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 constante waarde " +
CSCConstants.isCCC);

Zoals u hierboven kunt zien, worden enkele parameters op geldigheid gecontroleerd. Als het geldige waarden zijn, gebeurt het volgende:

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

Zoals we hierboven kunnen zien, hebben we een nieuwe gebeurteniscode (363) die naar de backend wordt verzonden. De bug die we hebben ontdekt, zit in de code die dit in de backend afhandelt.

De opcode heeft de naam sendmail, en om misbruik van deze bug te voorkomen, zullen we de meeste code van de volgende code redacteren.

De opcode-handler voor send_mail.

...geredigeerd ...

$ param = $ verzoek->{vrijlating};
param = DLOPEN (base64_decode, param)
LOG-applog " Decodeer waarden :: $ param \ n"
% requestData = split (/ [&=] /, $ param);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestData {hdnSender};
$ mailTo = $ requestData {hdnRecipient};
$ file = $ QUARANTINE_PATH."/".$ RequestData {hdnFilePath};

$ Mailfile = $ requestData {hdnFilePath};
$ Validate_email ="vals";
mijn $ 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 / && ((gedefinieerd $ requestData {hdnSender} && $ requestData {hdnSender} eq '') || $ requestData {hdnSender} = ~ / $ email_regex /) && index ($ requestData {hdnFilePath}, '.. /') == -1) {
$ Validate_email ="waar";
}
.... geredigeerd....

Zoals we hierboven kunnen zien, laat de pseudo-Perl-code ons zien hoe de backend invoer ontvangt van de frontend ($ requestData) en hoe het probeert enkele van de parameters die we verzenden te verifiëren..

Na de verificatie, als onze parameters geldig zijn, wordt de volgende code uitgevoerd:

% Mailreq = ("mailaction"=>"$ MAIL_FORWARD","onderwerpen"=>"$ strSubject","emailen"=>"$ mailto","bijlage"=>"$ file","smtpserverhost"=>"$ mailServerHost","FROMADDRESS"=>"$ mailin");

out = OPCODE mail_sender json% mailreq

De bovenstaande code zet onze verzoekparameters in de variabele mailreq en roept de functie mail_sender (OPCODE) aan. We zullen zien hoe deze opcode wordt uitgevoerd en waar precies de RCE gebeurt:

#mailaction 0 = mail_with_var, 1 = mail_forward, 2 = mail_attachment
$ Mailaction = $ verzoek->{Mailaction};
$ Subject = $ verzoek->{onderwerpen};
$ Het e-mailbericht = '';
$ Attachmentfile = $ verzoek->{bijlage};
$ ToEmail = $ verzoek->{emailen};

#mail body
ALS("$ verzoek gedefinieerd->{} Het e-mailbericht && '' $ verzoek->{} Het e-mailbericht") {
$ Het e-mailbericht = $ verzoek->{} Het e-mailbericht;
}
#SMTP-serverhost
ALS("$ verzoek gedefinieerd->{} Smtpserverhost && '' $ verzoek->{} Smtpserverhost") {
$ Smtpserverhost = $ verzoek->{Smtpserverhost};
}ANDERS{
result = QUERY "selecteer servicevalue van tblclientservices waarbij servicekey = 'MailServer'"
ALS("gedefinieerd $ resultaat->{Uitgang}->{Servicevalue} [0] && 'n $ resultaat->{Uitgang}->{Servicevalue} [0]") {
$ Smtpserverhost = $ result->{Uitgang}->{Servicevalue} [0];
}ANDERS{
$ Smtpserverhost ="127.0.0.1";
}
}

#SMTP-serverpoort
ALS("$ verzoek gedefinieerd->{} Smtpserverport && '' $ verzoek->{} Smtpserverport") {
$ Smtpserverport = $ verzoek->{Smtpserverport};
}ANDERS{
result = QUERY "selecteer servicevalue van tblclientservices waarbij servicekey = 'MailServerPort'"
ALS("gedefinieerd $ resultaat->{Uitgang}->{Servicevalue} [0] && 'n $ resultaat->{Uitgang}->{Servicevalue} [0]") {
$ Smtpserverport = $ result->{Uitgang}->{Servicevalue} [0];
}ANDERS{
$ Smtpserverport ="25";
}
}

#SMTP auth vlag
$ Smtpauthflag ="0";
ALS("$ verzoek gedefinieerd->{} Smtpauthflag && '' $ verzoek->{} Smtpauthflag") {
$ Smtpauthflag = $ verzoek->{Smtpauthflag};
}ANDERS{
result = QUERY "selecteer servicevalue van tblclientservices waarbij servicekey = 'SMTPAuthenticationFlag'"
ALS("gedefinieerd $ resultaat->{Uitgang}->{Servicevalue} [0] && 'n $ resultaat->{Uitgang}->{Servicevalue} [0]") {
$ Smtpauthflag = $ result->{Uitgang}->{Servicevalue} [0];
}
}

ALS("$ smtpauthflag == 1") {
ALS("$ verzoek gedefinieerd->{} Mailusername && '' $ verzoek->{} Mailusername") {

$ Mailusername = $ verzoek->{Mailusername};
$ Mailpassword = $ verzoek->{Mailpassword};

}ANDERS{
result = QUERY "selecteer servicevalue van tblclientservices waarbij servicekey = 'MailServerUsername'"
$ mailusername = $ resultaat->{Uitgang}->{Servicevalue} [0];
result = QUERY "selecteer servicevalue van tblclientservices waarbij servicekey = 'MailServerPassword'"
$ mailpassword = $ result->{Uitgang}->{Servicevalue} [0];
}
}ANDERS{

$ mailgebruikersnaam = "";
$ mailpassword = "";

}
ALS("$ verzoek gedefinieerd->{} FROMADDRESS && '' $ verzoek->{} FROMADDRESS") {
$ FROMADDRESS = $ verzoek->{FROMADDRESS};
}ANDERS{
result = QUERY "selecteer servicevalue van tblclientservices waarbij servicekey = 'FromAddress'"
$ fromaddress = $ result->{Uitgang}->{Servicevalue} [0];
}

#Veiligheidsmodus
ALS("$ verzoek gedefinieerd->{} Smtpsecurity && '' $ verzoek->{} Smtpsecurity") {
$ Smtpsecurity = $ verzoek->{Smtpsecurity};
}ANDERS{
result = QUERY "selecteer servicevalue van tblclientservices waarbij servicekey = 'smtpsecurity'"
$ smtpsecurity = $ resultaat->{Uitgang}->{Servicevalue} [0];
}

$ Smtpsecuritymode = 0;
ALS("$ smtpsecurity eq 'STARTTLS'") {
$ Smtpsecuritymode = 1;
} ANDERE ALS ("$ smtpsecurity eq 'SSL / TLS'") {
$ Smtpsecuritymode = 2;
}

#SMTP-certificaat

$ smtpcertificate = '';
$ Certpassword = '';

ALS("$ Smtpsecuritymode! = 0") {
ALS("$ verzoek gedefinieerd->{} Smtpcertificate && '' $ verzoek->{} Smtpcertificate") {
result = QUERY "selecteer certnaam, wachtwoord van tblvpncertificate waarbij certid = $ aanvraag->{} Smtpcertificate"
}ANDERS{
result = QUERY "selecteer certnaam, wachtwoord van tblvpncertificate where certid = (selecteer servicevalue :: int van tblclientservices where servicekey = 'smtpcertificate')"
}

$ smtpcertificate = $ resultaat->{Uitgang}->{Certname} [0];
$ Certpassword = $ result->{Uitgang}->{Password} [0];

}

#Van adres met naam
ALS("$ verzoek gedefinieerd->{} Fromaddresswithname && '' $ verzoek->{} Fromaddresswithname") {
$ Fromaddresswithname = $ verzoek->{Fromaddresswithname};
}ANDERS{
$ fromaddresswithname = $ OEMNAME . " <" . $ FROMADDRESS . ">";
}

De bovenstaande code doet hetzelfde als de andere opcode deed toen het startte. Het initialiseert variabelen (sommige van ons of van het apparaat indien niet gespecificeerd).

Nadat de variabelen zijn toegewezen, wordt het volgende codeblok uitgevoerd.

uit = EXECSH "/ bin / cschelper mail_send '$ fromaddress' '$ fromaddresswithname' '$ toEmail' '$ toEmail' '$ subject' '$ mailbody' '$ smtpserverhost' '$ smtpserverport' '$ mailgebruikersnaam' '$ mailwachtwoord' '$ mailaction' ' $ smtpsecuritymode '' $ smtpcertificate '' $ certpassword '' 1 '' $ attachmentfile '"

En daar is het dan, de opdrachtuitvoering. Nu is de oproep hier EXECSH die / bin / sh -c "ARGUMENTEN" aanroept. Omdat de uitvoering gebeurt met behulp van waarden die we beheren, kunnen we gemakkelijk externe opdrachtuitvoering uitvoeren, allemaal zonder authenticatie.

We zullen binnen enkele maanden een volledig rapport en het Proof of Concept uitbrengen met de juiste contouren.

Bijwerken: Dit onderzoek werd eerst behandeld op TechCrunch, lees hier meer.

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