CVE-2019-17059: Preauth-RCE di Sophos ‘Cyberoam Dijelaskan

Kami telah bekerja keras dengan para penyelidik keselamatan dalaman dan luaran di TheBestVPN untuk mendedahkan kelemahan yang dieksploitasi dari jauh di SSL VPN dan Firewall seperti Cyberoam, Fortigate dan Cisco VPN. Artikel ini adalah teknik teknikal tentang kelemahan kritikal yang tersentuh yang mempengaruhi Cyberoam SSL VPN yang juga dikenali sebagai CyberoamOS.


Eksploitasi Cyberoam ini, yang digelar CVE-2019-17059 adalah kelemahan penting yang membolehkan penyerang mengakses peranti Cyberoam anda tanpa memberikan nama pengguna atau kata laluan. Di samping itu, akses yang diberikan adalah tahap tertinggi (root), yang pada asasnya memberikan hak penyerang tanpa had pada peranti Cyberoam anda.

Dalam kebanyakan persekitaran rangkaian, peranti Cyberoam digunakan sebagai firewall dan gateway SSL VPN. Ini memberi penyerang yang berpotensi sebagai pijakan yang kuat dalam rangkaian. Ia menjadikannya lebih mudah untuk menyerang tuan rumah di dalam rangkaian, dan sejak peranti Cyberoam biasanya dipercayai dalam kebanyakan persekitaran, ini memberikan kelebihan penyerang yang akan menjadi kelebihan.

Menurut Shodan (mesin pencari untuk peranti yang disambungkan ke internet), terdapat lebih daripada 96,000 peranti Cyberoam yang terdapat di internet dari seluruh dunia. Kebanyakan peranti ini dipasang di perusahaan, universiti dan beberapa di bank terkenal di dunia. Ini membawa kepada serangan yang mempunyai kesan yang besar terhadap persekitaran ini.

Bekerja dengan pasukan keselamatan Sophos telah menjadi kegembiraan besar kerana mereka bertindak cepat dengan mengakui dan melancarkan patch hanya beberapa hari selepas laporan awal kami kepada mereka. Kudos kepada mereka! (pun ditujukan!)

mengesan Cyberoam

Dan kerana kebanyakan entiti ini adalah sasaran yang menarik untuk penyerang, ia menjadikan pepijat yang lebih kritikal.

CyberoamOS Remote Unauthenticated Root Command Execution

CyberoamOS adalah sistem operasi berasaskan Linux yang diubahsuai untuk peranti Cyberoam. OS ini mempunyai antara muka konfigurasi berasaskan web dan portal SSLVPN.

Antara muka web dibahagikan kepada dua bahagian utama:

  • Frontend yang ditulis di Jawa
  • Backend yang menggunakan kombinasi C dan Perl

Kami tidak akan menyelam jauh ke dalam bahagian dalaman atau kod belakang, terutamanya untuk menjimatkan masa dan menghadkan jumlah maklumat yang dinyatakan. Tetapi kami akan membincangkan secara ringkas bagaimana bug itu dicetuskan.

Kedua-dua konfigurasi dan antara muka SSLVPN mempunyai servlet yang mengendalikan operasi utama. Operasi ini ditakrifkan menggunakan parameter bernama "mod".

Kebanyakannya disahkan. Tetapi ada beberapa ops yang boleh kami akses tanpa pengesahan (seperti login).

Pepijat yang kami temukan terletak dalam mod antivirus / antispam e-mel. Mod permintaan untuk titik akhir ini (modul, op) ialah 458.

Satu perkara yang perlu diperhatikan ialah kod opsyen dipetakan ke nama mereka dalam pangkalan data Cyberoam (pangkalan data dalaman). Dengan melihat 458, kita dapat mengetahui nama opcode ini.

Berikut adalah baris dari skrip SQL inisialisasi database yang menunjukkan opcode nama 458:

masukkan ke dalam tblcrevent (opcode, perihalan, mod, permintaan)
nilai ('RELEASEQUARANTINEMAILFROMMAIL', 'MENGHILASKAN QUARANTINE MAIL DARI MAIL', '458', 2);

Fungsi opcode disimpan dalam direktori / _conf / csc / cscconf /. Kami tidak akan mendedahkan keseluruhan kod fungsi yang lemah, tetapi kami akan menyediakan beberapa coretan yang menunjukkan di mana dan bagaimana pepijat berlaku.

Satu kod dari frontend Java yang mengendalikan opcode 458:

