CVE-2019-17059: Preauth-RCE i Sophos Cyberoam Explained

Vi har arbetat hårt med interna och externa säkerhetsforskare här på TheBestVPN för att upptäcka allvarliga fjärröppningsbara kryphål i SSL VPN och brandväggar som Cyberoam, Fortigate och Cisco VPN. Den här artikeln är en teknisk referens om en korrigerad kritisk sårbarhet som påverkar Cyberoam SSL VPN, även känd som CyberoamOS.

Denna Cyberoam-exploit, kallad CVE-2019-17059 är en kritisk sårbarhet som låter angripare få åtkomst till din Cyberoam-enhet utan att ange något användarnamn eller lösenord. Dessutom är den tilldelade åtkomsten den högsta nivån (root), vilket i huvudsak ger en angripare obegränsade rättigheter på din Cyberoam-enhet.

I de flesta nätverksmiljöer används Cyberoam-enheter som brandväggar och SSL VPN-gateways. Detta ger en potentiell angripare ett starkt fotfäste i ett nätverk. Det gör det lättare att attackera värdar i nätverket, och eftersom Cyberoam-enheter vanligtvis är betrodda i de flesta miljöer, ger detta en krävande attacker extra fördel.

Enligt Shodan (en sökmotor för internetanslutna enheter) finns det mer än 96 000 cyberoam-enheter från hela världen. De flesta av dessa enheter är installerade i företag, universitet och vissa i världskända banker. Detta leder till att attackerna har stora effekter på dessa miljöer.

Att arbeta med Sophos säkerhetsteam har varit en stor glädje eftersom de agerade snabbt genom att erkänna och rulla ut korrigeringar bara några dagar efter vår första rapport till dem. Kudos till dem! (Pun-avsedd!)

upptäcka Cyberoam

Och eftersom de flesta av dessa enheter är attraktiva mål för angripare, gör det felen så kritiska.

CyberoamOS Remote Oautentiserat utförande av rotkommando

CyberoamOS är ett modifierat Linux-baserat operativsystem för Cyberoam-enheter. Detta operativsystem har ett webbaserat konfigurationsgränssnitt och en SSLVPN-portal.

Webgränssnittet är uppdelat i två huvuddelar:

  • En frontend skriven i Java
  • En backend som använder en kombination av C och Perl

Vi kommer inte att dyka djupt in i internalen i front- eller back-end-koden, främst för att spara tid och begränsa mängden information som avslöjas. Men vi kommer att diskutera kort hur felet utlöses.

Både konfigurations- och SSLVPN-gränssnitten har en servlet som hanterar huvudoperationer. Dessa operationer definieras med hjälp av en parameter som heter "läge".

De flesta av dessa är autentiserade. Men det finns några alternativ vi kan komma åt utan verifiering (som inloggning).

Buggarna vi har hittat ligger i antivirus / antispam-modulen via e-post. Förfrågningsläget för denna slutpunkt (modul, op) är 458.

En sak att notera är att opkoderna mappas till deras namn i Cyberoam-databasen (intern databas Postgres). Genom att slå upp 458 kan vi ta reda på vad namnet på denna opcode är.

Här är en rad från SQL-skriptet för databasinitialisering som visar namnet opcode 458:

infoga i tblcrevent (opcode, beskrivning, läge, requesttype)
värden ('RELEASEQUARANTINEMAILFROMMAIL', 'RELEASE QUARANTINE MAIL FRA MAIL', '458', 2);

Opcode-funktionerna lagras i katalogen / _conf / csc / cscconf /. Vi kommer inte att avslöja hela koden för den sårbara funktionen, men vi kommer att tillhandahålla några utdrag som visar var och hur felet inträffar.

En kod från Java-frontend som hanterar opoden 458:

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 Konstant värde " +
CSCConstants.isCCC);

Som du kan se ovan kontrolleras några parametrar för giltighet. Om de är giltiga värden händer följande:

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

