CVE-2019-17059: Wyjaśnienie Preauth-RCE w Cyberoamie Sophosa

Ciężko pracujemy z wewnętrznymi i zewnętrznymi badaczami bezpieczeństwa w TheBestVPN, aby odkryć poważne luki zdalnie nadające się do wykorzystania w SSL VPN i zaporach ogniowych, takich jak Cyberoam, Fortigate i Cisco VPN. Ten artykuł jest technicznym omówieniem poprawionej krytycznej luki w zabezpieczeniach Cyberoam SSL VPN znanej również jako CyberoamOS.

Ten exploit Cyberoam, nazwany CVE-2019-17059, jest krytyczną luką, która umożliwia atakującym dostęp do twojego urządzenia Cyberoam bez podawania nazwy użytkownika ani hasła. Ponadto przyznany dostęp to najwyższy poziom (root), który zasadniczo daje atakującemu nieograniczone prawa na twoim urządzeniu Cyberoam.

W większości środowisk sieciowych urządzenia Cyberoam są używane jako zapory ogniowe i bramy SSL VPN. Daje to potencjalnemu napastnikowi silną pozycję w sieci. Ułatwia atakowanie hostów w sieci, a ponieważ urządzenia Cyberoam są zwykle zaufane w większości środowisk, daje to potencjalnemu napastnikowi dodatkową przewagę.

Według Shodana (wyszukiwarki urządzeń podłączonych do Internetu) istnieje ponad 96 000 internetowych urządzeń Cyberoam z całego świata. Większość tych urządzeń jest instalowana w przedsiębiorstwach, uniwersytetach, a niektóre w renomowanych bankach. Prowadzi to do tego, że ataki mają ogromny wpływ na te środowiska.

Praca z zespołem bezpieczeństwa Sophos była ogromną przyjemnością, ponieważ działali szybko, potwierdzając i wdrażając łatki zaledwie kilka dni po naszym pierwszym raporcie do nich. Uznanie dla nich! (zamierzone!)

wykrywanie Cyberoamu

A ponieważ większość tych podmiotów jest atrakcyjnym celem dla atakujących, błędy są tym bardziej krytyczne.

Zdalne nieuwierzytelnione polecenie root w CyberoamOS

CyberoamOS to zmodyfikowany system operacyjny Linux dla urządzeń Cyberoam. Ten system operacyjny ma internetowy interfejs konfiguracyjny i portal SSLVPN.

Interfejs internetowy jest podzielony na dwie główne części:

  • Frontend napisany w Javie
  • Backend, który wykorzystuje kombinację C i Perla

Nie będziemy zagłębiać się głęboko w wewnętrzne elementy kodu front-end lub back-end, głównie w celu zaoszczędzenia czasu i ograniczenia ilości ujawnianych informacji. Ale omówimy pokrótce, jak wywoływany jest błąd.

Zarówno konfiguracja, jak i interfejsy SSLVPN mają serwlet obsługujący główne operacje. Te operacje są definiowane za pomocą parametru o nazwie „mode”.

Większość z nich jest uwierzytelniona. Ale jest kilka operacji, do których możemy uzyskać dostęp bez uwierzytelniania (np. Logowanie).

Znalezione przez nas błędy dotyczą modułu antywirusowego / antyspamowego. Tryb żądania dla tego punktu końcowego (moduł, op) to 458.

Należy zauważyć, że kody operacyjne są mapowane na ich nazwy w bazie danych Cyberoam (wewnętrzna baza danych Postgres). Patrząc w górę 458, możemy dowiedzieć się, jak nazywa się ten kod operacji.

Oto wiersz ze skryptu SQL inicjującego bazę danych pokazujący nazwę opcode 458:

wstaw do tblcrevent (kod operacji, opis, tryb, typ zapytania)
wartości („RELEASEQUARANTINEMAILFROMMAIL”, „RELEASE QUARANTINE MAIL FROM MAIL”, „458”, 2);

Funkcje opcode są przechowywane w katalogu / _conf / csc / cscconf /. Nie ujawnimy całego kodu podatnej na uszkodzenia funkcji, ale udostępnimy kilka fragmentów pokazujących, gdzie i jak występuje błąd.

Kod z interfejsu Java, który obsługuje kod operacji 458:

if ((jsonObject.getString ("hdnSender").równa się("") ||
validateEmail (jsonObject.getString ("hdnSender"))) &&
validateEmail (jsonObject.getString ("hdnRecipient")) &&
isSafeFilePath (jsonObject.getString ("hdnFilePath")) && b) {
httpServletResponse.setContentType ("text / html");
CyberoamLogger.debug ("Antywirus / AntiSpam", "CSC Wartość stała " +
CSCConstants.isCCC);

Jak widać powyżej, kilka parametrów jest sprawdzanych pod kątem ważności. Jeśli są to prawidłowe wartości, dzieje się tak:

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

Jak widać powyżej, mamy nowy kod zdarzenia (363), który zostanie wysłany do wewnętrznej bazy danych. Wykryty przez nas błąd znajduje się w kodzie, który obsługuje to w wewnętrznej bazie danych.

Kod operacyjny nazywa się sendmail i aby uniknąć wykorzystania tego błędu, będziemy redagować większość kodu z następującego kodu.

Program obsługi kodu op dla send_mail.

...zredagowane ...

$ param = $ żądanie->{wydanie};
param = DLOPEN (base64_decode, param)
LOG aplikacji " Dekoduj wartości :: $ param \ n"
% requestData = split (/ [&=] /, $ param);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestData {hdnSender};
$ mailTo = $ requestData {hdnRecipient};
$ plik = $ QUARANTINE_PATH."/".$ requestData {hdnFilePath};

$ mailfile = $ requestData {hdnFilePath};
$ validate_email ="fałszywy";
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 / && ((zdefiniowane $ requestData {hdnSender} && $ requestData {hdnSender} eq '') || $ requestData {hdnSender} = ~ / $ email_regex /) && indeks ($ requestData {hdnFilePath}, „.. /”) == -1) {
$ validate_email ="prawdziwe";
}
.... zredagowane....

Jak widać powyżej, pseudo-Perl pokazuje nam, w jaki sposób backend otrzymuje dane wejściowe z frontendu ($ requestData) i jak próbuje zweryfikować niektóre parametry, które wysyłamy.

Po weryfikacji, jeśli nasze parametry są prawidłowe, wykonywany jest następujący kod:

% mailreq = ("mailaction"=>"$ MAIL_FORWARD","Przedmiot"=>"$ strSubject","toEmail"=>"$ mailTo","plik załącznika"=>"plik $","smtpserverhost"=>"$ mailServerHost","z adresu"=>"$ mail");

out = OPCODE mail_sender json% mailreq

Powyższy kod ustawia parametry żądania w zmienną mailreq i wywołuje funkcję mail_sender (OPCODE). Zobaczymy, jak ten kod operacji jest wykonywany i gdzie dokładnie dzieje się RCE:

#mailaction 0 = mail_with_var, 1 = mail_forward, 2 = mail_attachment
$ mailaction = $ żądanie->{mailaction};
$ subject = $ request->{Przedmiot};
$ mailbody = '';
$ plik załącznika = $ żądanie->{plik załącznika};
$ toEmail = $ żądanie->{toEmail};

# ciało pocztowe
GDYBY("zdefiniowane żądanie $->{mailbody} && '' ne $ żądanie->{mailbody}") {
$ mailbody = $ request->{mailbody};
}
# Host serwera SMTP
GDYBY("zdefiniowane żądanie $->{smtpserverhost} && '' ne $ żądanie->{smtpserverhost}") {
$ smtpserverhost = $ żądanie->{smtpserverhost};
}JESZCZE{
wynik = QUERY "wybierz wartość usługi z tblclientservices, gdzie servicekey = 'MailServer'"
GDYBY("zdefiniowany wynik $->{wynik}->{servicevalue} [0] && Wynik „ne $”->{wynik}->{servicevalue} [0]") {
$ smtpserverhost = $ wynik->{wynik}->{servicevalue} [0];
}JESZCZE{
$ smtpserverhost ="127.0.0.1";
}
}

# Port serwera SMTP
GDYBY("zdefiniowane żądanie $->{smtpserverport} && '' ne $ żądanie->{smtpserverport}") {
$ smtpserverport = $ żądanie->{smtpserverport};
}JESZCZE{
wynik = QUERY "wybierz wartość usługi z tblclientservices, gdzie servicekey = 'MailServerPort'"
GDYBY("zdefiniowany wynik $->{wynik}->{servicevalue} [0] && Wynik „ne $”->{wynik}->{servicevalue} [0]") {
$ smtpserverport = $ wynik->{wynik}->{servicevalue} [0];
}JESZCZE{
$ smtpserverport ="25";
}
}

