|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
""" Pydantic verifier for config structure """
|
|
|
|
|
|
|
|
from enum import Enum
|
|
|
|
from typing import Optional
|
|
|
|
from pydantic.dataclasses import dataclass
|
|
|
|
from pydantic import conlist # pylint: disable=no-name-in-module
|
|
|
|
|
|
|
|
# TODO: Move from has_key to iterators and "is in"
|
|
|
|
|
|
|
|
|
|
|
|
class OSEnum(str, Enum):
|
|
|
|
""" List of all supported OS-es """
|
|
|
|
LINUX = "linux"
|
|
|
|
WINDOWS = "windows"
|
|
|
|
|
|
|
|
|
|
|
|
class VMControllerTypeEnum(str, Enum):
|
|
|
|
""" List of all supported controlled plugins. This is only done for VM controller plugins !
|
|
|
|
I do not expect many new ones. And typos in config can be a waste of time. Let's see if I am right. """
|
|
|
|
VAGRANT = "vagrant"
|
|
|
|
RUNNING_VM = "running_vm"
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class CalderaConfig:
|
|
|
|
""" Configuration for the Caldera server """
|
|
|
|
apikey: str
|
|
|
|
|
|
|
|
def has_key(self, keyname):
|
|
|
|
""" Checks if a key exists
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if keyname in self.__dict__.keys():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class VMController:
|
|
|
|
""" Configuration for the VM controller """
|
|
|
|
vm_type: VMControllerTypeEnum
|
|
|
|
vagrantfilepath: str
|
|
|
|
ip: Optional[str] = "" # pylint: disable=invalid-name
|
|
|
|
|
|
|
|
def has_key(self, keyname):
|
|
|
|
""" Checks if a key exists
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if keyname in self.__dict__.keys():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
# def __dict__(self):
|
|
|
|
# return {"vm_type": self.vm_type,
|
|
|
|
# "vagrantfilepath": self.vagrantfilepath,
|
|
|
|
# "ip": self.ip}
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class Attacker:
|
|
|
|
""" Configuration for a attacker VM """
|
|
|
|
name: str
|
|
|
|
vm_controller: VMController
|
|
|
|
vm_name: str
|
|
|
|
nicknames: Optional[list[str]]
|
|
|
|
machinepath: str
|
|
|
|
os: OSEnum # pylint: disable=invalid-name
|
|
|
|
use_existing_machine: bool = False
|
|
|
|
playground: Optional[str] = None
|
|
|
|
|
|
|
|
def has_key(self, keyname):
|
|
|
|
""" Checks if a key exists
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if keyname in self.__dict__.keys():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get(self, keyname, default=None):
|
|
|
|
""" Returns the value of a specific key
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if self.has_key(keyname):
|
|
|
|
return self.__dict__[keyname]
|
|
|
|
return default
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class Target:
|
|
|
|
""" Configuration for a target VM """
|
|
|
|
name: str
|
|
|
|
vm_controller: VMController
|
|
|
|
vm_name: str
|
|
|
|
os: OSEnum # pylint: disable=invalid-name
|
|
|
|
paw: str
|
|
|
|
group: str
|
|
|
|
machinepath: str
|
|
|
|
sensors: Optional[list[str]]
|
|
|
|
nicknames: Optional[list[str]]
|
|
|
|
active: bool = True
|
|
|
|
use_existing_machine: bool = False
|
|
|
|
playground: Optional[str] = None
|
|
|
|
halt_needs_force: Optional[str] = None
|
|
|
|
ssh_user: Optional[str] = None
|
|
|
|
ssh_password: Optional[str] = None
|
|
|
|
ssh_keyfile: Optional[str] = None
|
|
|
|
vulnerabilities: list[str] = None
|
|
|
|
|
|
|
|
def has_key(self, keyname):
|
|
|
|
""" Checks if a key exists
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if keyname in self.__dict__.keys():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get(self, keyname, default=None):
|
|
|
|
""" Returns the value of a specific key
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if self.has_key(keyname):
|
|
|
|
return self.__dict__[keyname]
|
|
|
|
return default
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class AttackConfig:
|
|
|
|
""" Generic configuration for attacks """
|
|
|
|
caldera_obfuscator: str = "plain-text"
|
|
|
|
caldera_jitter: str = "4/8"
|
|
|
|
nap_time: int = 5
|
|
|
|
|
|
|
|
def has_key(self, keyname):
|
|
|
|
""" Checks if a key exists
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if keyname in self.__dict__.keys():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class AttackList:
|
|
|
|
""" A list of attacks to run. Either plugin based or caldera based """
|
|
|
|
linux: Optional[list[str]]
|
|
|
|
windows: Optional[list[str]]
|
|
|
|
|
|
|
|
def has_key(self, keyname):
|
|
|
|
""" Checks if a key exists
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if keyname in self.__dict__.keys():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get(self, keyname, default=None):
|
|
|
|
""" Returns the value of a specific key
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if self.has_key(keyname):
|
|
|
|
return self.__dict__[keyname]
|
|
|
|
return default
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class Results:
|
|
|
|
""" What to do with the results """
|
|
|
|
loot_dir: str
|
|
|
|
|
|
|
|
def has_key(self, keyname):
|
|
|
|
""" Checks if a key exists
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if keyname in self.__dict__.keys():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class MainConfig:
|
|
|
|
""" Central configuration for PurpleDome """
|
|
|
|
caldera: CalderaConfig
|
|
|
|
attackers: conlist(Attacker, min_items=1)
|
|
|
|
targets: conlist(Target, min_items=1)
|
|
|
|
attacks: AttackConfig
|
|
|
|
caldera_attacks: AttackList
|
|
|
|
plugin_based_attacks: AttackList
|
|
|
|
results: Results
|
|
|
|
|
|
|
|
# Free form configuration for plugins
|
|
|
|
attack_conf: Optional[dict]
|
|
|
|
sensor_conf: Optional[dict]
|
|
|
|
|
|
|
|
def has_key(self, keyname):
|
|
|
|
""" Checks if a key exists
|
|
|
|
Required for compatibility with DotMap which is used in Unit tests
|
|
|
|
"""
|
|
|
|
if keyname in self.__dict__.keys():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: Check for name duplication
|