Som vi kan se ovan har vi en ny händelsekod (363) som skickas till backend. Bugg vi har upptäckt finns i koden som hanterar detta i backend.

Opoden heter sendmail, och för att undvika utnyttjande av detta fel kommer vi att redigera det mesta av koden från följande kod.

Opcode-hanteraren för send_mail.

...redigerad ...

$ param = $ begäran->{släpp};
param = DLOPEN (base64_decode, param)
LOGG-applog " Avkoda värden :: $ param \ n"
% requestData = split (/ [&=] /, $ param);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestData {hdnSender};
$ mailTo = $ requestData {hdnRecipient};
$ fil = $ QUARANTINE_PATH."/".$ RequestData {hdnFilePath};

$ Tag MAILFILE = $ requestData {hdnFilePath};
$ Validate_email ="falsk";
min $ 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 / && ((definierat $ requestData {hdnSender} && $ requestData {hdnSender} eq '') || $ requestData {hdnSender} = ~ / $ email_regex /) && index ($ requestData {hdnFilePath}, '.. /') == -1) {
$ Validate_email ="Sann";
}
.... redacted....

Som vi kan se ovan visar pseudo-Perl-koden hur backend får input från frontend ($ requestData) och hur den försöker verifiera några av de parametrar vi skickar.

Efter verifieringen, om våra parametrar är giltiga, körs följande kod:

% Mailreq = ("mailaction"=>"$ MAIL_FORWARD","ämne"=>"$ strSubject","att mejla"=>"$ mailTo","bifogad fil"=>"$ file","smtpserverhost"=>"$ mailServerHost","FROMADDRESS"=>"$ Mailfrom");

out = OPCODE mail_sender json% mailreq

Koden ovan ställer in våra förfrågningsparametrar i mailreq-variabel och kallar mail_sender-funktionen (OPCODE). Vi kommer att se hur denna opcode körs och var exakt RCE händer:

#mailaction 0 = mail_with_var, 1 = mail_forward, 2 = mail_attachment
$ Mailaction = $ begäran->{Mailaction};
$ Ämne = $ begäran->{ämne};
$ För meddelandetext = '';
$ Attachmentfile = $ begäran->{bifogad fil};
$ ToEmail = $ begäran->{att mejla};

#mail body
OM("definierade $ begäran->{För meddelandetext} && '' ne $ begäran->{För meddelandetext}") {
$ Meddelandetext = $ begäran->{För meddelandetext};
}
#SMTP-servervärd
OM("definierade $ begäran->{Smtpserverhost} && '' ne $ begäran->{Smtpserverhost}") {
$ Smtpserverhost = $ begäran->{Smtpserverhost};
}ANNAN{
resultat = QUERY "välj servicevalue från tblclientservices där servicekey = 'MailServer'"
OM("definierat $ -resultat->{produktion}->{Servicevalue} [0] && ne ne resultat->{produktion}->{Servicevalue} [0]") {
$ Smtpserverhost = $ result->{produktion}->{Servicevalue} [0];
}ANNAN{
$ Smtpserverhost ="127.0.0.1";
}
}

#SMTP-serverport
OM("definierade $ begäran->{SMTPServerPort} && '' ne $ begäran->{SMTPServerPort}") {
$ SMTPServerPort = $ begäran->{SMTPServerPort};
}ANNAN{
resultat = QUERY "välj servicevalue från tblclientservices där servicekey = 'MailServerPort'"
OM("definierat $ -resultat->{produktion}->{Servicevalue} [0] && ne ne resultat->{produktion}->{Servicevalue} [0]") {
$ SMTPServerPort = $ result->{produktion}->{Servicevalue} [0];
}ANNAN{
$ SMTPServerPort ="25";
}
}

