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

Kami telah bekerja keras dengan para peneliti keamanan internal dan eksternal di sini di TheBestVPN untuk mengungkap celah-celah serius yang dapat dieksploitasi dari jarak jauh di SSL VPN dan Firewall seperti Cyberoam, Fortigate dan Cisco VPNs. Artikel ini adalah petunjuk teknis tentang kerentanan kritis yang ditambal yang mempengaruhi Cyberoam SSL VPN yang juga dikenal sebagai CyberoamOS.


Eksploitasi Cyberoam ini, dijuluki CVE-2019-17059 adalah kerentanan kritis yang memungkinkan penyerang mengakses perangkat Cyberoam Anda tanpa memberikan nama pengguna atau kata sandi apa pun. Selain itu, akses yang diberikan adalah level tertinggi (root), yang pada dasarnya memberikan hak tidak terbatas kepada penyerang di perangkat Cyberoam Anda..

Di sebagian besar lingkungan jaringan, perangkat Cyberoam digunakan sebagai firewall dan gateway SSL VPN. Ini memberikan penyerang potensial pijakan yang kuat dalam jaringan. Ini membuatnya lebih mudah untuk menyerang host di dalam jaringan, dan karena perangkat Cyberoam biasanya dipercaya di sebagian besar lingkungan, ini memberi calon penyerang keunggulan tambahan..

Menurut Shodan (mesin pencari untuk perangkat yang terhubung internet), ada lebih dari 96.000 perangkat Cyberoam yang menghadap internet dari seluruh dunia. Sebagian besar perangkat ini dipasang di perusahaan, universitas, dan beberapa di bank terkenal di dunia. Ini mengarah pada serangan yang memiliki dampak besar pada lingkungan ini.

Bekerja dengan tim keamanan Sophos sangat menyenangkan karena mereka bertindak cepat dengan mengakui dan meluncurkan tambalan hanya beberapa hari setelah laporan awal kami kepada mereka. Kudos kepada mereka! (pun intended!)

mendeteksi Cyberoam

Dan karena sebagian besar entitas ini adalah target yang menarik bagi penyerang, itu membuat bug lebih kritis.

Eksekusi Perintah Root CyberoamOS Remote Tidak Diautentikasi

CyberoamOS adalah sistem operasi berbasis Linux yang dimodifikasi untuk perangkat Cyberoam. OS ini memiliki antarmuka konfigurasi berbasis web dan portal SSLVPN.

Antarmuka web dibagi menjadi dua bagian utama:

  • Frontend yang ditulis dalam Java
  • Backend yang menggunakan kombinasi C dan Perl

Kami tidak akan terjun jauh ke internal kode front-end atau back-end, terutama untuk menghemat waktu dan membatasi jumlah informasi yang diungkapkan. Tetapi kita akan membahas secara singkat bagaimana bug dipicu.

Konfigurasi dan antarmuka SSLVPN memiliki servlet yang menangani operasi utama. Operasi ini didefinisikan menggunakan parameter bernama "mode".

Sebagian besar dikonfirmasi. Tetapi ada beberapa ops yang dapat kita akses tanpa autentikasi (seperti login).

Bug yang kami temukan ada di modul antivirus / antispam email. Mode permintaan untuk titik akhir ini (modul, op) adalah 458.

Satu hal yang perlu diperhatikan adalah opcodes dipetakan sesuai namanya di basis data Cyberoam (basis data internal Postgres). Dengan mencari 458, kita bisa mengetahui apa nama opcode ini.

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

masukkan ke tblcrevent (opcode, deskripsi, mode, jenis permintaan)
nilai ('RELEASEQUARANTINEMAILFROMMAIL', 'RELEASE QUARANTINE MAIL FROM MAIL', '458', 2);

Fungsi opcode disimpan dalam direktori / _conf / csc / cscconf /. Kami tidak akan mengungkapkan seluruh kode fungsi rentan, tetapi kami akan memberikan beberapa cuplikan yang menunjukkan di mana dan bagaimana bug terjadi.

Kode dari Java frontend yang menangani opcode 458:

