CVE-2019-17059:ソフォスのCyber​​oamのPreauth-RCEの説明

TheBestVPNの社内および社外のセキュリティ研究者と協力して、SSL VPNおよびCyber​​oam、Fortigate、Cisco VPNなどのファイアウォールのリモートで悪用可能な深刻な抜け穴を発見しました。この記事は、Cyber​​oam SSL VPN(Cyber​​oamOSとも呼ばれます)に影響を与える、パッチを適用した重大な脆弱性に関する技術資料です。.


CVE-2019-17059と呼ばれるこのCyber​​oamエクスプロイトは、ユーザー名やパスワードを入力せずに攻撃者がCyber​​oamデバイスにアクセスできるようにする重要な脆弱性です。その上、許可されるアクセスは最高レベル(ルート)であり、これは基本的に攻撃者にCyber​​oamデバイスに対する無制限の権限を与えます.

ほとんどのネットワーク環境では、Cyber​​oamデバイスはファイアウォールおよびSSL VPNゲートウェイとして使用されます。これにより、潜在的な攻撃者がネットワーク内で強力な足場を築くことができます。ネットワーク内のホストを攻撃しやすくします。Cyber​​oamデバイスは通常ほとんどの環境で信頼されているため、攻撃者になる可能性があります。.

Shodan(インターネット接続デバイスの検索エンジン)によると、世界中から96,000以上のインターネットに接続されたCyber​​oamデバイスがあります。これらのデバイスのほとんどは、企業、大学、および世界的に有名な銀行に設置されています。これは、これらの環境に大きな影響を与える攻撃につながります.

ソフォスのセキュリティチームとの協力は、最初の報告から数日後にパッチを承認して公開することで迅速に対応したため、大きな喜びでした。彼らに称賛を! (しゃれた!)

Cyber​​oamの検出

そして、これらのエンティティのほとんどは攻撃者にとって魅力的な標的であるため、バグをより重要にします.

Cyber​​oamOSリモートの非認証ルートコマンドの実行

Cyber​​oamOSは、Cyber​​oamデバイス用に変更されたLinuxベースのオペレーティングシステムです。このOSには、Webベースの構成インターフェースとSSLVPNポータルがあります.

Webインターフェースは2つの主要部分に分かれています。

  • Javaで書かれたフロントエンド
  • CとPerlの組み合わせを使用するバックエンド

主に時間を節約し、公開される情報量を制限するために、フロントエンドコードまたはバックエンドコードの内部を深く掘り下げません。しかし、バグがどのようにトリガーされるかについて簡単に説明します.

構成とSSLVPNインターフェースの両方に、主要な操作を処理するサーブレットがあります。これらの操作は、「モード」という名前のパラメーターを使用して定義されます.

これらのほとんどは認証されています。ただし、認証なしでアクセスできる操作はいくつかあります(ログインなど).

私たちが発見したバグは、電子メールのウイルス対策/スパム対策モジュールにあります。このエンドポイント(モジュール、op)の要求モードは458です.

注意すべきことの1つは、オペコードがCyber​​oamデータベース(内部データベースPostgres)の名前にマップされていることです。 458を調べると、このオペコードの名前がわかります.

オペコード458という名前を示すデータベース初期化SQLスクリプトの行を次に示します。

tblcrevent(opcode、description、mode、requesttype)に挿入します
values( 'RELEASEQUARANTINEMAILFROMMAIL'、 'RELEASE QUARANTINE MAIL MAIL FROM MAIL'、 '458'、2);

オペコード関数は、ディレクトリ/ _conf / csc / cscconf /に保存されます。脆弱な関数のコード全体を明らかにすることはしませんが、バグが発生した場所と方法を示すスニペットをいくつか提供します.

オペコード458を処理するJavaフロントエンドのコード:

if((jsonObject.getString("hdnSender").equals("")||
validateEmail(jsonObject.getString("hdnSender"))) &&
validateEmail(jsonObject.getString("hdnRecipient")) &&
isSafeFilePath(jsonObject.getString("hdnFilePath")) && b){
httpServletResponse.setContentType("text / html");
Cyber​​oamLogger.debug("アンチウイルス/アンチスパム", "CSC定数値 " +
CSCConstants.isCCC);

上記を見るとわかるように、いくつかのパラメーターの有効性がチェックされます。有効な値である場合、次のことが起こります。

最終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};

$ 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","添付ファイル"=>"$ file","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 = $ request->{mailaction};
$ subject = $ request->{件名};
$ mailbody = '';
$ attachmentfile = $ request->{添付ファイル};
$ toEmail = $ request->{メールする};

