pylinting round3

pull/10/head
Thorsten Sick 3 years ago
parent ab6787241c
commit 12a481da70

@ -1,23 +1,25 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" Module to control Metasploit and related tools (MSFVenom) on the attack server """ """ Module to control Metasploit and related tools (MSFVenom) on the attack server """
import time
import socket
import os
import random
import requests
from pymetasploit3.msfrpc import MsfRpcClient from pymetasploit3.msfrpc import MsfRpcClient
# from app.machinecontrol import Machine # from app.machinecontrol import Machine
from app.attack_log import AttackLog from app.attack_log import AttackLog
from app.interface_sfx import CommandlineColors from app.interface_sfx import CommandlineColors
import time
import socket
from app.exceptions import MetasploitError, ServerError from app.exceptions import MetasploitError, ServerError
import requests
import random
import os
# https://github.com/DanMcInerney/pymetasploit3 # https://github.com/DanMcInerney/pymetasploit3
class Metasploit(): class Metasploit():
""" Metasploit class for basic Metasploit wrapping """
def __init__(self, password, attack_logger, **kwargs): def __init__(self, password, attack_logger, **kwargs):
""" """
@ -42,7 +44,7 @@ class Metasploit():
time.sleep(3) # Waiting for server to start. Or we would get https connection errors when getting the client. time.sleep(3) # Waiting for server to start. Or we would get https connection errors when getting the client.
def start_exploit_stub_for_external_payload(self, payload='linux/x64/meterpreter_reverse_tcp', exploit='exploit/multi/handler'): def start_exploit_stub_for_external_payload(self, payload='linux/x64/meterpreter_reverse_tcp', exploit='exploit/multi/handler'):
""" """ Start a metasploit handler and wait for external payload to connect
@:returns: res, which contains "job_id" and "uuid" @:returns: res, which contains "job_id" and "uuid"
""" """
@ -128,18 +130,18 @@ class Metasploit():
# Get_ip can also return a network name. Matching a session needs a real ip # Get_ip can also return a network name. Matching a session needs a real ip
name_resolution_worked = True name_resolution_worked = True
try: try:
ip = socket.gethostbyname(target.get_ip()) target_ip = socket.gethostbyname(target.get_ip())
except socket.gaierror: except socket.gaierror:
ip = target.get_ip() # Limp on feature if we can not get a name resolution target_ip = target.get_ip() # Limp on feature if we can not get a name resolution
name_resolution_worked = False name_resolution_worked = False
print(f"Name resolution for {target.get_ip()} failed. Sessions are: {self.get_client().sessions.list}") print(f"Name resolution for {target.get_ip()} failed. Sessions are: {self.get_client().sessions.list}")
retries = 100 retries = 100
while retries > 0: while retries > 0:
for k, v in self.get_client().sessions.list.items(): for key, value in self.get_client().sessions.list.items():
if v["session_host"] == ip: if value["session_host"] == target_ip:
# print(f"session list: {self.get_client().sessions.list}") # print(f"session list: {self.get_client().sessions.list}")
return k return key
time.sleep(1) time.sleep(1)
retries -= 1 retries -= 1
@ -180,12 +182,12 @@ class Metasploit():
shell.write(cmd) shell.write(cmd)
time.sleep(delay) time.sleep(delay)
retries = 20 retries = 20
r = "" shell_result = ""
while retries > 0: while retries > 0:
r += shell.read() shell_result += shell.read()
time.sleep(0.5) # Command needs time to execute time.sleep(0.5) # Command needs time to execute
retries -= 1 retries -= 1
res.append(r) res.append(shell_result)
return res return res
@ -223,6 +225,8 @@ class Metasploit():
class MSFVenom(): class MSFVenom():
""" Class to remote controll payload generator MSFVenom on the attacker machine """
def __init__(self, attacker, target, attack_logger: AttackLog): def __init__(self, attacker, target, attack_logger: AttackLog):
""" """
@ -348,23 +352,18 @@ class MetasploitInstant(Metasploit):
""" """
def __init__(self, password, attack_logger, **kwargs):
"""
:param password: password for the msfrpcd
:param attack_logger: The attack logging
:param kwargs: Relevant ones: uri, port, server, username
"""
super().__init__(password, attack_logger, **kwargs)
def parse_ps(self, ps_output): def parse_ps(self, ps_output):
d = [] """ Parses the data from ps
:param ps_output: Metasploit ps output
:return: A list of dicts
"""
ps_data = []
for line in ps_output.split("\n")[6:]: for line in ps_output.split("\n")[6:]:
pieces = line.split(" ") pieces = line.split(" ")
cleaned_pieces = [] cleaned_pieces = []
for p in pieces: for piece in pieces:
if len(p): if len(piece):
cleaned_pieces.append(p) cleaned_pieces.append(piece)
if len(cleaned_pieces) > 2: if len(cleaned_pieces) > 2:
rep = {"PID": int(cleaned_pieces[0].strip()), rep = {"PID": int(cleaned_pieces[0].strip()),
@ -382,9 +381,9 @@ class MetasploitInstant(Metasploit):
rep["User"] = cleaned_pieces[5].strip() rep["User"] = cleaned_pieces[5].strip()
if len(cleaned_pieces) >= 7: if len(cleaned_pieces) >= 7:
rep["Path"] = cleaned_pieces[6].strip() rep["Path"] = cleaned_pieces[6].strip()
d.append(rep) ps_data.append(rep)
return d return ps_data
def filter_ps_results(self, data, user=None, name=None, arch=None): def filter_ps_results(self, data, user=None, name=None, arch=None):
""" Filter the process lists for certain """ Filter the process lists for certain

@ -1,7 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" Manage plugins """ """ Manage plugins """
import straight.plugin
from glob import glob from glob import glob
import os import os
@ -10,6 +9,7 @@ from plugins.base.attack import AttackPlugin
from plugins.base.machinery import MachineryPlugin from plugins.base.machinery import MachineryPlugin
from plugins.base.sensor import SensorPlugin from plugins.base.sensor import SensorPlugin
from plugins.base.vulnerability_plugin import VulnerabilityPlugin from plugins.base.vulnerability_plugin import VulnerabilityPlugin
import straight.plugin
from app.interface_sfx import CommandlineColors from app.interface_sfx import CommandlineColors
# from app.interface_sfx import CommandlineColors # from app.interface_sfx import CommandlineColors
@ -180,15 +180,16 @@ class PluginManager():
# TODO: Add verify command to verify all plugins (or a specific one) # TODO: Add verify command to verify all plugins (or a specific one)
def print_default_config(self, subclass_name, name): def print_default_config(self, subclass_name, name):
""" Pretty prints the default config for this plugin """
subclass = None subclass = None
for a in sections: for section in sections:
if a["name"] == subclass_name: if section["name"] == subclass_name:
subclass = a["subclass"] subclass = section["subclass"]
if subclass is None: if subclass is None:
print("Use proper subclass. Available subclasses are: ") print("Use proper subclass. Available subclasses are: ")
"\n- ".join([a for a in sections["name"]]) "\n- ".join(list(sections["name"]))
plugins = self.get_plugins(subclass, [name]) plugins = self.get_plugins(subclass, [name])
for plugin in plugins: for plugin in plugins:

@ -3,11 +3,10 @@
""" Base class for classes to control any kind of machine: vm, bare metal, cloudified """ """ Base class for classes to control any kind of machine: vm, bare metal, cloudified """
from enum import Enum from enum import Enum
import os
from app.config import MachineConfig from app.config import MachineConfig
from app.interface_sfx import CommandlineColors from app.interface_sfx import CommandlineColors
from plugins.base.plugin_base import BasePlugin from plugins.base.plugin_base import BasePlugin
import os
class MachineStates(Enum): class MachineStates(Enum):

@ -20,28 +20,20 @@ class SensorPlugin(BasePlugin):
super().__init__() # pylint:disable=useless-super-delegation super().__init__() # pylint:disable=useless-super-delegation
self.debugit = False self.debugit = False
def set_sysconf(self, config): def prime(self): # pylint: disable=no-self-use
""" Set system config
@param config: A dict with system configuration relevant for all plugins
"""
super().set_sysconf(config)
def prime(self):
""" prime sets hard core configs in the target. You can use it to call everything that permanently alters the OS by settings. """ prime sets hard core configs in the target. You can use it to call everything that permanently alters the OS by settings.
If your prime function returns True the machine will be rebooted after prime-ing it. This is very likely what you want. Only use prime if install is not sufficient. If your prime function returns True the machine will be rebooted after prime-ing it. This is very likely what you want. Only use prime if install is not sufficient.
""" """
return False return False
def install(self): def install(self): # pylint: disable=no-self-use
""" Install the sensor. Executed on the target. Take the sensor from the share and (maybe) copy it to its destination. Do some setup """ Install the sensor. Executed on the target. Take the sensor from the share and (maybe) copy it to its destination. Do some setup
""" """
return True return True
def start(self, disown=None): def start(self, disown=None): # pylint: disable=unused-argument, no-self-use
""" Start the sensor. The connection to the client is disowned here. = Sent to background. This keeps the process running. """ Start the sensor. The connection to the client is disowned here. = Sent to background. This keeps the process running.
@param disown: Send async into background @param disown: Send async into background
@ -49,7 +41,7 @@ class SensorPlugin(BasePlugin):
return True return True
def stop(self): def stop(self): # pylint: disable=no-self-use
""" Stop the sensor """ """ Stop the sensor """
return True return True

@ -1,22 +1,28 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" A class you can use to add SSH features to you plugin. Useful for vm_controller/machinery classes """ """ A class you can use to add SSH features to you plugin. Useful for vm_controller/machinery classes """
import os.path import os.path
import socket
import time
import paramiko
from fabric import Connection from fabric import Connection
from app.exceptions import NetworkError
from invoke.exceptions import UnexpectedExit from invoke.exceptions import UnexpectedExit
import paramiko from app.exceptions import NetworkError
import time
import socket
from plugins.base.plugin_base import BasePlugin from plugins.base.plugin_base import BasePlugin
class SSHFeatures(BasePlugin): class SSHFeatures(BasePlugin):
""" A Mixin class to add SSH features to all kind of VM machinery """
def __init__(self): def __init__(self):
self.config = None
super().__init__() super().__init__()
self.connection = None self.connection = None
def get_ip(self):
""" Get the IP of a machine, must be overwritten in the machinery class """
raise NotImplementedError
def connect(self): def connect(self):
""" Connect to a machine """ """ Connect to a machine """
@ -79,10 +85,9 @@ class SSHFeatures(BasePlugin):
result = self.connection.run(cmd, disown=disown) result = self.connection.run(cmd, disown=disown)
print(result) print(result)
# paramiko.ssh_exception.SSHException in the next line is needed for windows openssh # paramiko.ssh_exception.SSHException in the next line is needed for windows openssh
except (paramiko.ssh_exception.NoValidConnectionsError, UnexpectedExit, paramiko.ssh_exception.SSHException): except (paramiko.ssh_exception.NoValidConnectionsError, UnexpectedExit, paramiko.ssh_exception.SSHException) as error:
if retry <= 0: if retry <= 0:
raise NetworkError raise NetworkError from error
else:
self.disconnect() self.disconnect()
self.connect() self.connect()
retry -= 1 retry -= 1
@ -122,8 +127,8 @@ class SSHFeatures(BasePlugin):
time.sleep(retry_sleep) time.sleep(retry_sleep)
self.disconnect() self.disconnect()
self.connect() self.connect()
except FileNotFoundError as e: except FileNotFoundError as error:
self.vprint(f"File not found: {e}", 0) self.vprint(f"File not found: {error}", 0)
break break
else: else:
return res return res
@ -146,16 +151,15 @@ class SSHFeatures(BasePlugin):
while retry > 0: while retry > 0:
try: try:
res = self.connection.get(src, dst) res = self.connection.get(src, dst)
except (paramiko.ssh_exception.NoValidConnectionsError, UnexpectedExit): except (paramiko.ssh_exception.NoValidConnectionsError, UnexpectedExit) as error:
if retry <= 0: if retry <= 0:
raise NetworkError raise NetworkError from error
else:
self.disconnect() self.disconnect()
self.connect() self.connect()
retry -= 1 retry -= 1
self.vprint("Got some SSH errors. Retrying", 2) self.vprint("Got some SSH errors. Retrying", 2)
except FileNotFoundError as e: except FileNotFoundError as error:
self.vprint(e, 0) self.vprint(error, 0)
break break
else: else:
break break

Loading…
Cancel
Save