CVE-2019-17059: Обяснено е Preauth-RCE в Cyberoam на Sophos

Ние работим усилено с изследователи за вътрешна и външна сигурност тук в TheBestVPN, за да разкрием сериозни дистанционно експлоатирани вратички в SSL VPN и защитни стени като Cyberoam, Fortigate и Cisco VPN. Тази статия е техническа стъпка към закърпената критична уязвимост, засягаща Cyberoam SSL VPN, известна също като CyberoamOS.


Този Cyberoam експлоатация, наречен CVE-2019-17059, е критична уязвимост, която позволява на нападателите да имат достъп до вашето устройство Cyberoam, без да предоставят потребителско име или парола. На всичкото отгоре предоставеният достъп е най-високото ниво (root), което по същество дава на атакуващия неограничени права на вашето устройство Cyberoam.

В повечето мрежови среди Cyberoam устройства се използват като защитни стени и SSL VPN шлюзи. Това дава на потенциалния нападател силна опора в мрежа. Улеснява атаката на хостове вътре в мрежата и тъй като устройствата на Cyberoam обикновено се доверяват в повечето среди, това дава допълнително предимство на евентуалния нападател.

Според Shodan (търсачка за устройства, свързани с интернет), има повече от 96 000 устройства с кибероам, обърнати към интернет от цял ​​свят. Повечето от тези устройства са инсталирани в предприятия, университети и някои в световно известни банки. Това води до атаките, които имат огромно въздействие върху тези среди.

Работата с екипа по сигурността на Sophos беше голяма наслада, тъй като те действаха бързо, като признаха и разгърнаха пластири само няколко дни след първоначалния ни доклад за тях. Кудо им! (Игра на думи, предназначени!)

откриване на Cyberoam

И тъй като повечето от тези образувания са привлекателни цели за нападателите, това прави всички бъгове по-критични.

Изпълнение на CyberoamOS Remote Neuthentication Root Command

CyberoamOS е модифицирана Linux-базирана операционна система за устройства Cyberoam. Тази ОС има уеб базиран конфигурационен интерфейс и SSLVPN портал.

Уеб интерфейсът е разделен на две основни части:

  • Фронтенд, написан на Java
  • Бекенд, който използва комбинация от C и Perl

Няма да се гмурнем дълбоко във вътрешността на предния или задния код, главно за да спестим време и да ограничим количеството разкрита информация. Но ще обсъдим накратко как се задейства грешката.

Както конфигурационните, така и SSLVPN интерфейсите имат сървлет, който обработва основните операции. Тези операции са дефинирани чрез параметър, наречен „режим“.

Повечето от тях са заверени. Но има няколко опции, до които можем да получим достъп без удостоверяване (като вход).

Намерените грешки се намират в електронния имейл антивирусен / антиспам модул. Режимът на заявка за тази крайна точка (модул, оп) е 458.

Едно нещо, което трябва да се отбележи, е, че кодовете са картографирани към техните имена в базата данни Cyberoam (вътрешна база данни Postgres). Преглеждайки 458, можем да разберем какво е името на този опкод.

Ето ред от SQL скрипта за инициализиране на базата данни, показващ името opcode 458:

вмъкнете в tblcrevent (опкод, описание, режим, тип на заявката)
стойности („RELEASEQUARANTINEMAILFROMMAIL“, „RELEASE QUARANTINE MAIL OF MAIL“, „458“, 2);

Функциите за опкод се съхраняват в директорията / _conf / csc / cscconf /. Няма да разкриваме целия код на уязвимата функция, но ще предоставим няколко фрагмента, показващи къде и как се случва грешката.

Код от Java интерфейса, който обработва опкод 458:

if ((jsonObject.getString ("hdnSender").се равнява("") ||
validateEmail (jsonObject.getString ("hdnSender"))) &&
validateEmail (jsonObject.getString ("hdnRecipient")) &&
isSafeFilePath (jsonObject.getString ("hdnFilePath")) && б) {
httpServletResponse.setContentType ("текст / HTML");
CyberoamLogger.debug ("Antivirus / AntiSpam", "CSC постоянна стойност " +
CSCConstants.isCCC);

Както можете да видите по-горе, няколко параметъра се проверяват за валидност. Ако те са валидни стойности, се случва следното:

final EventBean eventByMode = EventBean.getEventByMode (363);
... редактира.
final int sendWizardEvent = cscClient.sendWizardEvent (eventByMode, hashMap, sqlReader);

Както можем да видим по-горе, имаме нов код на събитието (363), който ще бъде изпратен към бекенда. Грешката, която открихме, е в кода, който се справя с това в бекенда.

Опкодът е наречен sendmail и за да избегнем експлоатацията на този бъг, ние ще редактираме по-голямата част от кода от следния код.

Манипулаторът на кода за send_mail.

...редактира ...

$ param = $ заявка->{Освобождаване};
param = DLOPEN (base64_decode, param)
LOG applog " Стойности за декодиране :: $ param \ n"
% requestData = split (/ [&=] /, $ парам);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestДанни {hdnSender};
$ mailTo = $ requestДанни {hdnRecipient};
$ file = $ QUARANTINE_PATH."/".$ RequestData {hdnFilePath};

$ Mailfile = $ requestData {hdnFilePath};
$ Validate_email ="фалшив";
моят $ email_regex = '^ ([\.]? [_ \ - \! \ # \ {\} \ $ \% \ ^ \&\ * \ + \ = \ |? \ \ '\\\\\\ / а-ZA-Z0-9]) * @ ([а-ZA-Z0-9] ([-] [а-zA- Z0-9] +) * \) + ([а-ZA-Z0-9] {0,6}) $. ";
if ($ requestData {hdnRecipient} = ~ / $ email_regex / && ((дефинирано $ requestData {hdnSender} && $ requestДанни {hdnSender} eq '') || $ requestДанни {hdnSender} = ~ / $ email_regex /) && индекс ($ requestData {hdnFilePath}, '.. /') == -1) {
$ Validate_email ="вярно";
}
.... редактирана....

Както можем да видим по-горе, псевдо-Perl кодът ни показва как бекендът получава вход от frontend ($ requestData) и как се опитва да провери някои от параметрите, които изпращаме.

След проверката, ако нашите параметри са валидни, се изпълнява следният код:

% Mailreq = ("mailaction"=>"$ MAIL_FORWARD","предмет"=>"$ strSubject","toEmail"=>"$ за mailto","прикачен файл"=>"$ файл","smtpserverhost"=>"$ mailServerHost","FROMADDRESS"=>"$ mailFrom");

out = OPCODE mail_sender json% mailreq

Кодът по-горе задава нашите параметри на заявката в променлива mailreq и извиква функцията mail_sender (OPCODE). Ще видим как се изпълнява този опкод и къде точно се случва RCE:

#mailaction 0 = mail_with_var, 1 = mail_forward, 2 = mail_attachment
$ Mailaction = $ поискване->{Mailaction};
$ = $ Предмет искане->{предмет};
$ Mailbody = '';
$ Attachmentfile = $ поискване->{прикачен файл};
$ ToEmail = $ поискване->{ToEmail};

#mail body
IF ("дефинирана $ заявка->{Mailbody} && '' ne $ заявка->{Mailbody}") {
$ Mailbody = $ поискване->{Mailbody};
}
#SMTP сървър хост
IF ("дефинирана $ заявка->{Smtpserverhost} && '' ne $ заявка->{Smtpserverhost}") {
$ Smtpserverhost = $ поискване->{Smtpserverhost};
} Още {
резултат = QUERY "изберете servicevalue от tblclientservices, където servicekey = 'MailServer'"
IF ("определен $ резултат->{Изход}->{Servicevalue} [0] && '' ne $ резултат->{Изход}->{Servicevalue} [0]") {
$ Smtpserverhost = $ резултат->{Изход}->{Servicevalue} [0];
} Още {
$ Smtpserverhost ="127.0.0.1";
}
}

#SMTP сървър порт
IF ("дефинирана $ заявка->{Smtpserverport} && '' ne $ заявка->{Smtpserverport}") {
$ Smtpserverport = $ поискване->{Smtpserverport};
} Още {
резултат = QUERY "изберете сервизна стойност от tblclientservices, където servicekey = 'MailServerPort'"
IF ("определен $ резултат->{Изход}->{Servicevalue} [0] && '' ne $ резултат->{Изход}->{Servicevalue} [0]") {
$ Smtpserverport = $ резултат->{Изход}->{Servicevalue} [0];
} Още {
$ Smtpserverport ="25";
}
}

