CVE-2019-17059:Sophos Cyber​​oam中的Preauth-RCE解释了

我们一直在TheBestVPN与内部和外部安全研究人员一起努力,以发现SSL VPN和Cyber​​oam,Fortigate和Cisco VPN等防火墙中的严重可远程利用的漏洞。本文是有关影响Cyber​​oam SSL VPN(也称为Cyber​​oamOS)的已修补关键漏洞的技术性文章。.


此Cyber​​oam漏洞被称为CVE-2019-17059,这是一个严重漏洞,攻击者可以利用该漏洞无需提供任何用户名或密码即可访问您的Cyber​​oam设备。最重要的是,授予的访问权限是最高级别(根),它实质上为攻击者提供了Cyber​​oam设备上的无限权限.

在大多数网络环境中,Cyber​​oam设备都用作防火墙和SSL VPN网关。这使潜在的攻击者在网络中拥有强大的立足点。它使攻击网络内部的主机变得更加容易,并且由于Cyber​​oam设备通常在大多数环境中都是受信任的,因此这为潜在的攻击者提供了额外的优势.

Shodan(用于连接互联网的设备的搜索引擎)表示,来自世界各地的超过96,000个面向互联网的Cyber​​oam设备。这些设备大多数安装在企业,大学和一些世界知名的银行中。这导致攻击对这些环境产生巨大影响.

与Sophos安全团队的合作使他们感到非常高兴,因为他们很快采取行动,在我们向他们提交初次报告后仅几天就确认并推出了补丁程序。对他们表示敬意! (双关语!)

侦测Cyber​​oam

而且由于这些实体中的大多数都是攻击者的诱人目标,因此使漏洞变得更加关键.

Cyber​​oamOS远程未经身份验证的根命令执行

Cyber​​oamOS是用于Cyber​​oam设备的基于Linux的经过修改的操作系统。该操作系统具有基于Web的配置界面和SSLVPN门户.

Web界面分为两个主要部分:

  • 用Java编写的前端
  • 结合使用C和Perl的后端

我们不会深入研究前端或后端代码的内部,主要是为了节省时间并限制所显示的信息量。但是我们将简要讨论该错误是如何触发的.

配置和SSLVPN接口都具有处理主要操作的servlet。使用名为“ mode”的参数定义这些操作.

其中大多数已通过身份验证。但是有些操作我们无需身份验证即可访问(例如登录).

我们发现的错误位于电子邮件防病毒/反垃圾邮件模块中。该端点(模块,操作)的请求模式为458.

需要注意的一件事是,操作码在Cyber​​oam数据库(内部数据库Postgres)中被映射为其名称。通过查找458,我们可以找出此操作码的名称是.

这是数据库初始化SQL脚本中的一行,显示名称为操作码458:

插入到tblcrevent(操作码,描述,模式,请求类型)
值('RELEASEQUARANTINEMAILFROMMAIL','从邮件中释放检疫邮件','458',2);

操作码功能存储在目录/ _conf / csc / cscconf /中。我们不会透露易受攻击的函数的全部代码,但是我们将提供一些片段来显示错误发生的位置和方式.

来自Java前端的处理操作码458的代码:

