diff --git a/app/config.py b/app/config.py index 17136e5..a16631d 100644 --- a/app/config.py +++ b/app/config.py @@ -204,6 +204,30 @@ class ExperimentConfig(): return res + def get_kali_attacks(self, for_os): + """ Get the configured kali attacks to run for a specific OS + + @param for_os: The os to query the registered attacks for + """ + + if "kali_attacks" not in self.raw_config: + return [] + if for_os not in self.raw_config["kali_attacks"]: + return [] + return self.raw_config["kali_attacks"][for_os] + + def get_caldera_attacks(self, for_os): + """ Get the configured caldera attacks to run for a specific OS + + @param for_os: The os to query the registered attacks for + """ + + if "caldera_attacks" not in self.raw_config: + return [] + if for_os not in self.raw_config["caldera_attacks"]: + return [] + return self.raw_config["caldera_attacks"][for_os] + def get_nap_time(self): """ Returns the attackers nap time between attack steps """ diff --git a/app/experimentcontrol.py b/app/experimentcontrol.py index 1f5a829..fd3e80a 100644 --- a/app/experimentcontrol.py +++ b/app/experimentcontrol.py @@ -99,7 +99,8 @@ class Experiment(): print(f"{CommandlineColors.OKBLUE}Running Caldera attacks{CommandlineColors.ENDC}") for target_1 in self.targets: # Run caldera attacks - caldera_attacks = self.experiment_control.raw_config["caldera_attacks"][target_1.get_os()] + # caldera_attacks = self.experiment_control.raw_config["caldera_attacks"][target_1.get_os()] + caldera_attacks = self.experiment_control.get_caldera_attacks(target_1.get_os()) if caldera_attacks: for attack in caldera_attacks: # TODO: Work with snapshots @@ -115,7 +116,9 @@ class Experiment(): # Run Kali attacks print(f"{CommandlineColors.OKBLUE}Running Kali attacks{CommandlineColors.ENDC}") for target_1 in self.targets: - for attack in self.experiment_control.raw_config["kali_attacks"][target_1.get_os()]: + kali_attacks = caldera_attacks = self.experiment_control.get_kali_attacks(target_1.get_os()) + #for attack in self.experiment_control.raw_config["kali_attacks"][target_1.get_os()]: + for attack in kali_attacks: # TODO: Work with snapshots self.attacker_1.kali_attack(attack, target_1.getip(), self.experiment_control) diff --git a/tests/data/attacks_missing.yaml b/tests/data/attacks_missing.yaml new file mode 100644 index 0000000..489a8cd --- /dev/null +++ b/tests/data/attacks_missing.yaml @@ -0,0 +1,146 @@ + +### +# Caldera configuration +caldera: + ### + # API key for caldera. See caldera configuration. Default is ADMIN123 + apikey: ADMIN123 + +### +# Attacks configuration +attackers: + ### + # Configuration for the first attacker. One should normally be enough + attacker: + + ### + # Defining VM controller settings for this machine + vm_controller: + ### + # Type of the VM controller, Options are "vagrant" + type: vagrant + ### + # # path where the vagrantfile is in + vagrantfilepath: systems + + ### + # Name of machine in Vagrantfile + vm_name: attacker + + ### + # machinepath is a path where the machine specific files and logs are stored. Relative to the Vagrantfile path + # and will be mounted internally as /vagrant/ + # If machinepoath is not set PurpleDome will try "vm_name" + machinepath: attacker1 + + ### + # OS of the VM guest. Options are so far "windows", "linux" + os: linux + + ### + # Do not destroy/create the machine: Set this to "yes". + use_existing_machine: yes + +### +# List of targets +targets: + ### + # Specific target + 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 + + target2: + #root: systems/target1 + vm_controller: + type: vagrant + vagrantfilepath: systems + + vm_name: target2 + os: windows + paw: target2w + group: red + + machinepath: target2w + + # Do not destroy/create the machine: Set this to "yes". + use_existing_machine: yes + ### + # Optional setting to activate force when halting the machine. Windows guests sometime get stuck + halt_needs_force: yes + + ### + # If SSH without vagrant support is used (Windows !) we need a user name (uppercase) + ssh_user: PURPLEDOME + + ### + # For non-vagrant ssh connections a ssh keyfile stored in the machinepath is required. + ssh_keyfile: id_rsa.3 + +# This is intentionally missing !!!! +### +# A list of caldera attacks to run against the targets. +#caldera_attacks: + ### + # Linux specific attacks. A list of caldera ability IDs +# linux: +# - "bd527b63-9f9e-46e0-9816-b8434d2b8989" + ### + # Windows specific attacks. A list of caldera ability IDs +# windows: + #- "bd527b63-9f9e-46e0-9816-b8434d2b8989" + + + +# This is intentionally missing !!!! +### +# Kali tool based attacks. Will result in kali commandline tools to be called. Currently supported are: "hydra" +#kali_attacks: + ### + # Linux specific attacks, a list + # linux: + # - hydra + ### + # Windows specific attacks, a list + # windows: + # - hydra + +### +# Configuration for the kali attack tools +kali_conf: + ### + # Hydra configuration + hydra: + ### + # A list of protocols to brute force against. Supported: "ssh" + protocols: + - ssh + #- ftp + #- ftps + ### + # A file containing potential user names + userfile: users.txt + ### + # A file containing potential passwords + pwdfile: passwords.txt + +### +# Settings for the results being harvested +results: + ### + # The directory the loot will be in + loot_dir: loot diff --git a/tests/data/attacks_perfect.yaml b/tests/data/attacks_perfect.yaml new file mode 100644 index 0000000..7a255fb --- /dev/null +++ b/tests/data/attacks_perfect.yaml @@ -0,0 +1,146 @@ + +### +# Caldera configuration +caldera: + ### + # API key for caldera. See caldera configuration. Default is ADMIN123 + apikey: ADMIN123 + +### +# Attacks configuration +attackers: + ### + # Configuration for the first attacker. One should normally be enough + attacker: + + ### + # Defining VM controller settings for this machine + vm_controller: + ### + # Type of the VM controller, Options are "vagrant" + type: vagrant + ### + # # path where the vagrantfile is in + vagrantfilepath: systems + + ### + # Name of machine in Vagrantfile + vm_name: attacker + + ### + # machinepath is a path where the machine specific files and logs are stored. Relative to the Vagrantfile path + # and will be mounted internally as /vagrant/ + # If machinepoath is not set PurpleDome will try "vm_name" + machinepath: attacker1 + + ### + # OS of the VM guest. Options are so far "windows", "linux" + os: linux + + ### + # Do not destroy/create the machine: Set this to "yes". + use_existing_machine: yes + +### +# List of targets +targets: + ### + # Specific target + 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 + + target2: + #root: systems/target1 + vm_controller: + type: vagrant + vagrantfilepath: systems + + vm_name: target2 + os: windows + paw: target2w + group: red + + machinepath: target2w + + # Do not destroy/create the machine: Set this to "yes". + use_existing_machine: yes + ### + # Optional setting to activate force when halting the machine. Windows guests sometime get stuck + halt_needs_force: yes + + ### + # If SSH without vagrant support is used (Windows !) we need a user name (uppercase) + ssh_user: PURPLEDOME + + ### + # For non-vagrant ssh connections a ssh keyfile stored in the machinepath is required. + ssh_keyfile: id_rsa.3 + +### +# A list of caldera attacks to run against the targets. +caldera_attacks: + ### + # Linux specific attacks. A list of caldera ability IDs + linux: + - "bd527b63-9f9e-46e0-9816-b8434d2b8989" + ### + # Windows specific attacks. A list of caldera ability IDs + windows: + - "bd527b63-9f9e-46e0-9816-b8434d2b8989" + - "foo" + - "bar" + +### +# Kali tool based attacks. Will result in kali commandline tools to be called. Currently supported are: "hydra" +kali_attacks: + ### + # Linux specific attacks, a list + linux: + - hydra + ### + # Windows specific attacks, a list + windows: + - hydra + - medusa + - skylla + +### +# Configuration for the kali attack tools +kali_conf: + ### + # Hydra configuration + hydra: + ### + # A list of protocols to brute force against. Supported: "ssh" + protocols: + - ssh + #- ftp + #- ftps + ### + # A file containing potential user names + userfile: users.txt + ### + # A file containing potential passwords + pwdfile: passwords.txt + +### +# Settings for the results being harvested +results: + ### + # The directory the loot will be in + loot_dir: loot diff --git a/tests/test_config.py b/tests/test_config.py index 96e4b92..76f7c47 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -531,6 +531,62 @@ class TestExperimentConfig(unittest.TestCase): self.assertEqual(ex.get_nap_time(), 0) + def test_kali_attacks_missing(self): + """ kali attacks entry fully missing from config """ + + ex = ExperimentConfig("tests/data/attacks_missing.yaml") + + self.assertEqual(ex.get_kali_attacks("linux"), []) + + def test_kali_attacks_empty(self): + """ zero entries in kali attacks list """ + + ex = ExperimentConfig("tests/data/attacks_perfect.yaml") + + self.assertEqual(ex.get_kali_attacks("missing"), []) + + def test_kali_attacks_one(self): + """ One entry in kali attacks list """ + + ex = ExperimentConfig("tests/data/attacks_perfect.yaml") + + self.assertEqual(ex.get_kali_attacks("linux"), ["hydra"]) + + def test_kali_attacks_many(self): + """ Many entries in kali attacks list """ + + ex = ExperimentConfig("tests/data/attacks_perfect.yaml") + + self.assertEqual(ex.get_kali_attacks("windows"), ["hydra", "medusa", "skylla"]) + + def test_caldera_attacks_missing(self): + """ caldera attacks entry fully missing from config """ + + ex = ExperimentConfig("tests/data/attacks_missing.yaml") + + self.assertEqual(ex.get_caldera_attacks("linux"), []) + + def test_caldera_attacks_empty(self): + """ zero entries in caldera attacks list """ + + ex = ExperimentConfig("tests/data/attacks_perfect.yaml") + + self.assertEqual(ex.get_caldera_attacks("missing"), []) + + def test_caldera_attacks_one(self): + """ One entry in caldera attacks list """ + + ex = ExperimentConfig("tests/data/attacks_perfect.yaml") + + self.assertEqual(ex.get_caldera_attacks("linux"), ["bd527b63-9f9e-46e0-9816-b8434d2b8989"]) + + def test_caldera_attacks_many(self): + """ Many entries in caldera attacks list """ + + ex = ExperimentConfig("tests/data/attacks_perfect.yaml") + + self.assertEqual(ex.get_caldera_attacks("windows"), ["bd527b63-9f9e-46e0-9816-b8434d2b8989", "foo", "bar"]) + if __name__ == '__main__': unittest.main()