#SMTP автентичен флаг
$ Smtpauthflag ="0";
IF ("дефинирана $ заявка->{Smtpauthflag} && '' ne $ заявка->{Smtpauthflag}") {
$ Smtpauthflag = $ поискване->{Smtpauthflag};
} Още {
резултат = QUERY "изберете servicevalue от tblclientservices, където servicekey = 'SMTPAuthenticationFlag'"
IF ("определен $ резултат->{Изход}->{Servicevalue} [0] && '' ne $ резултат->{Изход}->{Servicevalue} [0]") {
$ Smtpauthflag = $ резултат->{Изход}->{Servicevalue} [0];
}
}

IF ("$ smtpauthflag == 1") {
IF ("дефинирана $ заявка->{Mailusername} && '' ne $ заявка->{Mailusername}") {

$ Mailusername = $ поискване->{Mailusername};
$ Mailpassword = $ поискване->{Mailpassword};

} Още {
резултат = QUERY "изберете servicevalue от tblclientservices, където servicekey = 'MailServerUsername'"
$ mailusername = $ резултат->{Изход}->{Servicevalue} [0];
резултат = QUERY "изберете servicevalue от tblclientservices, където servicekey = 'MailServerPassword'"
$ mailpassword = $ резултат->{Изход}->{Servicevalue} [0];
}
} Още {

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

}
IF ("дефинирана $ заявка->{FROMADDRESS} && '' ne $ заявка->{FROMADDRESS}") {
$ FROMADDRESS = $ поискване->{FROMADDRESS};
} Още {
резултат = QUERY "изберете servicevalue от tblclientservices, където servicekey = 'FromAddress'"
$ fromaddress = $ резултат->{Изход}->{Servicevalue} [0];
}

# Защитен режим
IF ("дефинирана $ заявка->{Smtpsecurity} && '' ne $ заявка->{Smtpsecurity}") {
$ Smtpsecurity = $ поискване->{Smtpsecurity};
} Още {
резултат = QUERY "изберете сервизна стойност от tblclientservices, където servicekey = 'smtpsecurity'"
$ smtpsecurity = $ резултат->{Изход}->{Servicevalue} [0];
}

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

#SMTP сертификат

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

IF ("$ Smtpsecuritymode! = 0") {
IF ("дефинирана $ заявка->{Smtpcertificate} && '' ne $ заявка->{Smtpcertificate}") {
резултат = QUERY "изберете certname, парола от tblvpncertificate където certid = $ заявка->{Smtpcertificate}"
} Още {
резултат = QUERY "изберете certname, парола от tblvpncertificate където certid = (изберете servicevalue :: int от tblclientservices където servicekey = 'smtpcertificate')"
}

$ smtpcertificate = $ резултат->{Изход}->{Certname} [0];
$ Certpassword = $ резултат->{Изход}->{Парола} [0];

}

# От адрес с име
IF ("дефинирана $ заявка->{Fromaddresswithname} && '' ne $ заявка->{Fromaddresswithname}") {
$ Fromaddresswithname = $ поискване->{Fromaddresswithname};
} Още {
$ fromaddresswithname = $ OEMNAME . " <" . $ FROMADDRESS . ">";
}

Кодът по-горе прави същото, което направи и другият код, когато стартира. Той инициализира променливи (някои от нас или от устройството, ако не са посочени).

След присвояването на променливите се изпълнява следният кодов блок.

вън = ИЗЛОЖИТЕ "/ bin / cschelper mail_send '$ fromaddress' '$ fromaddresswithname' '$ toEmail' '$ toEmail' '$ subject' '$ mailbody' '$ smtpserverhost' '$ smtpserverport' '$ mailusername' '$ mailpassword' '$ mailaction' ' $ smtpsecuritymode '' $ smtpcertificate '' $ certpassword '' 1 '' $ attachmentfile '"

И ето го, изпълнението на командата. Сега обаждането тук е EXECSH което извиква / bin / sh -c „АРГУМЕНТИ“. С изпълнението, случващо се с помощта на стойности, които контролираме, можем лесно да постигнем отдалечено изпълнение на команда, всички без удостоверяване.

Ще пуснем пълен доклад и доказателството за концепцията с правилни очертания след няколко месеца.

Update: Това изследване беше разгледано първо на TechCrunch, прочетете повече тук.

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