# Flaga autoryzacji SMTP
$ smtpauthflag ="0";
GDYBY("zdefiniowane żądanie $->{smtpauthflag} && '' ne $ żądanie->{smtpauthflag}") {
$ smtpauthflag = $ żądanie->{smtpauthflag};
}JESZCZE{
wynik = QUERY "wybierz wartość usługi z tblclientservices, gdzie servicekey = 'SMTPAuthenticationFlag'"
GDYBY("zdefiniowany wynik $->{wynik}->{servicevalue} [0] && Wynik „ne $”->{wynik}->{servicevalue} [0]") {
$ smtpauthflag = $ wynik->{wynik}->{servicevalue} [0];
}
}

GDYBY("$ smtpauthflag == 1") {
GDYBY("zdefiniowane żądanie $->{mailusername} && '' ne $ żądanie->{mailusername}") {

$ mailusername = $ żądanie->{mailusername};
$ mailpassword = $ żądanie->{mailpassword};

}JESZCZE{
wynik = QUERY "wybierz wartość usługi z tblclientservices, gdzie servicekey = 'MailServerUsername'"
$ mailusername = $ wynik->{wynik}->{servicevalue} [0];
wynik = QUERY "wybierz wartość usługi z tblclientservices, gdzie servicekey = 'MailServerPassword'"
$ mailpassword = $ wynik->{wynik}->{servicevalue} [0];
}
}JESZCZE{

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

}
GDYBY("zdefiniowane żądanie $->{z adresu} && '' ne $ żądanie->{z adresu}") {
$ fromaddress = $ request->{z adresu};
}JESZCZE{
wynik = QUERY "wybierz wartość usługi z tblclientservices, gdzie servicekey = 'FromAddress'"
$ fromaddress = $ wynik->{wynik}->{servicevalue} [0];
}

#Tryb Bezpieczny
GDYBY("zdefiniowane żądanie $->{smtpsecurity} && '' ne $ żądanie->{smtpsecurity}") {
$ smtpsecurity = $ żądanie->{smtpsecurity};
}JESZCZE{
wynik = QUERY "wybierz wartość usługi z tblclientservices, gdzie servicekey = 'smtpsecurity'"
$ smtpsecurity = $ wynik->{wynik}->{servicevalue} [0];
}

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

# Certyfikat SMTP

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

GDYBY("$ smtpsecuritymode! = 0") {
GDYBY("zdefiniowane żądanie $->{smtpcertificate} && '' ne $ żądanie->{smtpcertificate}") {
wynik = QUERY "wybierz nazwę certyfikatu, hasło z tblvpncertificate, gdzie certid = $ request->{smtpcertificate}"
}JESZCZE{
wynik = QUERY "wybierz nazwę certyfikatu, hasło z tblvpncertificate gdzie certid = (wybierz servicevalue :: int z tblclientservices where servicekey = 'smtpcertificate')"
}

$ smtpcertificate = $ wynik->{wynik}->{nazwa certyfikatu} [0];
$ certpassword = $ wynik->{wynik}->{hasło} [0];

}

#Z adresu z nazwą
GDYBY("zdefiniowane żądanie $->{fromaddresswithname} && '' ne $ żądanie->{fromaddresswithname}") {
$ fromaddresswithname = $ żądanie->{fromaddresswithname};
}JESZCZE{
$ fromaddresswithname = $ OEMNAME . " <" . $ z adresu . ">";
}

Powyższy kod robi to samo, co drugi opcode, kiedy się uruchomił. Inicjuje zmienne (niektóre od nas lub z urządzenia, jeśli nie określono).

Po przypisaniu zmiennych wykonywany jest następujący blok kodu.

out = EXECSH "/ bin / cschelper mail_send '$ fromaddress' '$ fromaddresswithname' '$ toEmail' '$ toEmail' '$ subject' '$ mailbody' '$ smtpserverhost' '$ smtpserverport' '$ mailusername' '$ mailpassword' '$ mailaction' ' $ smtpsecuritymode '' $ smtpcertificate '' $ certpassword '' 1 '' $ plik załączników '"

I oto jest wykonanie polecenia. Teraz wywołaniem jest EXECSH, który nazywa / bin / sh-c „ARGUMENTY”. Ponieważ wykonanie odbywa się przy użyciu kontrolowanych przez nas wartości, możemy łatwo osiągnąć zdalne wykonanie polecenia, wszystko bez uwierzytelnienia.

Wydamy pełny raport i Proof of Concept z odpowiednimi zarysami za kilka miesięcy.

Aktualizacja: Badanie to zostało najpierw omówione w TechCrunch, czytaj więcej tutaj.

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