if ((jsonObject.getString ("hdnSender"). sama dengan ("") ||
validateEmail (jsonObject.getString ("hdnSender"))) &&
validateEmail (jsonObject.getString ("Penerima hdn")) &&
isSafeFilePath (jsonObject.getString ("hdnFilePath")) && b) {
httpServletResponse.setContentType ("teks / html");
CyberoamLogger.debug ("Antivirus / AntiSpam", "Nilai Konstan CSC " +
CSCConstants.isCCC);

Seperti yang Anda lihat di atas, beberapa parameter diperiksa validitasnya. Jika mereka adalah nilai yang valid, yang berikut ini terjadi:

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

Seperti yang dapat kita lihat di atas, kita memiliki kode acara baru (363) yang akan dikirim ke backend. Bug yang kami temukan ada di kode yang menangani ini di backend.

Opcode bernama sendmail, dan untuk menghindari eksploitasi bug ini, kami akan mereduksi sebagian besar kode dari kode berikut.

Penangan opcode untuk send_mail.

...dihapus ...

$ param = $ request->{melepaskan};
param = DLOPEN (base64_decode, param)
LOG logog " Nilai dekode :: $ 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";
$ email_regex saya = '^ ([\.]? [_ \ - \! \ # \ {\} \ $ \% \ ^ \&\ * \ + \ = \ | \? \ '\\ / a-zA-Z0-9]) * @ ([a-zA-Z0-9] ([-]? [a-zA- Z0-9] +) * \.) + ([A-zA-Z0-9] {0,6}) $ ';
if ($ requestData {hdnRecipient} = ~ / $ email_regex / && ((didefinisikan $ requestData {hdnSender} && $ requestData {hdnSender} eq '') || $ requestData {hdnSender} = ~ / $ email_regex /) && indeks ($ requestData {hdnFilePath}, '.. /') == -1) {
$ validate_email ="benar";
}
.... dihapus....

Seperti yang dapat kita lihat di atas, kode pseudo-Perl menunjukkan kepada kita bagaimana backend menerima input dari frontend ($ requestData) dan bagaimana ia mencoba memverifikasi beberapa parameter yang kami kirim.

Setelah verifikasi, jika parameter kami valid, kode berikut dijalankan:

% mailreq = ("surat"=>"$ MAIL_FORWARD","subyek"=>"$ strSubject","toEmail"=>"$ mailTo","file attachment"=>"$ file","smtpserverhost"=>"$ mailServerHost","dari alamat"=>"$ mailDari");

out = OPCODE mail_sender json% mailreq

Kode di atas menetapkan parameter permintaan kami ke dalam variabel mailreq dan memanggil fungsi mail_sender (OPCODE). Kita akan melihat bagaimana opcode ini dieksekusi dan di mana tepatnya RCE terjadi:

#mailaction 0 = mail_with_var, 1 = mail_forward, 2 = mail_attachment
$ mailaction = $ request->{mailaction};
$ subject = $ request->{subyek};
$ mailbody = '';
$ attachmentfile = $ request->{attachmentfile};
$ toEmail = $ request->{toEmail};

#mail body
JIKA("$ request yang ditentukan->{mailbody} && '' permintaan $->{mailbody}") {
$ mailbody = $ request->{mailbody};
}
Host server #SMTP
JIKA("$ request yang ditentukan->{smtpserverhost} && '' permintaan $->{smtpserverhost}") {
$ smtpserverhost = $ request->{smtpserverhost};
}LAIN{
hasil = QUERY "pilih servicevalue dari tblclientservices mana servicekey = 'MailServer'"
JIKA("didefinisikan $ hasil->{keluaran}->{servicevalue} [0] && '' hasil $->{keluaran}->{servicevalue} [0]") {
$ smtpserverhost = $ hasil->{keluaran}->{servicevalue} [0];
}LAIN{
$ smtpserverhost ="127.0.0.1";
}
}