如果((jsonObject.getString("hdnSender")。等于("")||
validateEmail(jsonObject.getString("hdnSender"))) &&
validateEmail(jsonObject.getString("hdn收件人")) &&
isSafeFilePath(jsonObject.getString("hdnFilePath")) && b){
httpServletResponse.setContentType("文字/ HTML");
Cyber​​oamLogger.debug("防病毒/反垃圾邮件", "CSC常数值 " +
CSCConstants.isCCC);

如您在上面看到的,检查了一些参数的有效性。如果它们是有效值,则会发生以下情况:

最后的EventBean eventByMode = EventBean.getEventByMode(363);
已编辑
最后的int sendWizardEvent = cscClient.sendWizardEvent(eventByMode,hashMap,sqlReader);

正如我们在上面看到的,我们有一个新的事件代码(363)将发送到后端。我们发现的错误位于后端中处理该错误的代码中.

该操作码名为sendmail,为避免利用此错误,我们将从以下代码中删除大部分代码.

send_mail的操作码处理程序.

...已编辑...

$ param = $ request->{发布};
参数= DLOPEN(base64_decode,param)
LOG applog " 解码值:: $ param \ n"
%requestData = split(/ [&=] /,$ param);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestData {hdnSender};
$ mailTo = $ requestData {hdnRecipient};
$文件= $ QUARANTINE_PATH."/".$ requestData {hdnFilePath};

$ mailfile = $ requestData {hdnFilePath};
$ validate_email ="假";
我的$ 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 / && (((已定义$ requestData {hdnSender} && $ requestData {hdnSender} eq'')|| $ requestData {hdnSender} =〜/ $ email_regex /) && index($ requestData {hdnFilePath},'.. /')== -1){
$ validate_email ="真正";
}
....已编辑....

正如我们在上面看到的,伪Perl代码向我们展示了后端如何从前端($ requestData)接收输入以及它如何尝试验证我们发送的某些参数。.

验证后,如果我们的参数有效,则执行以下代码:

%mailreq =("邮件动作"=>"$ MAIL_FORWARD","学科"=>"$ strSubject","发邮件"=>"$ mailTo","附件文件"=>"$文件","smtpserverhost"=>"$ mailServerHost","发件人地址"=>"$ 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 = $ request->{学科};
$ mailbody ='';
$ attachmentfile = $请求->{attachmentfile};
$ toEmail = $请求->{发邮件};

#邮件正文
如果("定义的$ request->{mailbody} && ''ne $请求->{mailbody}"){
$ mailbody = $请求->{mailbody};
}
#SMTP服务器主机
如果("定义的$ request->{smtpserverhost} && ''ne $请求->{smtpserverhost}"){
$ smtpserverhost = $请求->{smtpserverhost};
}其他{
结果= QUERY "从tblclientservices中选择servicevalue,其中servicekey ='MailServer'"
如果("定义的$ result->{输出}->{servicevalue} [0] && ''ne $ result->{输出}->{servicevalue} [0]"){
$ smtpserverhost = $结果->{输出}->{servicevalue} [0];
}其他{
$ smtpserverhost ="127.0.0.1";
}
}

#SMTP服务器端口
如果("定义的$ request->{smtpserverport} && ''ne $请求->{smtpserverport}"){
$ smtpserverport = $请求->{smtpserverport};
}其他{
结果= QUERY "从tblclientservices中选择servicevalue,其中servicekey ='MailServerPort'"
如果("定义的$ result->{输出}->{servicevalue} [0] && ''ne $ result->{输出}->{servicevalue} [0]"){
$ smtpserverport = $结果->{输出}->{servicevalue} [0];
}其他{
$ smtpserverport ="25";
}
}

#SMTP身份验证标志
$ smtpauthflag ="0";
如果("定义的$ request->{smtpauthflag} && ''ne $请求->{smtpauthflag}"){
$ smtpauthflag = $请求->{smtpauthflag};
}其他{
结果= QUERY "从tblclientservices中选择servicevalue,其中servicekey ='SMTPAuthenticationFlag'"
如果("定义的$ result->{输出}->{servicevalue} [0] && ''ne $ result->{输出}->{servicevalue} [0]"){
$ smtpauthflag = $结果->{输出}->{servicevalue} [0];
}
}

如果("$ smtpauthflag == 1"){
如果("定义的$ request->{mailusername} && ''ne $请求->{mailusername}"){

$ mailusername = $请求->{mailusername};
$ mailpassword = $请求->{mailpassword};

}其他{
结果= QUERY "从tblclientservices中选择servicevalue,其中servicekey ='MailServerUsername'"
$ mailusername = $ result->{输出}->{servicevalue} [0];
结果= QUERY "从tblclientservices中选择servicevalue,其中servicekey ='MailServerPassword'"
$ mailpassword = $ result->{输出}->{servicevalue} [0];
}
}其他{

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

}
如果("定义的$ request->{fromaddress} && ''ne $请求->{fromaddress}"){
$ fromaddress = $请求->{fromaddress};
}其他{
结果= QUERY "从tblclientservices中选择servicevalue,其中servicekey ='FromAddress'"
$ fromaddress = $ result->{输出}->{servicevalue} [0];
}

#安全模式
如果("定义的$ request->{smtpsecurity} && ''ne $请求->{smtpsecurity}"){
$ smtpsecurity = $请求->{smtpsecurity};
}其他{
结果= QUERY "从tblclientservices中选择servicevalue,其中servicekey ='smtpsecurity'"
$ smtpsecurity = $结果->{输出}->{servicevalue} [0];
}

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

#SMTP证书

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

如果("$ smtpsecuritymode!= 0"){
如果("定义的$ request->{smtpcertificate} && ''ne $请求->{smtpcertificate}"){
结果= QUERY "选择证书名称,从tblvpncertificate中输入密码,其中certid = $ request->{smtpcertificate}"
}其他{
结果= QUERY "从tblvpncertificate中选择证书名称,密码,其中certid =(从tblclientservices中选择servicevalue :: int,其中servicekey ='smtpcertificate')"
}

$ smtpcertificate = $ result->{输出}->{certname} [0];
$ certpassword = $结果->{输出}->{password} [0];

}

#发件人地址
如果("定义的$ request->{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“ ARGUMENTS”。通过使用我们控制的值执行执行,我们可以轻松实现远程命令执行,而无需身份验证.

我们将在几个月后发布完整的报告和概念证明,并提供适当的概述.

更新: 这项研究首先在TechCrunch上进行了报道,在此处了解更多.

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