CVE-2019-17059: объяснение Preauth-RCE в кибероаме 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 устройств Cyberoam, подключенных к Интернету, со всего мира. Большинство из этих устройств установлены на предприятиях, в университетах, а некоторые - во всемирно известных банках. Это приводит к тому, что атаки оказывают огромное влияние на эти среды..

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

обнаружение Cyberoam

И поскольку большинство этих объектов являются привлекательными целями для злоумышленников, это делает ошибки еще более критичными.

Выполнение CyberoamOS удаленного без проверки подлинности корневой команды

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

Веб-интерфейс разделен на две основные части:

  • Интерфейс написан на Java
  • Бэкэнд, который использует комбинацию C и Perl

Мы не будем углубляться во внутреннюю часть внешнего или внутреннего кода, главным образом, чтобы сэкономить время и ограничить объем раскрываемой информации. Но мы кратко обсудим, как ошибка вызвана.

И интерфейс, и конфигурация SSLVPN имеют сервлет, который обрабатывает основные операции. Эти операции определяются с помощью параметра с именем «mode».

Большинство из них аутентифицированы. Но есть несколько операций, к которым мы можем получить доступ без аутентификации (например, вход в систему).

Найденные ошибки лежат в модуле антивируса / антиспама. Режим запроса для этой конечной точки (module, op) - 458.

Следует отметить, что коды операций сопоставляются с их именами в базе данных Cyberoam (внутренняя база данных Postgres). Посмотрев 458, мы можем узнать, как называется этот код операции.

Вот строка из сценария SQL инициализации базы данных, показывающая код операции 458:

вставить в tblcrevent (код операции, описание, режим, тип запроса)
значения ('RELEASEQUARANTINEMAILFROMMAIL', 'RELEASE QUARANTINE MAIL ИЗ ПОЧТЫ', '458', 2);

Функции кода операции хранятся в каталоге / _conf / csc / cscconf /. Мы не будем раскрывать весь код уязвимой функции, но предоставим несколько фрагментов, показывающих, где и как возникает ошибка.

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

if ((jsonObject.getString ("hdnSender") .equals ("") ||
validateEmail (jsonObject.getString ("hdnSender"))) &&
validateEmail (jsonObject.getString ("hdnRecipient")) &&
isSafeFilePath (jsonObject.getString ("hdnFilePath")) && б) {
httpServletResponse.setContentType ("текст / html");
CyberoamLogger.debug ("Антивирусы / AntiSpam", "CSC постоянное значение " +
CSCConstants.isCCC);

Как вы можете видеть выше, несколько параметров проверяются на достоверность. Если они являются действительными значениями, происходит следующее:

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

Как мы видим выше, у нас есть новый код события (363), который будет отправлен на серверную часть. Ошибка, которую мы обнаружили, заключается в коде, который обрабатывает это в серверной части.

Код операции называется sendmail, и чтобы избежать использования этой ошибки, мы будем редактировать большую часть кода из следующего кода.

Обработчик кода операции для send_mail.

...отредактированный ...

$ param = $ request->{выпуск};
param = DLOPEN (base64_decode, param)
LOG applog " Значения декодирования :: $ param \ n"
% requestData = split (/ [&=] /, $ param);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestData {hdnSender};
$ mailTo = $ requestData {hdnRecipient};
$ file = $ QUARANTINE_PATH."/".$ RequestData {hdnFilePath};

$ = $ Файл почта requestData {hdnFilePath};
$ Validate_email ="ложный";
мой $ email_regex = '^ ([\.]? [_ \ - \! \ # \ {\} \ $ \% \ ^ \&\ * \ + \ = \ |? \ \ '\\\\\\ / A-Za-Z0-9]) * @ ([A-Za-Z0-9] ([-] [а-запорожец Z0-9] +) * \) + ([A-Za-Z0-9] {0,6}) $ '.;
if ($ requestData {hdnRecipient} = ~ / $ email_regex / && ((определено $ requestData {hdnSender} && $ requestData {hdnSender} eq '') || $ requestData {hdnSender} = ~ / $ email_regex /) && index ($ requestData {hdnFilePath}, '.. /') == -1) {
$ Validate_email ="правда";
}
.... отредактированное....

Как мы видим выше, псевдо-Perl-код показывает нам, как бэкэнд получает входные данные от внешнего интерфейса ($ 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};
$ Subject = $ запрос->{предмет};
$ Mailbody = '';
$ Attachmentfile = $ запрос->{прикрепленный файл};
$ ToEmail = $ запрос->{ToEmail};

# mail body
ЕСЛИ("определенный $ запрос->{} Mailbody && '' $ запрос->{} Mailbody") {
$ Mailbody = $ запрос->{Mailbody};
}
# Сервер SMTP
ЕСЛИ("определенный $ запрос->{} Smtpserverhost && '' $ запрос->{} Smtpserverhost") {
$ Smtpserverhost = $ запрос->{Smtpserverhost};
} ELSE {
результат = QUERY "выберите значение службы из tblclientservices, где servicekey = 'MailServer'"
ЕСЛИ("определенный $ результат->{выход}->{} Servicevalue [0] && '' ne $ result->{выход}->{} Servicevalue [0]") {
$ Smtpserverhost = $ результат->{выход}->{} Servicevalue [0];
} ELSE {
$ Smtpserverhost ="127.0.0.1";
}
}