jika ((jsonObject.getString ("hdnSender")."") ||
validateEmail (jsonObject.getString ("hdnSender"))) &&
validateEmail (jsonObject.getString ("hdnRecipient")) &&
isSafeFilePath (jsonObject.getString ("hdnFilePath")) && b) {
httpServletResponse.setContentType ("teks / html");
CyberoamLogger.debug ("Antivirus / Anti-Spam", "CSC Constant value " +
CSCConstants.isCCC);

Seperti yang anda lihat di atas, beberapa parameter diperiksa untuk kesahihan. Jika mereka adalah nilai yang sah, perkara berikut akan berlaku:

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

Seperti yang dapat kita lihat di atas, kita mempunyai kod acara baru (363) yang akan dihantar ke backend. Bug yang telah kami temukan adalah dalam kod yang mengendalikan ini dalam backend.

Kod opcode itu dinamakan sendmail, dan untuk mengelakkan eksploitasi pepijat ini, kami akan menyahaktifkan kebanyakan kod dari kod berikut.

Pengendali opcode untuk send_mail.

...redacted ...

$ param = permintaan $->{release};
param = DLOPEN (base64_decode, param)
LOG applog " Decode nilai :: $ param \ n"
% requestData = split (/ [&=] /, $ param);
$ mailServerHost = $ requestData {hdnDestDomain};
$ mailFrom = $ requestData {hdnSender};
$ mailTo = $ requestData {hdnRecipient};
$ file = $ QUARANTINE_PATH."/".$ requestData {hdnFilePath};

$ mailfile = $ requestData {hdnFilePath};
$ validate_email ="salah";
my $ email_regex = '^ ([\.]? [_ \ - \! \ # \ {\} \ $ \% \ ^ \&[a-zA-Z0-9] ([-]? [a-zA- Z0-9] +) * \.) + ([A-zA-Z0-9] {0,6}) $ ';
jika ($ requestData {hdnRecipient} = ~ / $ email_regex / && ((ditakrifkan $ requestData {hdnSender} && $ requestData {hdnSender} eq '') || $ requestData {hdnSender} = ~ / $ email_regex /) && indeks ($ requestData {hdnFilePath}, '.. /') == -1) {
$ validate_email ="benar";
}
.... redacted....

Seperti yang dapat kita lihat di atas, kod pseudo-Perl menunjukkan kepada kita bagaimana backend menerima input dari frontend ($ requestData) dan bagaimana ia cuba mengesahkan beberapa parameter yang kami hantar.

Selepas pengesahan, jika parameter kami sah, kod berikut dilaksanakan:

% mailreq = ("mailaction"=>"$ MAIL_FORWARD","subjek"=>"$ strSubject","toEmail"=>"$ mailTo","fail lampiran"=>"$ file","smtpserverhost"=>"$ mailServerHost","fromaddress"=>"$ mailFrom");

out = OPCODE mail_sender json% mailreq

Kod di atas menetapkan parameter permintaan kami ke dalam pembolehubah mailreq dan memanggil fungsi mail_sender (OPCODE). Kami akan melihat bagaimana opcode ini dilaksanakan dan di mana sebenarnya RCE berlaku:

#mailaction 0 = mail_with_var, 1 = mail_forward, 2 = mail_attachment
$ mailaction = permintaan $->{mailaction};
$ subjek = permintaan $->{subject};
$ mailbody = '';
$ attachmentfile = permintaan $->{fail lampiran};
$ toEmail = permintaan $->{toEmail};

#mail body
JIKA"permintaan $ yang ditakrifkan->{mailbody} && '' permintaan ne $->{mailbody}") {
$ mailbody = permintaan $->{mailbody};
}
Hos pelayan #SMTP
JIKA"permintaan $ yang ditakrifkan->{smtpserverhost} && '' permintaan ne $->{smtpserverhost}") {
$ smtpserverhost = permintaan $->{smtpserverhost};
} ELSE {
hasil = QUERY "pilih servisevalue dari servis taktik servicekey = 'MailServer'"
JIKA"hasil $ yang ditakrifkan->{pengeluaran}->{servicevalue} [0] && '' hasil ne $->{pengeluaran}->{servicevalue} [0]") {
$ smtpserverhost = hasil $->{pengeluaran}->{servicevalue} [0];
} ELSE {
$ smtpserverhost ="127.0.0.1";
}
}

