added verbosity switch

pull/3/head
Thorsten Sick 3 years ago
parent 73f0e40d99
commit 28b6ffb211

@ -25,8 +25,13 @@ def __mitre_fix_ttp__(ttp):
class AttackLog(): class AttackLog():
""" A specific logger class to log the progress of the attack steps """ """ A specific logger class to log the progress of the attack steps """
def __init__(self): def __init__(self, verbosity=0):
"""
@param verbosity: verbosity setting from 0 to 3 for stdout printing
"""
self.log = [] self.log = []
self.verbosity = verbosity
def start_caldera_attack(self, source, paw, group, ability_id, ttp=None, name=None, description=None): # pylint: disable=too-many-arguments def start_caldera_attack(self, source, paw, group, ability_id, ttp=None, name=None, description=None): # pylint: disable=too-many-arguments
""" Mark the start of a caldera attack """ Mark the start of a caldera attack
@ -141,3 +146,18 @@ class AttackLog():
""" Return logged data in dict format """ """ Return logged data in dict format """
return self.log return self.log
def vprint(self, text, verbosity):
""" verbosity based stdout printing
0: Errors only
1: Main colored information
2: Detailed progress information
3: Debug logs, data dumps, everything
@param text: The text to print
@param verbosity: the verbosity level the text has.
"""
if verbosity <= self.verbosity:
print(text)

@ -23,15 +23,16 @@ from pprint import pprint
class CalderaControl(): class CalderaControl():
""" Remote control Caldera through REST api """ """ Remote control Caldera through REST api """
def __init__(self, server, config=None, apikey=None): def __init__(self, server, attack_logger, config=None, apikey=None):
""" """
@param server: Caldera server url/ip @param server: Caldera server url/ip
@param attack_logger: The attack logger to use
@param config: The configuration @param config: The configuration
""" """
# print(server) # print(server)
self.url = server if server.endswith("/") else server + "/" self.url = server if server.endswith("/") else server + "/"
self.attack_logger = attack_logger
self.config = config self.config = config
@ -516,28 +517,28 @@ class CalderaControl():
# ##### Create / Run Operation # ##### Create / Run Operation
print(f"New adversary generated. ID: {adid}, ability: {ability_id} group: {group}") self.attack_logger.vprint(f"New adversary generated. ID: {adid}, ability: {ability_id} group: {group}", 2)
res = self.add_operation(operation_name, advid=adid, group=group) res = self.add_operation(operation_name, advid=adid, group=group)
print("Add operation: ") # print("Add operation: ")
pprint(res) # pprint(res)
opid = self.get_operation(operation_name)["id"] opid = self.get_operation(operation_name)["id"]
print("New operation created. OpID: " + str(opid)) self.attack_logger.vprint("New operation created. OpID: " + str(opid), 3)
self.execute_operation(opid) self.execute_operation(opid)
print("Execute operation") self.attack_logger.vprint("Execute operation",3 )
retries = 30 retries = 30
ability_name = self.get_ability(ability_id)[0]["name"] ability_name = self.get_ability(ability_id)[0]["name"]
ability_description = self.get_ability(ability_id)[0]["description"] ability_description = self.get_ability(ability_id)[0]["description"]
print(f"{CommandlineColors.OKBLUE}Executed attack operation{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Executed attack operation{CommandlineColors.ENDC}",1)
print(f"{CommandlineColors.BACKGROUND_BLUE} PAW: {paw} Group: {group} Ability: {ability_id} {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.BACKGROUND_BLUE} PAW: {paw} Group: {group} Ability: {ability_id} {CommandlineColors.ENDC}", 1)
print(f"{CommandlineColors.BACKGROUND_BLUE} {ability_name}: {ability_description} {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.BACKGROUND_BLUE} {ability_name}: {ability_description} {CommandlineColors.ENDC}", 1)
while not self.is_operation_finished(opid) and retries > 0: while not self.is_operation_finished(opid) and retries > 0:
print(f".... waiting for Caldera to finish {retries}") self.attack_logger.vprint(f".... waiting for Caldera to finish {retries}", 2)
time.sleep(10) time.sleep(10)
retries -= 1 retries -= 1
if retries <= 0: if retries <= 0:
print(f"{CommandlineColors.FAIL}Ran into retry timeout waiting for attack to finish{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.FAIL}Ran into retry timeout waiting for attack to finish{CommandlineColors.ENDC}", 1)
# TODO: Handle outout from several clients # TODO: Handle outout from several clients
@ -548,7 +549,7 @@ class CalderaControl():
retries -= 1 retries -= 1
time.sleep(10) time.sleep(10)
output = self.view_operation_output(opid, paw, ability_id) output = self.view_operation_output(opid, paw, ability_id)
print(f".... getting Caldera output {retries}") self.attack_logger.vprint(f".... getting Caldera output {retries}", 2)
if output: if output:
break break
except CalderaError: except CalderaError:
@ -556,10 +557,10 @@ class CalderaControl():
if output is None: if output is None:
output = str(self.get_operation_by_id(opid)) output = str(self.get_operation_by_id(opid))
print(f"{CommandlineColors.FAIL}Failed getting operation data. We just have: {output} from get_operation_by_id{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.FAIL}Failed getting operation data. We just have: {output} from get_operation_by_id{CommandlineColors.ENDC}", 0)
else: else:
outp = str(output) outp = str(output)
print(f"{CommandlineColors.BACKGROUND_GREEN} Output: {outp} {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.BACKGROUND_GREEN} Output: {outp} {CommandlineColors.ENDC}", 2)
pprint(output) pprint(output)
# ######## Cleanup # ######## Cleanup