# Порт сервера SMTP
ЕСЛИ("определенный $ запрос->{} Smtpserverport && '' $ запрос->{} Smtpserverport") {
$ Smtpserverport = $ запрос->{Smtpserverport};
} ELSE {
результат = QUERY "выберите значение службы из tblclientservices, где servicekey = 'MailServerPort'"
ЕСЛИ("определенный $ результат->{выход}->{} Servicevalue [0] && '' ne $ result->{выход}->{} Servicevalue [0]") {
$ Smtpserverport = $ результат->{выход}->{} Servicevalue [0];
} ELSE {
$ Smtpserverport ="25";
}
}

#SMTP auth flag
$ Smtpauthflag ="0";
ЕСЛИ("определенный $ запрос->{} Smtpauthflag && '' $ запрос->{} Smtpauthflag") {
$ Smtpauthflag = $ запрос->{Smtpauthflag};
} ELSE {
результат = QUERY "выберите значение службы из tblclientservices, где servicekey = 'SMTPAuthenticationFlag'"
ЕСЛИ("определенный $ результат->{выход}->{} Servicevalue [0] && '' ne $ result->{выход}->{} Servicevalue [0]") {
$ Smtpauthflag = $ результат->{выход}->{} Servicevalue [0];
}
}

ЕСЛИ("$ smtpauthflag == 1") {
ЕСЛИ("определенный $ запрос->{} Mailusername && '' $ запрос->{} Mailusername") {

$ Mailusername = $ запрос->{Mailusername};
$ Mailpassword = $ запрос->{Mailpassword};

} ELSE {
результат = QUERY "выберите значение службы из tblclientservices, где servicekey = 'MailServerUsername'"
$ mailusername = $ result->{выход}->{} Servicevalue [0];
результат = QUERY "выберите значение службы из tblclientservices, где servicekey = 'MailServerPassword'"
$ mailpassword = $ result->{выход}->{} Servicevalue [0];
}
} ELSE {

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

}
ЕСЛИ("определенный $ запрос->{} FromAddress && '' $ запрос->{} FromAddress") {
$ FromAddress = $ запрос->{FromAddress};
} ELSE {
результат = QUERY "выберите значение службы из tblclientservices, где servicekey = 'FromAddress'"
$ fromaddress = $ result->{выход}->{} Servicevalue [0];
}

#Безопасный режим
ЕСЛИ("определенный $ запрос->{} Smtpsecurity && '' $ запрос->{} Smtpsecurity") {
$ Smtpsecurity = $ запрос->{Smtpsecurity};
} ELSE {
результат = QUERY "выберите значение службы из tblclientservices, где servicekey = 'smtpsecurity'"
$ smtpsecurity = $ result->{выход}->{} Servicevalue [0];
}

$ Smtpsecuritymode = 0;
ЕСЛИ("$ smtpsecurity eq 'STARTTLS'") {
$ Smtpsecuritymode = 1;
} ИЛИ ЕСЛИ ("$ smtpsecurity eq 'SSL / TLS'") {
$ Smtpsecuritymode = 2;
}

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

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

ЕСЛИ("$ Smtpsecuritymode! = 0") {
ЕСЛИ("определенный $ запрос->{} Smtpcertificate && '' $ запрос->{} Smtpcertificate") {
результат = QUERY "выберите имя сертификата, пароль из tblvpncertificate, где certid = $ request->{} Smtpcertificate"
} ELSE {
результат = QUERY "выберите certname, пароль от tblvpncertificate, где certid = (выберите servicevalue :: int из tblclientservices, где servicekey = 'smtpcertificate')"
}

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

}

# С адреса с именем
ЕСЛИ("определенный $ запрос->{} Fromaddresswithname && '' $ запрос->{} Fromaddresswithname") {
$ Fromaddresswithname = $ запрос->{Fromaddresswithname};
} ELSE {
$ fromaddresswithname = $ OEMNAME . " <" . $ FromAddress . ">";
}

Код выше делает то же самое, что и другой код операции при запуске. Инициализирует переменные (некоторые из нас или с устройства, если не указано).

После присвоения переменных выполняется следующий блок кода.

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

И вот оно, выполнение команды. Теперь вызов здесь EXECSH, который вызывает / bin / sh -c «ARGUMENTS». Поскольку выполнение происходит с использованием значений, которые мы контролируем, мы можем легко добиться удаленного выполнения команд, все без аутентификации.

Через несколько месяцев мы выпустим полный отчет и подтверждение концепции с надлежащими планами..

Обновить: Это исследование было освещено в первую очередь на TechCrunch, подробнее здесь.

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