Port pelayan #SMTP
JIKA"permintaan $ yang ditakrifkan->{smtpserverport} && '' permintaan ne $->{smtpserverport}") {
$ smtpserverport = permintaan $->{smtpserverport};
} ELSE {
hasil = QUERY "pilih servicevalue dari tblclientservices di mana servicekey = 'MailServerPort'"
JIKA"hasil $ yang ditakrifkan->{pengeluaran}->{servicevalue} [0] && '' hasil ne $->{pengeluaran}->{servicevalue} [0]") {
$ smtpserverport = hasil $->{pengeluaran}->{servicevalue} [0];
} ELSE {
$ smtpserverport ="25";
}
}

#SMTP tanda nama
$ smtpauthflag ="0";
JIKA"permintaan $ yang ditakrifkan->{smtpauthflag} && '' permintaan ne $->{smtpauthflag}") {
$ smtpauthflag = permintaan $->{smtpauthflag};
} ELSE {
hasil = QUERY "pilih servicevalue dari tblclientservices where servicekey = 'SMTPAuthenticationFlag'"
JIKA"hasil $ yang ditakrifkan->{pengeluaran}->{servicevalue} [0] && '' hasil ne $->{pengeluaran}->{servicevalue} [0]") {
$ smtpauthflag = hasil $->{pengeluaran}->{servicevalue} [0];
}
}

JIKA"$ smtpauthflag == 1") {
JIKA"permintaan $ yang ditakrifkan->{mailusername} && '' permintaan ne $->{mailusername}") {

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

} ELSE {
hasil = QUERY "pilih servicevalue dari tblclientservices where servicekey = 'MailServerUsername'"
$ mailusername = $ result->{pengeluaran}->{servicevalue} [0];
hasil = QUERY "pilih servicevalue dari servis taktik servicekey = 'MailServerPassword'"
$ mailpassword = hasil $->{pengeluaran}->{servicevalue} [0];
}
} ELSE {

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

}
JIKA"permintaan $ yang ditakrifkan->{fromaddress} && '' permintaan ne $->{fromaddress}") {
$ fromaddress = permintaan $->{fromaddress};
} ELSE {
hasil = QUERY "pilih serviservalue dari servis tuhan servicekey = 'FromAddress'"
$ fromaddress = hasil $->{pengeluaran}->{servicevalue} [0];
}

#Security Mode
JIKA"permintaan $ yang ditakrifkan->{smtpsecurity} && '' permintaan ne $->{smtpsecurity}") {
$ smtpsecurity = permintaan $->{smtpsecurity};
} ELSE {
hasil = QUERY "pilih servicevalue dari servis taktik servicekey = 'smtpsecurity'"
$ smtpsecurity = hasil $->{pengeluaran}->{servicevalue} [0];
}

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

Sijil #SMTP

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

JIKA"$ smtpsecuritymode! = 0") {
JIKA"permintaan $ yang ditakrifkan->{smtpertertijk} && '' permintaan ne $->{smtpertertijk}") {
hasil = QUERY "pilih certname, kata laluan dari tblvpncertificate di mana certid = permintaan $->{smtpertertijk}"
} ELSE {
hasil = QUERY "pilih certname, kata laluan dari tblvpncertificate where certid = (pilih servicevalue :: int dari tblclientservices where servicekey = 'smtpcertificate')"
}

$ smtpcertificate = hasil $->{pengeluaran}->{certname} [0];
$ certpassword = hasil $->{pengeluaran}->{password} [0];

}

#From Address with Name
JIKA"permintaan $ yang ditakrifkan->{fromaddresswithname} && '' permintaan ne $->{fromaddresswithname}") {
$ fromaddresswithname = permintaan $->{fromaddresswithname};
} ELSE {
$ fromaddresswithname = $ OEMNAME . " <" . $ fromaddress . ">";
}

Kod di atas tidak sama dengan opcode yang lain apabila ia bermula. Ia memulakan pembolehubah (beberapa dari kami atau dari peranti jika tidak ditentukan).

Selepas pemboleh ubah diberikan, blok kod berikut dilaksanakan.

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

Dan di sana, pelaksanaan perintah. Kini panggilan di sini adalah EXECSH yang memanggil / bin / sh -c "ARGUMEN". Dengan pelaksanaan yang berlaku menggunakan nilai-nilai yang kita kontrol, kita boleh dengan mudah mencapai pelaksanaan arahan jauh, semua tanpa pengesahan.

Kami akan melepaskan laporan lengkap dan Bukti Konsep dengan garis panduan yang betul dalam beberapa bulan.

Kemas kini: Penyelidikan ini diliputi pertama di TechCrunch, baca lebih lanjut di sini.

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