Port server #SMTP
JIKA("$ request yang ditentukan->{smtpserverport} && '' permintaan $->{smtpserverport}") {
$ smtpserverport = $ request->{smtpserverport};
}LAIN{
hasil = QUERY "pilih servicevalue dari tblclientservices mana servicekey = 'MailServerPort'"
JIKA("didefinisikan $ hasil->{keluaran}->{servicevalue} [0] && '' hasil $->{keluaran}->{servicevalue} [0]") {
$ smtpserverport = $ hasil->{keluaran}->{servicevalue} [0];
}LAIN{
$ smtpserverport ="25";
}
}

Bendera autor #SMTP
$ smtpauthflag ="0";
JIKA("$ request yang ditentukan->{smtpauthflag} && '' permintaan $->{smtpauthflag}") {
$ smtpauthflag = $ request->{smtpauthflag};
}LAIN{
hasil = QUERY "pilih servicevalue dari tblclientservices mana servicekey = 'SMTPAuthenticationFlag'"
JIKA("didefinisikan $ hasil->{keluaran}->{servicevalue} [0] && '' hasil $->{keluaran}->{servicevalue} [0]") {
$ smtpauthflag = $ hasil->{keluaran}->{servicevalue} [0];
}
}

JIKA("$ smtpauthflag == 1") {
JIKA("$ request yang ditentukan->{mailusername} && '' permintaan $->{mailusername}") {

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

}LAIN{
hasil = QUERY "pilih servicevalue dari tblclientservices mana servicekey = 'MailServerUsername'"
$ mailusername = $ hasil->{keluaran}->{servicevalue} [0];
hasil = QUERY "pilih servicevalue dari tblclientservices mana servicekey = 'MailServerPassword'"
$ mailpassword = $ hasil->{keluaran}->{servicevalue} [0];
}
}LAIN{

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

}
JIKA("$ request yang ditentukan->{dari alamat} && '' permintaan $->{dari alamat}") {
$ fromaddress = $ request->{fromaddress};
}LAIN{
hasil = QUERY "pilih servicevalue dari tblclientservices mana servicekey = 'FromAddress'"
$ fromaddress = $ result->{keluaran}->{servicevalue} [0];
}

#Mode aman
JIKA("$ request yang ditentukan->{smtpsecurity} && '' permintaan $->{smtpsecurity}") {
$ smtpsecurity = $ request->{smtpsecurity};
}LAIN{
hasil = QUERY "pilih servicevalue dari tblclientservices mana servicekey = 'smtpsecurity'"
$ smtpsecurity = $ hasil->{keluaran}->{servicevalue} [0];
}

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

Sertifikat #SMTP

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

JIKA("$ smtpsecuritymode! = 0") {
JIKA("$ request yang ditentukan->{smtpcertificate} && '' permintaan $->{smtpcertificate}") {
hasil = QUERY "pilih certname, kata sandi dari tblvpncertificate di mana certid = $ request->{smtpcertificate}"
}LAIN{
hasil = QUERY "pilih certname, kata sandi dari tblvpncertificate mana certid = (pilih servicevalue :: int dari tblclientservices mana servicekey = 'smtpcertificate')"
}

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

}

#Dari Alamat dengan Nama
JIKA("$ request yang ditentukan->{fromaddresswithname} && '' permintaan $->{fromaddresswithname}") {
$ fromaddresswithname = $ request->{fromaddresswithname};
}LAIN{
$ fromaddresswithname = $ OEMNAME . " <" . $ dari alamat . ">";
}

Kode di atas melakukan hal yang sama seperti yang dilakukan opcode lainnya ketika dimulai. Ini menginisialisasi variabel (beberapa dari kami atau dari perangkat jika tidak ditentukan).

Setelah variabel ditetapkan, blok kode berikut dijalankan.

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

Dan itu dia, eksekusi perintah. Sekarang panggilan di sini adalah EXECSH yang memanggil / bin / sh -c “ARGUMENTS”. Dengan eksekusi yang terjadi menggunakan nilai yang kami kontrol, kami dapat dengan mudah mencapai eksekusi perintah jarak jauh, semua tanpa otentikasi.

Kami akan merilis laporan lengkap dan Bukti Konsep dengan garis besar yang tepat dalam beberapa bulan.

Memperbarui: Penelitian ini pertama kali dibahas di TechCrunch, baca lebih lanjut di sini.

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