@ -22,21 +22,22 @@ from app.exceptions import ServerError
class Experiment(): class Experiment():
""" Class handling experiments """ """ Class handling experiments """
def __init__(self, configfile): def __init__(self, configfile, verbosity=0):
""" """
@param configfile: Path to the configfile to load """ @param configfile: Path to the configfile to load
@param verbosity: verbosity level between 0 and 3
"""
self.attacker_1 = None self.attacker_1 = None
self.experiment_control = ExperimentConfig(configfile) self.experiment_control = ExperimentConfig(configfile)
self.attack_logger = AttackLog() self.attack_logger = AttackLog(verbosity)
self.__start_attacker() self.__start_attacker()
caldera_url = "http://" + self.attacker_1.getip() + ":8888" caldera_url = "http://" + self.attacker_1.getip() + ":8888"
caldera_control = CalderaControl(caldera_url, config=self.experiment_control) caldera_control = CalderaControl(caldera_url, attack_logger=self.attack_logger, config=self.experiment_control)
# Deleting all currently registered Caldera gents # Deleting all currently registered Caldera gents
print(caldera_control.kill_all_agents()) self.attack_logger.vprint(caldera_control.kill_all_agents(), 3)
print(caldera_control.delete_all_agents()) self.attack_logger.vprint(caldera_control.delete_all_agents(), 3)
self.starttime = datetime.now().strftime("%Y_%m_%d___%H_%M_%S") self.starttime = datetime.now().strftime("%Y_%m_%d___%H_%M_%S")
self.lootdir = os.path.join(self.experiment_control.loot_dir(), self.starttime) self.lootdir = os.path.join(self.experiment_control.loot_dir(), self.starttime)
@ -50,8 +51,8 @@ class Experiment():
tname = target_conf.vmname() tname = target_conf.vmname()
print(f"{CommandlineColors.OKBLUE}preparing target {tname} ....{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}preparing target {tname} ....{CommandlineColors.ENDC}", 1)
target_1 = Machine(target_conf) target_1 = Machine(target_conf, attack_logger=self.attack_logger)
target_1.set_caldera_server(self.attacker_1.getip()) target_1.set_caldera_server(self.attacker_1.getip())
try: try:
if not target_conf.use_existing_machine(): if not target_conf.use_existing_machine():
@ -64,43 +65,43 @@ class Experiment():
needs_reboot = target_1.prime_sensors() needs_reboot = target_1.prime_sensors()
if needs_reboot: if needs_reboot:
target_1.reboot() target_1.reboot()
print(f"{CommandlineColors.OKGREEN}Target is up: {tname} {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Target is up: {tname} {CommandlineColors.ENDC}",1)
self.targets.append(target_1) self.targets.append(target_1)
# Install vulnerabilities # Install vulnerabilities
for a_target in self.targets: for a_target in self.targets:
print(f"Installing vulnerabilities on {a_target.get_paw()}") self.attack_logger.vprint(f"Installing vulnerabilities on {a_target.get_paw()}",2)
a_target.install_vulnerabilities() a_target.install_vulnerabilities()
a_target.start_vulnerabilities() a_target.start_vulnerabilities()
# Install sensor plugins # Install sensor plugins
for a_target in self.targets: for a_target in self.targets:
print(f"Installing sensors on {a_target.get_paw()}") self.attack_logger.vprint(f"Installing sensors on {a_target.get_paw()}",2)
a_target.install_sensors() a_target.install_sensors()
a_target.start_sensors() a_target.start_sensors()
# First start of caldera implants # First start of caldera implants
for target_1 in self.targets: for target_1 in self.targets:
target_1.start_caldera_client() target_1.start_caldera_client()
print(f"{CommandlineColors.OKGREEN}Initial start of caldera client: {tname} {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Initial start of caldera client: {tname} {CommandlineColors.ENDC}", 1)
time.sleep(20) # Wait for all the clients to contact the caldera server time.sleep(20) # Wait for all the clients to contact the caldera server
print(f"{CommandlineColors.OKBLUE}Contacting caldera agents on all targets ....{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Contacting caldera agents on all targets ....{CommandlineColors.ENDC}", 1)
# Wait until all targets are registered as Caldera targets # Wait until all targets are registered as Caldera targets
for target_1 in self.targets: for target_1 in self.targets:
running_agents = caldera_control.list_paws_of_running_agents() running_agents = caldera_control.list_paws_of_running_agents()
print(f"Agents currently running: {running_agents}") self.attack_logger.vprint(f"Agents currently running: {running_agents}", 2)
while target_1.get_paw() not in running_agents: while target_1.get_paw() not in running_agents:
print(f"Connecting to caldera {caldera_url}, running agents are: {running_agents}") self.attack_logger.vprint(f"Connecting to caldera {caldera_url}, running agents are: {running_agents}", 3)
print(f"Missing agent: {target_1.get_paw()} ...") self.attack_logger.vprint(f"Missing agent: {target_1.get_paw()} ...", 3)
target_1.start_caldera_client() target_1.start_caldera_client()
print(f"Restarted caldera agent: {target_1.get_paw()} ...") self.attack_logger.vprint(f"Restarted caldera agent: {target_1.get_paw()} ...", )
time.sleep(120) # Was 30, but maybe there are timing issues time.sleep(120) # Was 30, but maybe there are timing issues
running_agents = caldera_control.list_paws_of_running_agents() running_agents = caldera_control.list_paws_of_running_agents()
print(f"{CommandlineColors.OKGREEN}Caldera agents reached{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Caldera agents reached{CommandlineColors.ENDC}", 1)
# Attack them # Attack them
print(f"{CommandlineColors.OKBLUE}Running Caldera attacks{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Running Caldera attacks{CommandlineColors.ENDC}",1 )
for target_1 in self.targets: for target_1 in self.targets:
# Run caldera attacks # Run caldera attacks
caldera_attacks = self.experiment_control.get_caldera_attacks(target_1.get_os()) caldera_attacks = self.experiment_control.get_caldera_attacks(target_1.get_os())
@ -108,8 +109,8 @@ class Experiment():
for attack in caldera_attacks: for attack in caldera_attacks:
# TODO: Work with snapshots # TODO: Work with snapshots
# TODO: If we have several targets in the same group, it is nonsense to attack each one separately. Make this smarter # TODO: If we have several targets in the same group, it is nonsense to attack each one separately. Make this smarter
print(f"Attacking machine with PAW: {target_1.get_paw()} with {attack}") self.attack_logger.vprint(f"Attacking machine with PAW: {target_1.get_paw()} with {attack}", 2)
caldera_control = CalderaControl("http://" + self.attacker_1.getip() + ":8888", config=self.experiment_control) caldera_control = CalderaControl("http://" + self.attacker_1.getip() + ":8888", self.attack_logger, config=self.experiment_control)
caldera_control.attack(attack_logger=self.attack_logger, paw=target_1.get_paw(), ability_id=attack, group=target_1.get_group()) caldera_control.attack(attack_logger=self.attack_logger, paw=target_1.get_paw(), ability_id=attack, group=target_1.get_group())
@ -119,38 +120,38 @@ class Experiment():
# Fix: Caldera sometimes gets stuck. This is why we better re-start the caldera server and wait till all the implants re-connected # Fix: Caldera sometimes gets stuck. This is why we better re-start the caldera server and wait till all the implants re-connected
# Reason: In some scenarios we keep the infra up for hours or days. No re-creation like intended. This can cause Caldera to hick up # Reason: In some scenarios we keep the infra up for hours or days. No re-creation like intended. This can cause Caldera to hick up
print(f"{CommandlineColors.OKBLUE}Restarting caldera server and waiting for clients to re-connect{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Restarting caldera server and waiting for clients to re-connect{CommandlineColors.ENDC}", 1)
self.attacker_1.start_caldera_server() self.attacker_1.start_caldera_server()
print(f"Pausing before next attack (config: nap_time): {self.experiment_control.get_nap_time()}") self.attack_logger.vprint(f"Pausing before next attack (config: nap_time): {self.experiment_control.get_nap_time()}", 2)
time.sleep(self.experiment_control.get_nap_time()) time.sleep(self.experiment_control.get_nap_time())
retries = 100 retries = 100
for target_system in self.targets: for target_system in self.targets:
running_agents = caldera_control.list_paws_of_running_agents() running_agents = caldera_control.list_paws_of_running_agents()
print(f"Agents currently connected to the server: {running_agents}") self.attack_logger.vprint(f"Agents currently connected to the server: {running_agents}", 2)
while target_system.get_paw() not in running_agents: while target_system.get_paw() not in running_agents:
time.sleep(1) time.sleep(1)
running_agents = caldera_control.list_paws_of_running_agents() running_agents = caldera_control.list_paws_of_running_agents()
retries -= 1 retries -= 1
print(f"Waiting for clients to re-connect ({retries}, {running_agents}) ") self.attack_logger.vprint(f"Waiting for clients to re-connect ({retries}, {running_agents}) ", 3)
if retries <= 0: if retries <= 0:
raise ServerError raise ServerError
print(f"{CommandlineColors.OKGREEN}Restarted caldera server clients re-connected{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Restarted caldera server clients re-connected{CommandlineColors.ENDC}", 1)
# End of fix # End of fix
print(f"{CommandlineColors.OKGREEN}Finished Caldera attacks{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Finished Caldera attacks{CommandlineColors.ENDC}", 1)
# Run Kali attacks # Run Kali attacks
print(f"{CommandlineColors.OKBLUE}Running Kali attacks{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Running Kali attacks{CommandlineColors.ENDC}", 1)
for target_1 in self.targets: for target_1 in self.targets:
kali_attacks = self.experiment_control.get_kali_attacks(target_1.get_os()) kali_attacks = self.experiment_control.get_kali_attacks(target_1.get_os())
for attack in kali_attacks: for attack in kali_attacks:
# TODO: Work with snapshots # TODO: Work with snapshots
print(f"Attacking machine with PAW: {target_1.get_paw()} with attack: {attack}") self.attack_logger.vprint(f"Attacking machine with PAW: {target_1.get_paw()} with attack: {attack}", 1)
self.attacker_1.kali_attack(attack, target_1.getip(), self.experiment_control) self.attacker_1.kali_attack(attack, target_1.getip(), self.experiment_control)
print(f"Pausing before next attack (config: nap_time): {self.experiment_control.get_nap_time()}") self.attack_logger.vprint(f"Pausing before next attack (config: nap_time): {self.experiment_control.get_nap_time()}", 3)
time.sleep(self.experiment_control.get_nap_time()) time.sleep(self.experiment_control.get_nap_time())
print(f"{CommandlineColors.OKGREEN}Finished Kali attacks{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Finished Kali attacks{CommandlineColors.ENDC}", 1)
# Stop sensor plugins # Stop sensor plugins
# Collect data # Collect data
@ -160,8 +161,10 @@ class Experiment():
# Uninstall vulnerabilities # Uninstall vulnerabilities
for a_target in self.targets: for a_target in self.targets:
print(f"Uninstalling vulnerabilities on {a_target.get_paw()}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE} Uninstalling vulnerabilities on {a_target.get_paw()} {CommandlineColors.ENDC}", 1)
a_target.stop_vulnerabilities() a_target.stop_vulnerabilities()
self.attack_logger.vprint(f"{CommandlineColors.OKGREEN} Done uninstalling vulnerabilities on {a_target.get_paw()} {CommandlineColors.ENDC}",
1)
# Stop target machines # Stop target machines
for target_1 in self.targets: for target_1 in self.targets:
@ -181,14 +184,14 @@ class Experiment():
] ]
print(f"Creating zip file {filename}") self.attack_logger.vprint(f"Creating zip file {filename}", 1)
with zipfile.ZipFile(filename, "w") as zfh: with zipfile.ZipFile(filename, "w") as zfh:
for a_glob in globs: for a_glob in globs:
a_glob = self.lootdir + a_glob a_glob = self.lootdir + a_glob
for a_file in glob.iglob(a_glob, recursive=True): for a_file in glob.iglob(a_glob, recursive=True):
if a_file != filename: if a_file != filename:
print(a_file) self.attack_logger.vprint(a_file, 2)
zfh.write(a_file) zfh.write(a_file)
@staticmethod @staticmethod
@ -226,13 +229,13 @@ class Experiment():
except FileExistsError: except FileExistsError:
pass pass
for a_file in self.__get_results_files(root): for a_file in self.__get_results_files(root):
print("Copy {} {}".format(a_file, os.path.abspath(self.experiment_control.loot_dir()))) self.attack_logger.vprint("Copy {} {}".format(a_file, os.path.abspath(self.experiment_control.loot_dir())), 3)
def __start_attacker(self): def __start_attacker(self):
""" Start the attacking VM """ """ Start the attacking VM """
# Preparing attacker # Preparing attacker
self.attacker_1 = Machine(self.experiment_control.attacker(0).raw_config) self.attacker_1 = Machine(self.experiment_control.attacker(0).raw_config, attack_logger=self.attack_logger)
if not self.experiment_control.attacker(0).use_existing_machine(): if not self.experiment_control.attacker(0).use_existing_machine():
try: try:
@ -248,7 +251,7 @@ class Experiment():
self.attacker_1.install_caldera_server(cleanup=False) self.attacker_1.install_caldera_server(cleanup=False)
self.attacker_1.start_caldera_server() self.attacker_1.start_caldera_server()
self.attacker_1.set_attack_logger(self.attack_logger) # self.attacker_1.set_attack_logger(self.attack_logger)
def __stop_attacker(self): def __stop_attacker(self):
""" Stop the attacking VM """ """ Stop the attacking VM """