#メール本文
IF("定義済みの$ request->{mailbody} && '' ne $ request->{mailbody}"){
$ mailbody = $ request->{mailbody};
}
#SMTPサーバーホスト
IF("定義済みの$ request->{smtpserverhost} && '' ne $ request->{smtpserverhost}"){
$ smtpserverhost = $ request->{smtpserverhost};
}そうしないと{
結果= QUERY "servicekey = 'MailServer'のtblclientservicesからservicevalueを選択します"
IF("定義済みの$ result->{出力}->{servicevalue} [0] && '' ne $ result->{出力}->{servicevalue} [0]"){
$ smtpserverhost = $ result->{出力}->{servicevalue} [0];
}そうしないと{
$ smtpserverhost ="127.0.0.1";
}
}

#SMTPサーバーポート
IF("定義済みの$ request->{smtpserverport} && '' ne $ request->{smtpserverport}"){
$ smtpserverport = $ request->{smtpserverport};
}そうしないと{
結果= QUERY "servicekey = 'MailServerPort'のtblclientservicesからservicevalueを選択します"
IF("定義済みの$ result->{出力}->{servicevalue} [0] && '' ne $ result->{出力}->{servicevalue} [0]"){
$ smtpserverport = $ result->{出力}->{servicevalue} [0];
}そうしないと{
$ smtpserverport ="25";
}
}

#SMTP認証フラグ
$ smtpauthflag ="0";
IF("定義済みの$ request->{smtpauthflag} && '' ne $ request->{smtpauthflag}"){
$ smtpauthflag = $ request->{smtpauthflag};
}そうしないと{
結果= QUERY "servicekey = 'SMTPAuthenticationFlag'のtblclientservicesからservicevalueを選択します"
IF("定義済みの$ result->{出力}->{servicevalue} [0] && '' ne $ result->{出力}->{servicevalue} [0]"){
$ smtpauthflag = $ result->{出力}->{servicevalue} [0];
}
}

IF("$ smtpauthflag == 1"){
IF("定義済みの$ request->{mailusername} && '' ne $ request->{mailusername}"){

$ mailusername = $ request->{mailusername};
$ mailpassword = $ request->{mailpassword};

}そうしないと{
結果= QUERY "servicekey = 'MailServerUsername'のtblclientservicesからservicevalueを選択します"
$ mailusername = $ result->{出力}->{servicevalue} [0];
結果= QUERY "servicekey = 'MailServerPassword'のtblclientservicesからservicevalueを選択します"
$ mailpassword = $ result->{出力}->{servicevalue} [0];
}
}そうしないと{

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

}
IF("定義済みの$ request->{fromaddress} && '' ne $ request->{fromaddress}"){
$ fromaddress = $ request->{fromaddress};
}そうしないと{
結果= QUERY "servicekey = 'FromAddress'のtblclientservicesからservicevalueを選択します"
$ fromaddress = $ result->{出力}->{servicevalue} [0];
}

#セキュリティモード
IF("定義済みの$ request->{smtpsecurity} && '' ne $ request->{smtpsecurity}"){
$ smtpsecurity = $ request->{smtpsecurity};
}そうしないと{
結果= QUERY "servicekey = 'smtpsecurity'のtblclientservicesからservicevalueを選択します"
$ smtpsecurity = $ result->{出力}->{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("定義済みの$ request->{smtpcertificate} && '' ne $ request->{smtpcertificate}"){
結果= QUERY "certid = $ requestのtblvpncertificateからcertname、passwordを選択します->{smtpcertificate}"
}そうしないと{
結果= QUERY "tblvpncertificateからcertid =(select servicevalue :: int from tblclientservices where servicekey = 'smtpcertificate')からcertname、passwordを選択します"
}

$ smtpcertificate = $ result->{出力}->{certname} [0];
$ certpassword = $ result->{出力}->{パスワード} [0];

}

#From Address with Name
IF("定義済みの$ request->{fromaddresswithname} && '' ne $ request->{fromaddresswithname}"){
$ fromaddresswithname = $ request->{fromaddresswithname};
}そうしないと{
$ 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 '"

そして、それはコマンドの実行です。ここでの呼び出しは、/ bin / sh -c“ ARGUMENTS”を呼び出すEXECSHです。制御する値を使用して実行することで、すべて認証なしでリモートコマンドの実行を簡単に実現できます。.

数か月以内に、完全なレポートと適切なアウトラインを含む概念実証をリリースします。.

更新: この調査はTechCrunchで最初に取り上げられました。詳細はこちらをご覧ください.

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