#SMTP autorisationsflagga
$ Smtpauthflag ="0";
OM("definierade $ begäran->{Smtpauthflag} && '' ne $ begäran->{Smtpauthflag}") {
$ Smtpauthflag = $ begäran->{Smtpauthflag};
}ANNAN{
resultat = QUERY "välj servicevalue från tblclientservices där servicekey = 'SMTPAuthenticationFlag'"
OM("definierat $ -resultat->{produktion}->{Servicevalue} [0] && ne ne resultat->{produktion}->{Servicevalue} [0]") {
$ Smtpauthflag = $ result->{produktion}->{Servicevalue} [0];
}
}

OM("$ smtpauthflag == 1") {
OM("definierade $ begäran->{Mailusername} && '' ne $ begäran->{Mailusername}") {

$ Mailusername = $ begäran->{Mailusername};
$ Mailpassword = $ begäran->{Mailpassword};

}ANNAN{
resultat = QUERY "välj servicevalue från tblclientservices där servicekey = 'MailServerUsername'"
$ mailusname = $ resultat->{produktion}->{Servicevalue} [0];
resultat = QUERY "välj servicevalue från tblclientservices där servicekey = 'MailServerPassword'"
$ mailpassword = $ resultat->{produktion}->{Servicevalue} [0];
}
}ANNAN{

$ mailusname = "";
$ postpassword = "";

}
OM("definierade $ begäran->{ADDRESS} && '' ne $ begäran->{ADDRESS}") {
$ ADDRESS = $ begäran->{ADDRESS};
}ANNAN{
resultat = QUERY "välj servicevalue från tblclientservices där servicekey = 'FromAddress'"
$ fromaddress = $ resultat->{produktion}->{Servicevalue} [0];
}

#Säkerhetsläge
OM("definierade $ begäran->{Smtpsecurity} && '' ne $ begäran->{Smtpsecurity}") {
$ Smtpsecurity = $ begäran->{Smtpsecurity};
}ANNAN{
resultat = QUERY "välj servicevalue från tblclientservices där servicekey = 'smtpsecurity'"
$ smtpsecurity = $ resultat->{produktion}->{Servicevalue} [0];
}

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

#SMTP-certifikat

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

OM("$ Smtpsecuritymode! = 0") {
OM("definierade $ begäran->{Smtpcertificate} && '' ne $ begäran->{Smtpcertificate}") {
resultat = QUERY "välj certnamn, lösenord från tblvpncertificate där certid = $ begär->{Smtpcertificate}"
}ANNAN{
resultat = QUERY "välj certnamn, lösenord från tblvpncertificate där certid = (välj servicevalue :: int från tblclientservices där servicekey = 'smtpcertificate')"
}

$ smtpcertificate = $ resultat->{produktion}->{Certname} [0];
$ Certpassword = $ result->{produktion}->{Lösenord} [0];

}

# Från adress med namn
OM("definierade $ begäran->{Fromaddresswithname} && '' ne $ begäran->{Fromaddresswithname}") {
$ Fromaddresswithname = $ begäran->{Fromaddresswithname};
}ANNAN{
$ fromaddresswithname = $ OEMNAME . " <" . $ FROMADDRESS . ">";
}

Koden ovan gör samma sak som den andra opoden gjorde när den startar. Det initialiserar variabler (vissa från oss eller från enheten om de inte anges).

När variablerna har tilldelats exekveras följande kodblock.

ut = EXECSH "/ bin / cschelper mail_send '$ fromaddress' '$ fromaddresswithname' '$ toEmail' '$ toEmail' '$ subject' '$ mailbody' '$ smtpserverhost' '$ smtpserverport' '$ mailusname' '$ mailpassword' '$ mailaction' ' $ smtpsecuritymode '' $ smtpcertificate '' $ certpassword '' 1 '' $ bilaga fil"

Och där är det, exekveringen av kommandot. Nu är samtalet här EXECSH som kallar / bin / sh -c “ARGUMENTS”. När exekveringen sker med värden vi kontrollerar, kan vi enkelt uppnå exekvering av fjärrkommandon, allt utan verifiering.

Vi kommer att släppa en fullständig rapport och Proof of Concept med korrekta konturer inom några månader.

Uppdatering: Denna forskning behandlades först på TechCrunch, läs mer här.

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