@ -21,22 +21,24 @@ from plugins.base.vulnerability_plugin import VulnerabilityPlugin
class Machine(): class Machine():
""" A virtual machine. Attacker or target. Abstracting stuff away. """ """ A virtual machine. Attacker or target. Abstracting stuff away. """
def __init__(self, config, calderakey="ADMIN123"): def __init__(self, config, attack_logger, calderakey="ADMIN123",):
""" """
@param config: The machine configuration as dict @param config: The machine configuration as dict
@param attack_logger: The attack logger to use
@param calderakey: Key to the caldera controller @param calderakey: Key to the caldera controller
""" """
self.vm_manager = None self.vm_manager = None
self.attack_logger = None self.attack_logger = None
self.set_attack_logger(attack_logger)
if isinstance(config, MachineConfig): if isinstance(config, MachineConfig):
self.config = config self.config = config
else: else:
self.config = MachineConfig(config) self.config = MachineConfig(config)
self.plugin_manager = PluginManager() self.plugin_manager = PluginManager(self.attack_logger)
# TODO: Read config from plugin # TODO: Read config from plugin
if self.config.vmcontroller() == "vagrant": if self.config.vmcontroller() == "vagrant":
@ -111,7 +113,7 @@ class Machine():
while not res: while not res:
time.sleep(5) time.sleep(5)
res = self.vm_manager.__call_connect__() res = self.vm_manager.__call_connect__()
print("Re-connecting....") self.attack_logger.vprint("Re-connecting....", 3)
def up(self): # pylint: disable=invalid-name def up(self): # pylint: disable=invalid-name
""" Starts a VM. Creates it if not already created """ """ Starts a VM. Creates it if not already created """
@ -159,13 +161,13 @@ class Machine():
for plugin in self.plugin_manager.get_plugins(KaliPlugin, [attack]): for plugin in self.plugin_manager.get_plugins(KaliPlugin, [attack]):
name = plugin.get_name() name = plugin.get_name()
print(f"{CommandlineColors.OKBLUE}Running Kali plugin {name}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Running Kali plugin {name}{CommandlineColors.ENDC}", 2)
syscon = {"abs_machinepath_internal": self.abs_machinepath_internal, syscon = {"abs_machinepath_internal": self.abs_machinepath_internal,
"abs_machinepath_external": self.abs_machinepath_external} "abs_machinepath_external": self.abs_machinepath_external}
plugin.set_sysconf(syscon) plugin.set_sysconf(syscon)
plugin.process_config(config.kali_conf(name)) plugin.process_config(config.kali_conf(plugin.get_config_section_name()))
plugin.set_machine_plugin(self.vm_manager) plugin.set_machine_plugin(self.vm_manager)
plugin.__set_logger__(self.attack_logger) # plugin.__set_logger__(self.attack_logger)
plugin.__execute__([target]) plugin.__execute__([target])
def load_machine_plugin(self): def load_machine_plugin(self):
@ -174,13 +176,15 @@ class Machine():
for plugin in self.plugin_manager.get_plugins(MachineryPlugin, [self.config.vmcontroller()]): for plugin in self.plugin_manager.get_plugins(MachineryPlugin, [self.config.vmcontroller()]):
name = plugin.get_name() name = plugin.get_name()
print(f"{CommandlineColors.OKBLUE}Installing machinery: {name}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Installing machinery: {name}{CommandlineColors.ENDC}", 1)
syscon = {"abs_machinepath_internal": self.abs_machinepath_internal, syscon = {"abs_machinepath_internal": self.abs_machinepath_internal,
"abs_machinepath_external": self.abs_machinepath_external} "abs_machinepath_external": self.abs_machinepath_external}
plugin.set_sysconf(syscon) plugin.set_sysconf(syscon)
plugin.__call_process_config__(self.config) plugin.__call_process_config__(self.config)
self.vm_manager = plugin self.vm_manager = plugin
self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Installed machinery: {name}{CommandlineColors.ENDC}",
1)
break break
def prime_sensors(self): def prime_sensors(self):
@ -195,7 +199,7 @@ class Machine():
for plugin in self.plugin_manager.get_plugins(SensorPlugin, self.config.sensors()): for plugin in self.plugin_manager.get_plugins(SensorPlugin, self.config.sensors()):
name = plugin.get_name() name = plugin.get_name()
# if name in self.config.sensors(): # if name in self.config.sensors():
print(f"{CommandlineColors.OKBLUE}Priming sensor: {name}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Priming sensor: {name}{CommandlineColors.ENDC}", 2)
syscon = {"abs_machinepath_internal": self.abs_machinepath_internal, syscon = {"abs_machinepath_internal": self.abs_machinepath_internal,
"abs_machinepath_external": self.abs_machinepath_external, "abs_machinepath_external": self.abs_machinepath_external,
} }
@ -206,7 +210,7 @@ class Machine():
plugin.setup() plugin.setup()
reboot |= plugin.prime() reboot |= plugin.prime()
self.sensors.append(plugin) self.sensors.append(plugin)
print(f"{CommandlineColors.OKGREEN}Primed sensor: {name}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Primed sensor: {name}{CommandlineColors.ENDC}", 2)
return reboot return reboot
def install_sensors(self): def install_sensors(self):
@ -219,7 +223,7 @@ class Machine():
for plugin in self.get_sensors(): for plugin in self.get_sensors():
name = plugin.get_name() name = plugin.get_name()
print(f"{CommandlineColors.OKBLUE}Installing sensor: {name}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Installing sensor: {name}{CommandlineColors.ENDC}", 2)
syscon = {"abs_machinepath_internal": self.abs_machinepath_internal, syscon = {"abs_machinepath_internal": self.abs_machinepath_internal,
"abs_machinepath_external": self.abs_machinepath_external, "abs_machinepath_external": self.abs_machinepath_external,
} }
@ -228,7 +232,7 @@ class Machine():
plugin.process_config(self.config.raw_config.get(name, {})) # plugin specific configuration plugin.process_config(self.config.raw_config.get(name, {})) # plugin specific configuration
plugin.setup() plugin.setup()
plugin.install() plugin.install()
print(f"{CommandlineColors.OKGREEN}Installed sensor: {name}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Installed sensor: {name}{CommandlineColors.ENDC}", 2)
def get_sensors(self) -> [SensorPlugin]: def get_sensors(self) -> [SensorPlugin]:
""" Returns a list of running sensors """ """ Returns a list of running sensors """
@ -241,10 +245,10 @@ class Machine():
""" """
for plugin in self.get_sensors(): for plugin in self.get_sensors():
print(f"{CommandlineColors.OKBLUE}Starting sensor: {plugin.get_name()}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Starting sensor: {plugin.get_name()}{CommandlineColors.ENDC}", 2)
plugin.set_machine_plugin(self.vm_manager) plugin.set_machine_plugin(self.vm_manager)
plugin.start() plugin.start()
print(f"{CommandlineColors.OKGREEN}Started sensor: {plugin.get_name()}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Started sensor: {plugin.get_name()}{CommandlineColors.ENDC}", 2)
def stop_sensors(self): def stop_sensors(self):
""" Stop sensors """ Stop sensors
@ -254,10 +258,10 @@ class Machine():
""" """
for plugin in self.get_sensors(): for plugin in self.get_sensors():
print(f"{CommandlineColors.OKBLUE}Stopping sensor: {plugin.get_name()}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Stopping sensor: {plugin.get_name()}{CommandlineColors.ENDC}", 2)
plugin.set_machine_plugin(self.vm_manager) plugin.set_machine_plugin(self.vm_manager)
plugin.stop() plugin.stop()
print(f"{CommandlineColors.OKGREEN}Stopped sensor: {plugin.get_name()}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Stopped sensor: {plugin.get_name()}{CommandlineColors.ENDC}", 2)
def collect_sensors(self, lootdir): def collect_sensors(self, lootdir):
""" Collect data from sensors """ Collect data from sensors
@ -271,10 +275,10 @@ class Machine():
os.mkdir(machine_specific_path) os.mkdir(machine_specific_path)
for plugin in self.get_sensors(): for plugin in self.get_sensors():
print(f"{CommandlineColors.OKBLUE}Collecting sensor: {plugin.get_name()}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Collecting sensor: {plugin.get_name()}{CommandlineColors.ENDC}",2 )
plugin.set_machine_plugin(self.vm_manager) plugin.set_machine_plugin(self.vm_manager)
plugin.__call_collect__(machine_specific_path) plugin.__call_collect__(machine_specific_path)
print(f"{CommandlineColors.OKGREEN}Collected sensor: {plugin.get_name()}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Collected sensor: {plugin.get_name()}{CommandlineColors.ENDC}",2 )
############ ############
@ -287,8 +291,8 @@ class Machine():
for plugin in self.plugin_manager.get_plugins(VulnerabilityPlugin, self.config.vulnerabilities()): for plugin in self.plugin_manager.get_plugins(VulnerabilityPlugin, self.config.vulnerabilities()):
name = plugin.get_name() name = plugin.get_name()
print(f"Configured vulnerabilities: {self.config.vulnerabilities()}") self.attack_logger.vprint(f"Configured vulnerabilities: {self.config.vulnerabilities()}",3 )
print(f"{CommandlineColors.OKBLUE}Installing vulnerability: {name}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Installing vulnerability: {name}{CommandlineColors.ENDC}", 2)
syscon = {"abs_machinepath_internal": self.abs_machinepath_internal, syscon = {"abs_machinepath_internal": self.abs_machinepath_internal,
"abs_machinepath_external": self.abs_machinepath_external} "abs_machinepath_external": self.abs_machinepath_external}
plugin.set_sysconf(syscon) plugin.set_sysconf(syscon)
@ -309,7 +313,7 @@ class Machine():
""" """
for plugin in self.get_vulnerabilities(): for plugin in self.get_vulnerabilities():
print(f"{CommandlineColors.OKBLUE}Activating vulnerability: {plugin.get_name()}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Activating vulnerability: {plugin.get_name()}{CommandlineColors.ENDC}",2 )
plugin.set_machine_plugin(self.vm_manager) plugin.set_machine_plugin(self.vm_manager)
plugin.start() plugin.start()
@ -320,7 +324,7 @@ class Machine():
""" """
for plugin in self.get_vulnerabilities(): for plugin in self.get_vulnerabilities():
print(f"{CommandlineColors.OKBLUE}Uninstalling vulnerability: {plugin.get_name()}{CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Uninstalling vulnerability: {plugin.get_name()}{CommandlineColors.ENDC}", 2)
plugin.set_machine_plugin(self.vm_manager) plugin.set_machine_plugin(self.vm_manager)
plugin.stop() plugin.stop()
@ -342,7 +346,7 @@ class Machine():
@param version: Caldera version to use. Check Caldera git for potential branches to use @param version: Caldera version to use. Check Caldera git for potential branches to use
""" """
# https://github.com/mitre/caldera.git # https://github.com/mitre/caldera.git
print(f"{CommandlineColors.OKBLUE}Installing Caldera server {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Installing Caldera server {CommandlineColors.ENDC}", 1)
if cleanup: if cleanup:
cleanupcmd = "rm -rf caldera;" cleanupcmd = "rm -rf caldera;"
@ -350,7 +354,7 @@ class Machine():
cleanupcmd = "" cleanupcmd = ""
cmd = f"cd {self.caldera_basedir}; {cleanupcmd} git clone https://github.com/mitre/caldera.git --recursive --branch {version}; cd caldera; pip3 install -r requirements.txt" cmd = f"cd {self.caldera_basedir}; {cleanupcmd} git clone https://github.com/mitre/caldera.git --recursive --branch {version}; cd caldera; pip3 install -r requirements.txt"
print(f"{CommandlineColors.OKGREEN}Caldera server installed {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Caldera server installed {CommandlineColors.ENDC}", 1)
res = self.vm_manager.__call_remote_run__(cmd) res = self.vm_manager.__call_remote_run__(cmd)
return "Result installing caldera server " + str(res) return "Result installing caldera server " + str(res)
@ -362,14 +366,14 @@ class Machine():
for i in range(timeout): for i in range(timeout):
time.sleep(10) time.sleep(10)
caldera_url = "http://" + self.getip() + ":8888" caldera_url = "http://" + self.getip() + ":8888"
caldera_control = CalderaControl(caldera_url, apikey=self.calderakey) caldera_control = CalderaControl(caldera_url, self.attack_logger, apikey=self.calderakey)
print(f"{i} Trying to connect to {caldera_url} Caldera API") self.attack_logger.vprint(f"{i} Trying to connect to {caldera_url} Caldera API", 3)
try: try:
caldera_control.list_adversaries() caldera_control.list_adversaries()
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
pass pass
else: else:
print("Caldera: All systems nominal") self.attack_logger.vprint("Caldera: All systems nominal", 3)
return True return True
raise ServerError raise ServerError
@ -377,14 +381,14 @@ class Machine():
""" Start the caldera server on the VM. Required for an attacker VM """ """ Start the caldera server on the VM. Required for an attacker VM """
# https://github.com/mitre/caldera.git # https://github.com/mitre/caldera.git
print(f"{CommandlineColors.OKBLUE}Starting Caldera server {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Starting Caldera server {CommandlineColors.ENDC}", 1)
# The pkill was added because the server sometimes gets stuck. And we can not re-create the attacking machines in all cases # The pkill was added because the server sometimes gets stuck. And we can not re-create the attacking machines in all cases
self.vm_manager.__call_remote_run__(" pkill -f server.py;", disown=False) self.vm_manager.__call_remote_run__(" pkill -f server.py;", disown=False)
cmd = f"cd {self.caldera_basedir}; cd caldera ; nohup python3 server.py --insecure &" cmd = f"cd {self.caldera_basedir}; cd caldera ; nohup python3 server.py --insecure &"
self.vm_manager.__call_remote_run__(cmd, disown=True) self.vm_manager.__call_remote_run__(cmd, disown=True)
self.wait_for_caldera_server() self.wait_for_caldera_server()
print(f"{CommandlineColors.OKGREEN}Caldera server started. Confirmed it is running. {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Caldera server started. Confirmed it is running. {CommandlineColors.ENDC}", 1)
def create_start_caldera_client_cmd(self): def create_start_caldera_client_cmd(self):
""" Creates a command to start the caldera client """ """ Creates a command to start the caldera client """
@ -410,11 +414,11 @@ class Machine():
""" Install caldera client. Required on targets """ """ Install caldera client. Required on targets """
name = self.vm_manager.get_vm_name() name = self.vm_manager.get_vm_name()
print(f"{CommandlineColors.OKBLUE}Starting Caldera client {name} {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Starting Caldera client {name} {CommandlineColors.ENDC}", 1)
if self.get_os() == "windows": if self.get_os() == "windows":
url = "http://" + self.caldera_server + ":8888" url = "http://" + self.caldera_server + ":8888"
caldera_control = CalderaControl(url, apikey=self.calderakey) caldera_control = CalderaControl(url, self.attack_logger, apikey=self.calderakey)
caldera_control.fetch_client(platform="windows", caldera_control.fetch_client(platform="windows",
file="sandcat.go", file="sandcat.go",
target_dir=self.abs_machinepath_external, target_dir=self.abs_machinepath_external,
@ -440,7 +444,7 @@ class Machine():
print(cmd) print(cmd)
self.vm_manager.remote_run(cmd, disown=True) self.vm_manager.remote_run(cmd, disown=True)
print(f"{CommandlineColors.OKGREEN}Caldera client started {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Caldera client started {CommandlineColors.ENDC}", 1)
def get_os(self): def get_os(self):
""" Returns the OS of the machine """ """ Returns the OS of the machine """
@ -484,7 +488,7 @@ nohup ./sandcat.go -server $server -group {self.config.caldera_group()} -v -paw
else: else:
playground = "" playground = ""
url = "http://" + self.caldera_server + ":8888" url = "http://" + self.caldera_server + ":8888"
caldera_control = CalderaControl(url, apikey=self.calderakey) caldera_control = CalderaControl(url, self.attack_logger, apikey=self.calderakey)
filename = caldera_control.fetch_client(platform="windows", filename = caldera_control.fetch_client(platform="windows",
file="sandcat.go", file="sandcat.go",
target_dir=self.abs_machinepath_external, target_dir=self.abs_machinepath_external,
@ -502,7 +506,7 @@ START {playground}{filename} -server {url} -group {self.config.caldera_group()}
content = self.__install_caldera_service_cmd() content = self.__install_caldera_service_cmd()
print(f"{CommandlineColors.OKBLUE}Installing Caldera service {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKBLUE}Installing Caldera service {CommandlineColors.ENDC}", 1)
if self.get_os() == "linux": if self.get_os() == "linux":
filename = os.path.join(self.abs_machinepath_external, "caldera_agent.sh") filename = os.path.join(self.abs_machinepath_external, "caldera_agent.sh")
@ -510,7 +514,7 @@ START {playground}{filename} -server {url} -group {self.config.caldera_group()}
filename = os.path.join(self.abs_machinepath_external, "caldera_agent.bat") filename = os.path.join(self.abs_machinepath_external, "caldera_agent.bat")
with open(filename, "wt") as fh: with open(filename, "wt") as fh:
fh.write(content) fh.write(content)
print(f"{CommandlineColors.OKGREEN}Installed Caldera server {CommandlineColors.ENDC}") self.attack_logger.vprint(f"{CommandlineColors.OKGREEN}Installed Caldera service {CommandlineColors.ENDC}", 1)
def set_caldera_server(self, server): def set_caldera_server(self, server):
""" Set the local caldera server config """ """ Set the local caldera server config """

@ -26,8 +26,13 @@ sections = [{"name": "Vulnerabilities",
class PluginManager(): class PluginManager():
""" Manage plugins """ """ Manage plugins """
def __init__(self): def __init__(self, attack_logger):
"""
@param attack_logger: The attack logger to use
"""
self.base = "plugins/**/*.py" self.base = "plugins/**/*.py"
self.attack_logger = attack_logger
def get_plugins(self, subclass, name_filter=None) -> [BasePlugin]: def get_plugins(self, subclass, name_filter=None) -> [BasePlugin]:
""" Returns a list plugins matching specified criteria """ Returns a list plugins matching specified criteria
@ -53,6 +58,7 @@ class PluginManager():
handlers = get_handlers(plugins) handlers = get_handlers(plugins)
for plugin in handlers: for plugin in handlers:
plugin.set_logger(self.attack_logger)
if name_filter is None: if name_filter is None:
res.append(plugin) res.append(plugin)
else: else:

@ -5,6 +5,7 @@
import argparse import argparse
from app.calderacontrol import CalderaControl from app.calderacontrol import CalderaControl
from app.attack_log import AttackLog
# https://caldera.readthedocs.io/en/latest/The-REST-API.html # https://caldera.readthedocs.io/en/latest/The-REST-API.html
@ -74,6 +75,8 @@ def create_parser():
""" Creates the parser for the command line arguments""" """ Creates the parser for the command line arguments"""
main_parser = argparse.ArgumentParser("Controls a Caldera server to attack other systems") main_parser = argparse.ArgumentParser("Controls a Caldera server to attack other systems")
main_parser.add_argument('--verbose', '-v', action='count', default=0)
subparsers = main_parser.add_subparsers(help="sub-commands") subparsers = main_parser.add_subparsers(help="sub-commands")
# Sub parser for attacks # Sub parser for attacks
@ -113,7 +116,8 @@ if __name__ == "__main__":
print(args.caldera_url) print(args.caldera_url)
caldera_control = CalderaControl(args.caldera_url, config=None, apikey=args.apikey) attack_logger = AttackLog(args.verbose)
caldera_control = CalderaControl(args.caldera_url, attack_logger, config=None, apikey=args.apikey)
print("Caldera Control ready") print("Caldera Control ready")
str(args.func(caldera_control, args)) str(args.func(caldera_control, args))

@ -20,7 +20,7 @@ def run(args):
@param args: arguments from the argparse parser @param args: arguments from the argparse parser
""" """
Experiment(args.configfile) Experiment(args.configfile, args.verbose)
def create_parser(): def create_parser():
@ -29,6 +29,7 @@ def create_parser():
subparsers = parser.add_subparsers(help="sub-commands") subparsers = parser.add_subparsers(help="sub-commands")
parser.set_defaults(func=explain) parser.set_defaults(func=explain)
parser.add_argument('--verbose', '-v', action='count', default=0)
# Sub parser for machine creation # Sub parser for machine creation
parser_run = subparsers.add_parser("run", help="run experiments") parser_run = subparsers.add_parser("run", help="run experiments")

@ -7,6 +7,7 @@ import yaml
from app.calderacontrol import CalderaControl from app.calderacontrol import CalderaControl
from app.machinecontrol import Machine from app.machinecontrol import Machine
from app.attack_log import AttackLog
def create_machines(arguments): def create_machines(arguments):
@ -19,7 +20,8 @@ def create_machines(arguments):
with open(arguments.configfile) as fh: with open(arguments.configfile) as fh:
config = yaml.safe_load(fh) config = yaml.safe_load(fh)
target_ = Machine(config["targets"]["target1"]) attack_logger = AttackLog(arguments.verbose)
target_ = Machine(config["targets"]["target1"], attack_logger)
attacker_1 = Machine(config["attackers"]["attacker"]) attacker_1 = Machine(config["attackers"]["attacker"])
print("Got them") print("Got them")
@ -54,7 +56,8 @@ def download_caldera_client(arguments):
@param arguments: The arguments from argparse @param arguments: The arguments from argparse
""" """
caldera_control = CalderaControl(args.ip, None) attack_logger = AttackLog(arguments.verbose)
caldera_control = CalderaControl(args.ip, attack_logger, None)
caldera_control.fetch_client(platform=arguments.platform, caldera_control.fetch_client(platform=arguments.platform,
file=arguments.file, file=arguments.file,
target_dir=arguments.target_dir, target_dir=arguments.target_dir,
@ -65,6 +68,7 @@ def create_parser():
""" Creates the parser for the command line arguments""" """ Creates the parser for the command line arguments"""
main_parser = argparse.ArgumentParser("Controls a Caldera server to attack other systems") main_parser = argparse.ArgumentParser("Controls a Caldera server to attack other systems")
main_parser.add_argument('--verbose', '-v', action='count', default=0)
subparsers = main_parser.add_subparsers(help="sub-commands") subparsers = main_parser.add_subparsers(help="sub-commands")
# Sub parser for machine creation # Sub parser for machine creation

@ -3,17 +3,22 @@
import argparse import argparse
from app.pluginmanager import PluginManager from app.pluginmanager import PluginManager
from app.attack_log import AttackLog
def list_plugins(arguments): def list_plugins(arguments):
""" List plugins """ """ List plugins """
p = PluginManager()
attack_logger = AttackLog(arguments.verbose)
p = PluginManager(attack_logger)
p.print_list() p.print_list()
def get_default_config(arguments): def get_default_config(arguments):
""" print default config of a specific plugin """ """ print default config of a specific plugin """
p = PluginManager()
attack_logger = AttackLog(arguments.verbose)
p = PluginManager(attack_logger)
p.print_default_config(arguments.subclass_name, arguments.plugin_name) p.print_default_config(arguments.subclass_name, arguments.plugin_name)
@ -21,6 +26,7 @@ def create_parser():
""" Creates the parser for the command line arguments""" """ Creates the parser for the command line arguments"""
main_parser = argparse.ArgumentParser("Manage plugins") main_parser = argparse.ArgumentParser("Manage plugins")
main_parser.add_argument('--verbose', '-v', action='count', default=0)
subparsers = main_parser.add_subparsers(help="sub-commands") subparsers = main_parser.add_subparsers(help="sub-commands")
# Sub parser for machine creation # Sub parser for machine creation

@ -21,7 +21,6 @@ class KaliPlugin(BasePlugin):
super().__init__() super().__init__()
self.conf = {} # Plugin specific configuration self.conf = {} # Plugin specific configuration
self.sysconf = {} # System configuration. common for all plugins self.sysconf = {} # System configuration. common for all plugins
self.attack_logger = None
def teardown(self): def teardown(self):
""" Cleanup afterwards """ """ Cleanup afterwards """
@ -47,19 +46,6 @@ class KaliPlugin(BasePlugin):
self.attack_logger.stop_kali_attack(self.machine_plugin.config.vmname(), targets, self.name, ttp=self.get_ttp()) self.attack_logger.stop_kali_attack(self.machine_plugin.config.vmname(), targets, self.name, ttp=self.get_ttp())
return res return res
def command(self, targets, config):
""" Generate command
@param targets: A list of targets, ip addresses will do
@param config: dict with command specific configuration
"""
raise NotImplementedError
def __set_logger__(self, attack_logger):
""" Set the attack logger for this machine """
self.attack_logger = attack_logger
def get_ttp(self): def get_ttp(self):
""" Returns the ttp of the plugin, please set in boilerplate """ """ Returns the ttp of the plugin, please set in boilerplate """
if self.ttp: if self.ttp:

@ -117,9 +117,9 @@ class MachineryPlugin(BasePlugin):
# This is the interface from the main code to the plugin system. Do not touch # This is the interface from the main code to the plugin system. Do not touch
def __call_halt__(self): def __call_halt__(self):
""" Wrapper around halt """ """ Wrapper around halt """
print(f"{CommandlineColors.OKBLUE}Stopping machine: {self.config.vmname()} {CommandlineColors.ENDC}") self.vprint(f"{CommandlineColors.OKBLUE}Stopping machine: {self.config.vmname()} {CommandlineColors.ENDC}", 1)
self.halt() self.halt()
print(f"{CommandlineColors.OKGREEN}Machine stopped: {self.config.vmname()}{CommandlineColors.ENDC}") self.vprint(f"{CommandlineColors.OKGREEN}Machine stopped: {self.config.vmname()}{CommandlineColors.ENDC}", 1)
def __call_process_config__(self, config: MachineConfig): def __call_process_config__(self, config: MachineConfig):
""" Wrapper around process_config """ """ Wrapper around process_config """

@ -22,15 +22,28 @@ class BasePlugin():
self.machine_plugin = None self.machine_plugin = None
self.sysconf = {} self.sysconf = {}
self.conf = {} self.conf = {}
self.attack_logger = None
self.default_config_name = "default_config.yaml" self.default_config_name = "default_config.yaml"
def get_playground(self):
""" Returns the machine specific playground
Which is the folder on the machine where we run our tasks in
"""
return self.machine_plugin.get_playground()
def set_logger(self, attack_logger):
""" Set the attack logger for this machine """
self.attack_logger = attack_logger
def setup(self): def setup(self):
""" Prepare everything for the plugin """ """ Prepare everything for the plugin """
for a_file in self.required_files: for a_file in self.required_files:
src = os.path.join(os.path.dirname(self.plugin_path), a_file) src = os.path.join(os.path.dirname(self.plugin_path), a_file)
print(src) self.vprint(src, 3)
self.copy_to_machine(src) self.copy_to_machine(src)
def set_machine_plugin(self, machine_plugin): def set_machine_plugin(self, machine_plugin):
@ -61,9 +74,6 @@ class BasePlugin():
self.conf = {**self.conf, **config} self.conf = {**self.conf, **config}
print("\n\n\n\n\n BASE plugin")
print(self.conf)
def copy_to_machine(self, filename): def copy_to_machine(self, filename):
""" Copies a file shipped with the plugin to the machine share folder """ Copies a file shipped with the plugin to the machine share folder
@ -83,7 +93,7 @@ class BasePlugin():
@param disown: Run in background @param disown: Run in background
""" """
print(f" Plugin running command {command}") self.vprint(f" Plugin running command {command}", 3)
res = self.machine_plugin.__call_remote_run__(command, disown=disown) res = self.machine_plugin.__call_remote_run__(command, disown=disown)
return res return res
@ -138,11 +148,32 @@ class BasePlugin():
filename = self.get_default_config_filename() filename = self.get_default_config_filename()
if not os.path.isfile(filename): if not os.path.isfile(filename):
print(f"Did not find default config {filename}") self.vprint(f"Did not find default config {filename}", 3)
self.conf = {} self.conf = {}
else: else:
with open(filename) as fh: with open(filename) as fh:
print(f"Loading default config {filename}") self.vprint(f"Loading default config {filename}", 3)
self.conf = yaml.safe_load(fh) self.conf = yaml.safe_load(fh)
if self.conf is None: if self.conf is None:
self.conf = {} self.conf = {}
def get_config_section_name(self):
""" Returns the name for the config sub-section to use for this plugin.
Defaults to the name of the plugin. This method should be overwritten if it gets more complicated """
return self.get_name()
def vprint(self, text, verbosity):
""" verbosity based stdout printing
0: Errors only
1: Main colored information
2: Detailed progress information
3: Debug logs, data dumps, everything
@param text: The text to print
@param verbosity: the verbosity level the text has.
"""
self.attack_logger.vprint(text, verbosity)

@ -29,7 +29,7 @@ class SSHFeatures(BasePlugin):
try: try:
if self.config.os() == "linux": if self.config.os() == "linux":
uhp = self.get_ip() uhp = self.get_ip()
print(f"Connecting to {uhp}") self.vprint(f"Connecting to {uhp}", 3)
self.c = Connection(uhp, connect_timeout=timeout) self.c = Connection(uhp, connect_timeout=timeout)
if self.config.os() == "windows": if self.config.os() == "windows":
@ -39,20 +39,20 @@ class SSHFeatures(BasePlugin):
args["key_filename"] = self.config.ssh_keyfile() args["key_filename"] = self.config.ssh_keyfile()
if self.config.ssh_password(): if self.config.ssh_password():
args["password"] = self.config.ssh_password() args["password"] = self.config.ssh_password()
print(args) self.vprint(args, 3)
uhp = self.get_ip() uhp = self.get_ip()
print(uhp) self.vprint(uhp, 3)
self.c = Connection(uhp, connect_timeout=timeout, user=self.config.ssh_user(), connect_kwargs=args) self.c = Connection(uhp, connect_timeout=timeout, user=self.config.ssh_user(), connect_kwargs=args)
except (paramiko.ssh_exception.SSHException, socket.timeout): except (paramiko.ssh_exception.SSHException, socket.timeout):
print(f"Failed to connect, will retry {retries} times. Timeout: {timeout}") self.vprint(f"Failed to connect, will retry {retries} times. Timeout: {timeout}", 0)
retries -= 1 retries -= 1
timeout += 10 timeout += 10
time.sleep(retry_sleep) time.sleep(retry_sleep)
else: else:
print(f"Connection: {self.c}") self.vprint(f"Connection: {self.c}", 3)
return self.c return self.c
print("SSH network error") self.vprint("SSH network error", 0)
raise NetworkError raise NetworkError
def remote_run(self, cmd, disown=False): def remote_run(self, cmd, disown=False):
@ -67,8 +67,8 @@ class SSHFeatures(BasePlugin):
self.connect() self.connect()
cmd = cmd.strip() cmd = cmd.strip()
print("Running SSH remote run: " + cmd) self.vprint("Running SSH remote run: " + cmd, 3)
print("Disown: " + str(disown)) self.vprint("Disown: " + str(disown), 3)
result = None result = None
retry = 2 retry = 2
while retry > 0: while retry > 0:
@ -83,12 +83,12 @@ class SSHFeatures(BasePlugin):
self.disconnect() self.disconnect()
self.connect() self.connect()
retry -= 1 retry -= 1
print("Got some SSH errors. Retrying") self.vprint("Got some SSH errors. Retrying", 2)
else: else:
break break
if result and result.stderr: if result and result.stderr:
print("Debug: Stderr: " + str(result.stderr.strip())) self.vprint("Debug: Stderr: " + str(result.stderr.strip()), 0)
if result: if result:
return result.stdout.strip() return result.stdout.strip()
@ -103,7 +103,7 @@ class SSHFeatures(BasePlugin):
""" """
self.connect() self.connect()
print(f"PUT {src} -> {dst}") self.vprint(f"PUT {src} -> {dst}", 3)
res = "" res = ""
retries = 10 retries = 10
@ -113,18 +113,18 @@ class SSHFeatures(BasePlugin):
try: try:
res = self.c.put(src, dst) res = self.c.put(src, dst)
except (paramiko.ssh_exception.SSHException, socket.timeout, UnexpectedExit): except (paramiko.ssh_exception.SSHException, socket.timeout, UnexpectedExit):
print(f"PUT Failed to connect, will retry {retries} times. Timeout: {timeout}") self.vprint(f"PUT Failed to connect, will retry {retries} times. Timeout: {timeout}", 3)
retries -= 1 retries -= 1
timeout += 10 timeout += 10
time.sleep(retry_sleep) time.sleep(retry_sleep)
self.disconnect() self.disconnect()
self.connect() self.connect()
except FileNotFoundError as e: except FileNotFoundError as e:
print(f"File not found: {e}") self.vprint(f"File not found: {e}", 0)
break break
else: else:
return res return res
print("SSH network error on PUT command") self.vprint("SSH network error on PUT command", 0)
raise NetworkError raise NetworkError
def get(self, src, dst): def get(self, src, dst):
@ -146,9 +146,9 @@ class SSHFeatures(BasePlugin):
self.disconnect() self.disconnect()
self.connect() self.connect()
retry -= 1 retry -= 1
print("Got some SSH errors. Retrying") self.vprint("Got some SSH errors. Retrying", 2)
except FileNotFoundError as e: except FileNotFoundError as e:
print(e) self.vprint(e, 0)
break break
else: else:
break break

@ -84,7 +84,7 @@ class VagrantPlugin(SSHFeatures, MachineryPlugin):
return self.c return self.c
uhp = self.v.user_hostname_port(vm_name=self.config.vmname()) uhp = self.v.user_hostname_port(vm_name=self.config.vmname())
print(f"Connecting to {uhp}") self.vprint(f"Connecting to {uhp}", 3)
self.c = Connection(uhp, connect_kwargs={"key_filename": self.v.keyfile(vm_name=self.config.vmname())}) self.c = Connection(uhp, connect_kwargs={"key_filename": self.v.keyfile(vm_name=self.config.vmname())})
return self.c return self.c

@ -23,22 +23,18 @@ class SshdVulnerability(VulnerabilityPlugin):
# allow password access via ssh # allow password access via ssh
cmd = "sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config" cmd = "sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config"
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
# Restart ssh # Restart ssh
cmd = "sudo service ssh restart" cmd = "sudo service ssh restart"
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
def stop(self): def stop(self):
# Re-configure sshd to stable state # Re-configure sshd to stable state
cmd = "sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config" cmd = "sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config"
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
# Restart ssh # Restart ssh
cmd = "sudo service ssh restart" cmd = "sudo service ssh restart"
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)

@ -28,7 +28,6 @@ class WeakPasswordVulnerabilityVulnerability(VulnerabilityPlugin):
for user in self.conf["linux"]: for user in self.conf["linux"]:
cmd = f"sudo useradd -m -p '{user['password']}' -s /bin/bash {user['name']}" cmd = f"sudo useradd -m -p '{user['password']}' -s /bin/bash {user['name']}"
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
elif self.machine_plugin.config.os() == "windows": elif self.machine_plugin.config.os() == "windows":
@ -36,13 +35,11 @@ class WeakPasswordVulnerabilityVulnerability(VulnerabilityPlugin):
for user in self.conf["windows"]: for user in self.conf["windows"]:
# net user username password /add # net user username password /add
cmd = f"net user {user['name']} {user['password']} /add" cmd = f"net user {user['name']} {user['password']} /add"
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
for user in self.conf["windows"]: for user in self.conf["windows"]:
# Adding the new users to RDP (just in case we want to test RDP) # Adding the new users to RDP (just in case we want to test RDP)
cmd = f"""NET LOCALGROUP "Remote Desktop Users" {user['name']} /ADD""" cmd = f"""NET LOCALGROUP "Remote Desktop Users" {user['name']} /ADD"""
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
else: else:
@ -54,21 +51,18 @@ class WeakPasswordVulnerabilityVulnerability(VulnerabilityPlugin):
for user in self.conf["linux"]: for user in self.conf["linux"]:
# Remove user # Remove user
cmd = f"sudo userdel -r {user['name']}" cmd = f"sudo userdel -r {user['name']}"
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
elif self.machine_plugin.config.os() == "windows": elif self.machine_plugin.config.os() == "windows":
for user in self.conf["windows"]: for user in self.conf["windows"]:
# net user username /delete # net user username /delete
cmd = f"net user {user['name']} /delete" cmd = f"net user {user['name']} /delete"
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
# Remove the new users to RDP (just in case we want to test RDP) # Remove the new users to RDP (just in case we want to test RDP)
for user in self.conf["windows"]: for user in self.conf["windows"]:
# net user username /delete # net user username /delete
cmd = f""""NET LOCALGROUP "Remote Desktop Users" {user['name']} /DELETE""" cmd = f""""NET LOCALGROUP "Remote Desktop Users" {user['name']} /DELETE"""
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
else: else:

@ -24,22 +24,18 @@ class RDPVulnerability(VulnerabilityPlugin):
# allow password access via rdp # allow password access via rdp
cmd = r"""reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f""" cmd = r"""reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f"""
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
# Open Firewall # Open Firewall
cmd = """netsh advfirewall firewall set rule group="remote desktop" new enable=Yes""" cmd = """netsh advfirewall firewall set rule group="remote desktop" new enable=Yes"""
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
def stop(self): def stop(self):
# Re-configure sshd to stable state # Re-configure sshd to stable state
cmd = r"""reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 1 /f""" cmd = r"""reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 1 /f"""
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)
# Reset firewall # Reset firewall
cmd = """netsh advfirewall firewall set rule group="remote desktop" new enable=No""" cmd = """netsh advfirewall firewall set rule group="remote desktop" new enable=No"""
print(cmd)
self.run_cmd(cmd) self.run_cmd(cmd)

Loading…
Cancel
Save